Commit 57cb8da6 authored by Nico Mack's avatar Nico Mack

Added CoronaBundleFactory

Fixed Bug in ModalWidget which may cause Concurrent Modification
Exceptions.
parent cdb36aff
......@@ -180,6 +180,17 @@ public class BootstrappingUtils {
// ---------------------------------------------------------------------------
private static String getAttribute(Element rootElement, String attributeName, BootstrapContext context) {
String attribute;
if ((attributeName != null) && (attributeName.length() > 0)) {
attribute = rootElement.getAttributeValue(attributeName);
return interpolate(attribute, context);
}
return null;
}
// ---------------------------------------------------------------------------
private static String interpolate(String content, BootstrapContext context) {
if (content == null)
......
......@@ -169,39 +169,6 @@ public class CoronaBootstrapper {
return coronas;
}
// ---------------------------------------------------------------------------
/**
* Method used for bootstrapping all coronas found as child nodes of a root node. The method will
* look for child nodes names <code>corona</code>. The method returns a map, using the coronas'
* <code>handleId</code> property as the key and the corona itself as the value.
*
* @param coronaRootNode
* The root node that holds all <code>corona</code> child nodes.
* @param context
* @param callbacks
* @return A map containing all concrete {@link Corona} instances that could be build from the
* provided root node keyed to the handle ID to which they are associated. *
* @throws BuildException
* Thrown when a corona was not associated to any handle.
*/
// ---------------------------------------------------------------------------
// public static Multimap<Integer, Corona> getCoronas(Element coronaRootNode, BootstrapContext
// context, Map<String, BootstrapCallback> callbacks) throws BuildException {
// Multimap<Integer, Corona> coronas = ArrayListMultimap.create();
//
// for (Element coronaNode : coronaRootNode.getChildren(Externalization.CORONA_NODE)) {
// int handleId = BootstrappingUtils.getContentAsInteger(coronaNode, Externalization.HANDLE_NODE,
// BootstrappingUtils.MANDATORY, 0, context);
// CoronaFactory<Corona> factory = new CoronaFactory<>(coronaNode, context, callbacks);
// while (factory.hasNext()) {
// Corona newInstance = factory.next();
// coronas.put(handleId, newInstance);
// }
// }
// return coronas;
// }
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2016.
*
* This file is part of TULIP.
*
* TULIP is licensed under a dual-licensing scheme. For non-commercial purposes, the LGPL version 3,
* as stated below, is applicable. For all commercial purposes TULIP is licensed under a LIST
* proprietary license. Please contact LIST at tto@list.lu to obtain a commercial license.
*
* For all non-commercial purposes, TULIP is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, version 3 of the License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.Externalization;
import lu.list.itis.dkd.tui.widget.corona.bundle.CoronaBundle;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.jdom2.Element;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 1.0.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class CoronaBundleBootstrapper {
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
private CoronaBundleBootstrapper() {}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Method used for bootstrapping all coronas found as child nodes of a root node. The method will
* look for child nodes names <code>corona</code>.
*
* @param coronaBundlesNode
* The root node that holds all <code>bundle</code> child nodes.
* @return A map containing all concrete {@link CoronaBundle} instances that could be build from the
* provided root node keyed to the bundle name to which they are associated.
* @throws BuildException
* Thrown when a bundle could not be build.
*/
// ---------------------------------------------------------------------------
public static Multimap<String, CoronaBundle> getCoronaBundles(Element coronaBundlesNode) throws BuildException {
return getCoronaBundles(coronaBundlesNode, null, null);
}
// ---------------------------------------------------------------------------
/**
* Method used for bootstrapping all bundles found as child nodes of a root node. The method will
* look for child nodes names <code>bundle</code>. The method returns a map, using the bundles'
* <code>name</code> property as the key and the bundle itself as the value.
*
* @param coronaBundlesNode
* The root node that holds all <code>bundle</code> child nodes.
* @param context
* @param callback
* @return A map containing all concrete {@link CoronaBundle} instances that could be build from the
* provided root node keyed to the bundle name to which they are associated.
* @throws BuildException
* Thrown when a bundle could not be build.
*/
// ---------------------------------------------------------------------------
public static Multimap<String, CoronaBundle> getCoronaBundles(Element coronaBundlesNode, BootstrapContext context, BootstrapCallback callback) throws BuildException {
Multimap<String, CoronaBundle> bundles = ArrayListMultimap.create();
if (coronaBundlesNode != null) {
for (Element bundleNode : coronaBundlesNode.getChildren(Externalization.BUNDLE_NODE)) {
CoronaBundleFactory<CoronaBundle> factory = new CoronaBundleFactory<>(bundleNode, context, callback);
while (factory.hasNext()) {
CoronaBundle newInstance = factory.next();
bundles.put(newInstance.getName(), newInstance);
}
}
}
return bundles;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.Externalization;
import lu.list.itis.dkd.tui.utility.StringUtils;
import lu.list.itis.dkd.tui.widget.corona.bundle.CoronaBundle;
import org.jdom2.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 1.5
* @version 1.5.0
* @param <C>
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class CoronaBundleFactory<C extends CoronaBundle> implements Iterator<C> {
private boolean repeating;
private int index;
private int count;
private BootstrapContext context;
private Element bundleNode;
private String indexVariable;
private BootstrapCallback callback;
// ***************************************************************************
// * Constants
// ***************************************************************************
private static final Logger LOGGER = LoggerFactory.getLogger(CoronaBundleFactory.class.getSimpleName());
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param bundleNode
* @param context
* @param callback
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public CoronaBundleFactory(Element bundleNode, BootstrapContext context, BootstrapCallback callback) throws BuildException {
this.buildFromBootstrap(bundleNode, context, callback);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitive(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
@SuppressWarnings("hiding")
private void buildFromBootstrap(Element bundleNode, BootstrapContext context, BootstrapCallback callback) throws BuildException {
this.bundleNode = bundleNode;
this.callback = callback;
this.context = context;
this.index = 0;
this.repeating = BootstrappingUtils.getAttributeAsBoolean(bundleNode, Externalization.REPEAT_ATTRIBUTE, BootstrappingUtils.OPTIONAL, false);
if (this.repeating) {
if (this.callback != null) {
this.context = this.callback.reset(this.context);
this.context = this.callback.initialize(bundleNode, this.context);
}
this.indexVariable = BootstrappingUtils.getAttributeAsString(bundleNode, Externalization.INDEX_ATTRIBUTE, BootstrappingUtils.MANDATORY, null);
String countVariable = BootstrappingUtils.getAttributeAsString(bundleNode, Externalization.COUNT_ATTRIBUTE, BootstrappingUtils.MANDATORY, null);
context.setProperty(this.indexVariable, this.index);
Object countProperty = context.getProperty(countVariable);
if (countProperty == null) {
throw new BuildException(StringUtils.build("Specified count property {} has not been set in context!", countVariable)); //$NON-NLS-1$
}
this.count = Integer.parseInt(countProperty.toString());
} else {
this.count = 1;
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@Override
public boolean hasNext() {
return (index < count);
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
// ---------------------------------------------------------------------------
@SuppressWarnings("unchecked")
@Override
public C next() {
C next = null;
if (!hasNext()) {
throw new NoSuchElementException();
}
try {
if (callback != null)
this.context = callback.preInstantiation(this.bundleNode, this.context);
C instance = (C) new CoronaBundle(this.bundleNode, this.context, this.callback);
next = instance;
if (callback != null)
this.context = callback.postInstantiation(this.bundleNode, this.context);
} catch (SecurityException | IllegalArgumentException | BuildException exception) {
LOGGER.error("Failed to instantiate a corona bundle from template!", exception); //$NON-NLS-1$
}
this.index++;
if (this.repeating) {
context.setProperty(this.indexVariable, this.index);
if (callback != null)
this.context = callback.next(context);
}
if ((callback != null) && !hasNext()) {
this.context = this.callback.finalize(context);
}
return next;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
......@@ -87,16 +87,6 @@ public class CoronaFactory<C extends Corona> implements Iterator<C> {
this.index = 0;
this.repeating = BootstrappingUtils.getAttributeAsBoolean(coronaNode, Externalization.REPEAT_ATTRIBUTE, BootstrappingUtils.OPTIONAL, false);
if (this.repeating) {
// if (callback == null) {
// String callbackAttribute = BootstrappingUtils.getAttributeAsString(coronaNode,
// Externalization.CALLBACK_ATTRIBUTE, BootstrappingUtils.MANDATORY, null);
// if (context.hasProperty(callbackAttribute)) {
// this.callback = (BootstrapCallback) context.getProperty(callbackAttribute);
// } else {
// throw new BuildException(StringUtils.build("Required callback {} was not found in available
// callbacks!", callbackAttribute)); //$NON-NLS-1$
// }
// }
if (this.callback != null) {
this.context = this.callback.reset(this.context);
......
......@@ -71,6 +71,12 @@ public class ModalWidget extends TetherableWidget {
activeBundles = new ArrayList<>();
}
// ---------------------------------------------------------------------------
public ModalWidget(ModalWidget original) {
super(original);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitive(s) *
......@@ -189,7 +195,9 @@ public class ModalWidget extends TetherableWidget {
// ---------------------------------------------------------------------------
private void deactivateAllActiveBundles() {
for (String activeBundle : activeBundles) {
List<String> currentlyActive = new ArrayList<>(activeBundles);
for (String activeBundle : currentlyActive) {
this.deactivateBundle(activeBundle);
}
activeBundles.clear();
......@@ -249,8 +257,6 @@ public class ModalWidget extends TetherableWidget {
return coronaBundles.get(bundle);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
......
......@@ -19,6 +19,7 @@ package lu.list.itis.dkd.tui.widget.builder;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapCallback;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapContext;
import lu.list.itis.dkd.tui.bootstrapping.CoronaBundleBootstrapper;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.Externalization;
import lu.list.itis.dkd.tui.widget.ModalWidget;
......@@ -80,14 +81,18 @@ public abstract class BaseModalWidgetBuilder<B extends BaseModalWidgetBuilder<B>
// ---------------------------------------------------------------------------
private void buildFromBootstrap(@Nullable Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
// coronaBundles = TreeMultimap.create();
// Element bundlesElement = rootElement.getChild(Externalization.BUNDLES_NODE);
// if (bundlesElement != null) {
// for (Element bundleElement : bundlesElement.getChildren(Externalization.BUNDLE_NODE)) {
// CoronaBundle bundle = new CoronaBundle(bundleElement, context, callback);
// coronaBundles.put(bundle.getName(), bundle);
// }
// }
coronaBundles = TreeMultimap.create();
Element bundlesElement = rootElement.getChild(Externalization.BUNDLES_NODE);
if (bundlesElement != null) {
for (Element bundleElement : bundlesElement.getChildren(Externalization.BUNDLE_NODE)) {
CoronaBundle bundle = new CoronaBundle(bundleElement, context, callback);
coronaBundles.put(bundle.getName(), bundle);
}
}
if (bundlesElement != null)
coronaBundles = CoronaBundleBootstrapper.getCoronaBundles(bundlesElement, context, callback);
}
// ---------------------------------------------------------------------------
......
......@@ -25,6 +25,7 @@ import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.Externalization;
import lu.list.itis.dkd.tui.widget.corona.Corona;
import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
......@@ -109,6 +110,10 @@ public class CoronaBundle implements Comparable<CoronaBundle> {
private void buildFromBootstrap(@Nullable Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
name = BootstrappingUtils.getAttributeAsString(rootElement, Externalization.NAME_NODE, BootstrappingUtils.OPTIONAL, Externalization.EMPTY_STRING);
if (Strings.isNullOrEmpty(name)) {
name = BootstrappingUtils.getContentAsString(rootElement, Externalization.NAME_NODE, BootstrappingUtils.OPTIONAL, Externalization.EMPTY_STRING, context);
}
isExclusive = BootstrappingUtils.getAttributeAsBoolean(rootElement, Externalization.EXCLUSIVE_NODE, BootstrappingUtils.OPTIONAL, Boolean.FALSE);
isDefault = BootstrappingUtils.getAttributeAsBoolean(rootElement, Externalization.DEFAULT_NODE, BootstrappingUtils.OPTIONAL, Boolean.FALSE);
coronas = CoronaBootstrapper.getCoronas(rootElement.getChild(Externalization.CORONAS_NODE), context, callback);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment