Commit d8b063ce authored by Nico Mack's avatar Nico Mack

Added ScriptBootstrapper

parent a4d572b4
......@@ -146,6 +146,7 @@ ROTATE_WITH_TETHER_NODE=rotateWithTether
ROTATION_DIRECTION_NODE=rotationDirection
SCALE_NODE=scale
SATURATION_NODE=saturation
SCRIPT_BUILDER_NAMESPACE=lu.list.itis.dkd.tui.scripting.builder
SCREEN_ID_NODE=screenId
SECTION_NODE=section
SECTIONS_NODE=sections
......
package lu.list.itis.dkd.tui.bootstrapping;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.scripting.Script;
import lu.list.itis.dkd.tui.scripting.builder.BaseScriptBuilder;
import lu.list.itis.dkd.tui.utility.Externalization;
import org.jdom2.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @author nico.mack@list.lu
* @since 2.5
* @version 2.5.0
*/
public class ScriptBootstrapper {
private static final Logger LOGGER = LoggerFactory.getLogger(ScriptBootstrapper.class.getSimpleName());
/**
* Method used to determine the appropriate builder for a given object and then issue a build call.
*
* @param objectNode
* The node from a larger document that contains, as children, all the necessary information
* to resolve the correct builder and build the final widget.
* @return The final widget as defined by the children of the element node.
* @throws ClassNotFoundException
* Thrown when the class of the builder for the widget or those of the nested corona
* builder(s) could not be found.
* @throws SecurityException
* Thrown when the constructor cannot be retrieved due to some security constraints.
* @throws NoSuchMethodException
* Thrown when no constructor with the given parameter type is available.
* @throws InvocationTargetException
* Thrown if the invocation of any constructor through reflection throws an exception.
* @throws IllegalArgumentException
* Thrown when the provided argument is not eligible for the builder's constructor.
* @throws IllegalAccessException
* Thrown if this Constructor object is enforcing Java language access control and the
* underlying constructor is inaccessible.
* @throws InstantiationException
* Thrown if the class that declares the underlying constructor represents an abstract
* class.
*/
@SuppressWarnings("unchecked")
private static Script buildScriptFromElement(Element scriptingNode, BootstrapContext context, BootstrapCallback callback) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Script instance = null;
Element type = scriptingNode.getChild(Externalization.TYPE_NODE);
Class<?> builder = Class.forName(Externalization.SCRIPT_BUILDER_NAMESPACE + Externalization.NAMESPACE_SEPARATOR + type.getValue() + Externalization.BUILDER_CLASS_POSTFIX);
if ((context == null) || (context.size() == 0)) {
Constructor<BaseScriptBuilder<?>> constructor = (Constructor<BaseScriptBuilder<?>>) builder.getConstructor(new Class[] {Element.class});
instance = constructor.newInstance(new Object[] {scriptingNode}).build();
} else {
Constructor<BaseScriptBuilder<?>> constructor = (Constructor<BaseScriptBuilder<?>>) builder.getConstructor(new Class[] {Element.class, BootstrapContext.class, BootstrapCallback.class});
instance = constructor.newInstance(new Object[] {scriptingNode, context, callback}).build();
}
return instance;
}
/**
* builds a widget from the specified template node. A second parameter allows specifying the
* bootstrapping context, a map holding the names and the values of variables for interpolation of
* variable properties in template definition.
*
* @param scriptingNode
* specifies the template node to build the widget from
* @param bootstrapContext
* specifies the names of variables and their respective values for interpolation of
* properties in template definition
* @param callback
* @return an instance of the widget as specified in the provided template node.
* @throws BuildException
* if build of widget failed
*/
public static Script buildScriptFromTemplate(Element scriptingNode, BootstrapContext bootstrapContext, BootstrapCallback callback) throws BuildException {
Script instance;
try {
instance = buildScriptFromElement(scriptingNode, bootstrapContext, callback);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) {
LOGGER.error("A script could not be build from specified template!", e); //$NON-NLS-1$
throw new BuildException("A script could not be build from specified template!" + e.getMessage(), e); //$NON-NLS-1$
}
return instance;
}
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2018. 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.scripting;
import lu.list.itis.dkd.tui.scripting.builder.BaseScriptBuilder;
import com.jgoodies.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class Script {
protected Scriptable instance;
protected Field field;
protected String property;
protected String expression;
// ***************************************************************************
// * Constants *
// ***************************************************************************
private static final Logger LOGGER = LoggerFactory.getLogger(Script.class.getName());
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param builder
*/
// ---------------------------------------------------------------------------
public Script(BaseScriptBuilder<?> builder) {
this.property = builder.property;
this.expression = builder.expression;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param newInstance
*/
// ---------------------------------------------------------------------------
public void setScriptableInstance(Scriptable newInstance) {
Preconditions.checkArgument(newInstance != null, "Specified instance CAN'T be null!"); //$NON-NLS-1$
this.instance = newInstance;
this.field = this.instance.findProperty(this.property);
if (this.field == null) {
LOGGER.error("Failed to lookup property {} for scriptable instance {}!", this.property, this.instance); //$NON-NLS-1$
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Successful lookup of property {} for scriptable instance {}!", this.property, this.instance); //$NON-NLS-1$
}
}
// ---------------------------------------------------------------------------
/**
* @param newValue
* @return
*/
// ---------------------------------------------------------------------------
public boolean setProperty(Object newValue) {
return this.instance.setProperty(this.field, newValue);
}
}
\ No newline at end of file
......@@ -21,7 +21,7 @@ import java.lang.reflect.Field;
* @version [major].[minor].[micro]
*/
public interface Scriptable {
Field getProperty(String property);
Field findProperty(String property);
void setProperty(Field property, Object value);
boolean setProperty(Field property, Object value);
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2018. 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.scripting.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.BootstrappingUtils;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.scripting.Script;
import lu.list.itis.dkd.tui.utility.Externalization;
import org.jdom2.Element;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
* @param <B>
*/
public abstract class BaseScriptBuilder<B extends BaseScriptBuilder<B>> {
public String property;
public String expression;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public BaseScriptBuilder(Element rootElement) throws BuildException {
this.buildFromBootstrap(rootElement, null, null);
}
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @param context
* @param callback
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public BaseScriptBuilder(Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
this.buildFromBootstrap(rootElement, context, callback);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
private void buildFromBootstrap(@Nullable Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
property = BootstrappingUtils.getContentAsString(rootElement, Externalization.PROPERTY_NODE, BootstrappingUtils.MANDATORY, null, context);
expression = BootstrappingUtils.getContentAsString(rootElement, Externalization.EXPRESSION_NODE, BootstrappingUtils.MANDATORY, null, context);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @return
*/
public abstract Script build();
}
......@@ -181,6 +181,7 @@ public class Externalization extends NLS {
public static String ROTATION_DIRECTION_NODE;
public static String SCALE_NODE;
public static String SATURATION_NODE;
public static String SCRIPT_BUILDER_NAMESPACE;
public static String SCREEN_ID_NODE;
public static String SECTION_NODE;
public static String SECTIONS_NODE;
......
......@@ -696,7 +696,7 @@ public abstract class Corona implements Comparable<Corona>, Cloneable, Touchable
// ---------------------------------------------------------------------------
@Override
public Field getProperty(String property) {
public Field findProperty(String property) {
Field field = null;
try {
......@@ -710,12 +710,15 @@ public abstract class Corona implements Comparable<Corona>, Cloneable, Touchable
// ---------------------------------------------------------------------------
@Override
public void setProperty(Field property, Object value) {
public boolean setProperty(Field property, Object value) {
boolean success = false;
try {
property.set(this, value);
success = true;
} catch (IllegalArgumentException | IllegalAccessException e) {
LOGGER.error("Failed to set property {} to value {}!", property.getName(), value, e); //$NON-NLS-1$
}
return success;
}
// ---------------------------------------------------------------------------
......
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