Commit 53ed2271 authored by Nico Mack's avatar Nico Mack

Added SqlExecutor, new Variable types including Vectors. Variables are

no parameterized. Setting value from object is done via dedicated
setValueFromObject method in order to avoid conflict with Type Erasure.
parent 931e073d
......@@ -80,7 +80,19 @@
<version>2.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901-1.jdbc4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<repositories>
......
......@@ -41,9 +41,9 @@ public class Phenomenon {
/** The clock which may dictate the sampling rate and advancement of the phenomenon. */
private Clock clock;
/** The independent variables characterising the system. */
private ConcurrentHashMap<String, Variable> independentVariables;
private ConcurrentHashMap<String, Variable<?>> independentVariables;
/** The variables depending on the system and its inputs. */
private ConcurrentHashMap<String, Variable> dependentVariables;
private ConcurrentHashMap<String, Variable<?>> dependentVariables;
/** The system computing dependent variables from input independent variables. */
private lu.list.itis.dkd.tui.cps.system.System system;
/** Field indicating whether the observation is to be driven by a clock. */
......@@ -62,8 +62,8 @@ public class Phenomenon {
* Indication whether the observation of the phenomenon is to be driven by the ticking of
* a clock or is synchronous.
*/
public Phenomenon(ConcurrentHashMap<String, Variable> independentVariables,
ConcurrentHashMap<String, Variable> dependentVariables,
public Phenomenon(ConcurrentHashMap<String, Variable<?>> independentVariables,
ConcurrentHashMap<String, Variable<?>> dependentVariables,
lu.list.itis.dkd.tui.cps.system.System system, boolean clockDriven) {
clock = new Clock();
this.independentVariables = independentVariables;
......@@ -103,7 +103,7 @@ public class Phenomenon {
*
* @return The {@link Collection} of dependent variables.
*/
public Collection<Variable> getOutputs() {
public Collection<Variable<?>> getOutputs() {
return dependentVariables.values();
}
......@@ -115,7 +115,7 @@ public class Phenomenon {
* @return The instance of the {@link Variable} or <code>null</code> if no such {@link Variable}
* was defined.
*/
public @Nullable Variable getOutput(String variableName) {
public @Nullable Variable<?> getOutput(String variableName) {
return dependentVariables.get(variableName);
}
......@@ -124,7 +124,7 @@ public class Phenomenon {
*
* @return The value of independentVariables.
*/
public Collection<Variable> getInputs() {
public Collection<Variable<?>> getInputs() {
return independentVariables.values();
}
......
......@@ -22,6 +22,8 @@ package lu.list.itis.dkd.tui.cps.system;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.system.executor.Executor;
import lu.list.itis.dkd.tui.cps.variable.Variable;
......@@ -30,6 +32,7 @@ import com.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.LinkedHashSet;
import javax.script.ScriptEngine;
......@@ -90,7 +93,7 @@ public class Equation {
// executing script!", e); //$NON-NLS-1$
// }
LinkedHashSet<Variable> dependentVariables;
LinkedHashSet<Variable<?>> dependentVariables;
String evaluationErrors;
Preconditions.checkState(scriptExecutor != null);
......@@ -98,7 +101,7 @@ public class Equation {
try {
scriptExecutor.resetExecutionErrors();
for (Variable variable : lockedMapping.getIndependentVariables()) {
for (Variable<?> variable : lockedMapping.getIndependentVariables()) {
scriptExecutor.set(variable);
}
......@@ -108,12 +111,28 @@ public class Equation {
}
dependentVariables = mapping.getDependentVariables();
for (Variable variable : dependentVariables) {
boolean consolidated = (dependentVariables.size() > 1);
HashMap<InputChangeListener, Variable<?>> consolidatedListeners = null;
if (consolidated)
consolidatedListeners = new HashMap<>();
for (Variable<?> variable : dependentVariables) {
variable.setConsolidated(consolidated);
if (consolidated)
consolidatedListeners = variable.consolidateListeners(consolidatedListeners);
try {
variable = scriptExecutor.get(variable);
} catch (Exception exception) {
LOGGER.error("Error while retrieving variable {}", variable.getName(), exception); //$NON-NLS-1$
}
variable.setConsolidated(false);
}
if (consolidated && consolidatedListeners != null) {
for (InputChangeListener listener : consolidatedListeners.keySet()) {
Variable<?> variable = consolidatedListeners.get(listener);
listener.inputChanged(new InputEvent(variable));
}
}
evaluationErrors = scriptExecutor.getExecutionErrors();
......@@ -121,8 +140,8 @@ public class Equation {
if (evaluationErrors.length() > 0) {
LOGGER.warn("Error while evaluating equation : {}", evaluationErrors); //$NON-NLS-1$
LOGGER.warn("Script = {}", this.script); //$NON-NLS-1$
LinkedHashSet<Variable> independentVariables = mapping.getIndependentVariables();
for (Variable variable : independentVariables) {
LinkedHashSet<Variable<?>> independentVariables = mapping.getIndependentVariables();
for (Variable<?> variable : independentVariables) {
LOGGER.trace("{} = {}", variable.getName(), variable.getValue()); //$NON-NLS-1$
}
}
......@@ -176,7 +195,7 @@ public class Equation {
* @return <code>True</code> if the {@link Variable} instance is an independent variable that is
* part of this {@link Equation} isntance's computation.
*/
public boolean catersTo(Variable variable) {
public boolean catersTo(Variable<?> variable) {
return mapping.catersTo(variable);
}
......
......@@ -92,7 +92,7 @@ public class LinearEquationSystem extends System {
super.inputChanged(input);
for (Equation equation : equations.values()) {
if (equation.catersTo((Variable) input.getSource())) {
if (equation.catersTo((Variable<?>) input.getSource())) {
equation.evaluate();
}
}
......
......@@ -36,8 +36,8 @@ import java.util.LinkedHashSet;
*/
@NonNullByDefault
public class Mapping {
private LinkedHashSet<Variable> independentVariables;
private LinkedHashSet<Variable> dependentVariables;
private LinkedHashSet<Variable<?>> independentVariables;
private LinkedHashSet<Variable<?>> dependentVariables;
/**
* Constructor initialising the mapping.
......@@ -47,7 +47,7 @@ public class Mapping {
* @param dependentVariable
* The dependent variable of the mapping.
*/
public Mapping(LinkedHashSet<Variable> independentVariables, LinkedHashSet<Variable> dependentVariables) {
public Mapping(LinkedHashSet<Variable<?>> independentVariables, LinkedHashSet<Variable<?>> dependentVariables) {
// Preconditions.checkArgument(!independentVariables.isEmpty(), "The set of input variables
// cannot be empty."); //$NON-NLS-1$
this.independentVariables = independentVariables;
......@@ -59,7 +59,7 @@ public class Mapping {
*
* @return The value of independentVariables.
*/
public LinkedHashSet<Variable> getIndependentVariables() {
public LinkedHashSet<Variable<?>> getIndependentVariables() {
return independentVariables;
}
......@@ -68,7 +68,7 @@ public class Mapping {
*
* @return The value of dependentVariables.
*/
public LinkedHashSet<Variable> getDependentVariables() {
public LinkedHashSet<Variable<?>> getDependentVariables() {
return dependentVariables;
}
......@@ -78,7 +78,7 @@ public class Mapping {
String separator = ""; //$NON-NLS-1$
StringBuilder renderer = new StringBuilder();
for (Variable variable : independentVariables) {
for (Variable<?> variable : independentVariables) {
renderer.append(separator).append(variable.getName());
separator = ", "; //$NON-NLS-1$
}
......@@ -86,7 +86,7 @@ public class Mapping {
renderer.append(" => "); //$NON-NLS-1$
separator = ""; //$NON-NLS-1$
for (Variable variable : dependentVariables) {
for (Variable<?> variable : dependentVariables) {
renderer.append(separator).append(variable.getName());
separator = ", "; //$NON-NLS-1$
}
......@@ -133,8 +133,8 @@ public class Mapping {
* @return <code>True</code> if the {@link Variable} instance is an independent variable managed
* by this {@link Mapping} instance.
*/
public boolean catersTo(Variable variable) {
for (Variable _variable : independentVariables) {
public boolean catersTo(Variable<?> variable) {
for (Variable<?> _variable : independentVariables) {
if (_variable.equals(variable)) {
return true;
}
......@@ -149,12 +149,12 @@ public class Mapping {
* @return A deep copy of the {@link Mapping}.
*/
public Mapping lock() {
LinkedHashSet<Variable> clonedIndependentVariables = new LinkedHashSet<>();
for (Variable variable : independentVariables) {
LinkedHashSet<Variable<?>> clonedIndependentVariables = new LinkedHashSet<>();
for (Variable<?> variable : independentVariables) {
clonedIndependentVariables.add(variable.clone());
}
LinkedHashSet<Variable> clonedDependentVariables = new LinkedHashSet<>();
for (Variable variable : dependentVariables) {
LinkedHashSet<Variable<?>> clonedDependentVariables = new LinkedHashSet<>();
for (Variable<?> variable : dependentVariables) {
clonedDependentVariables.add(variable.clone());
}
......
......@@ -37,9 +37,9 @@ abstract public class Executor {
LOGGER.warn("Imports not supported by Executor!"); //$NON-NLS-1$
}
abstract public void set(Variable variable);
abstract public void set(Variable<?> variable);
abstract public boolean eval(String script);
abstract public Variable get(Variable variable);
abstract public Variable<?> get(Variable<?> variable);
}
......@@ -2,7 +2,9 @@ package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.system.Import;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.cps.variable.VectorVariable;
import org.python.core.PyArray;
import org.python.core.PyFloat;
import org.python.core.PyObject;
import org.python.core.PyTuple;
......@@ -45,12 +47,32 @@ public class PythonExecutor extends Executor {
}
}
@SuppressWarnings("unchecked")
@Override
public void set(Variable variable) {
Double numericValue = Double.valueOf(variable.getValue().toString());
engine.set(variable.getName(), new PyFloat(numericValue));
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Parameter {} = {}", variable.getName(), variable.getValue()); //$NON-NLS-1$
public void set(Variable<?> variable) {
if (variable instanceof VectorVariable) {
VectorVariable<Double> vector = (VectorVariable<Double>) variable;
List<Double> list = vector.getValue();
if (!list.isEmpty()) {
PyArray array = new PyArray(Double.class, list.size());
int index = 0;
for (Double value : list) {
if (value == null)
value = Double.valueOf(0);
array.set(index++, new PyFloat(value));
}
engine.set(variable.getName(), array);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Parameter {} = {}", variable.getName(), list.toString()); //$NON-NLS-1$
}
}
} else {
Double numericValue = Double.valueOf(variable.getValue().toString());
engine.set(variable.getName(), new PyFloat(numericValue));
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Parameter {} = {}", variable.getName(), variable.getValue()); //$NON-NLS-1$
}
}
}
......@@ -66,7 +88,7 @@ public class PythonExecutor extends Executor {
}
@Override
public Variable get(Variable variable) {
public Variable<?> get(Variable<?> variable) {
PyObject result = null;
String equate = variable.getEquate();
if ((equate != null) && (equate.length() > 0)) {
......@@ -85,7 +107,7 @@ public class PythonExecutor extends Executor {
}
}
variable.setValue((result != null) ? result.__tojava__(Double.class) : null);
variable.setValueFromObject((result != null) ? result.__tojava__(Double.class) : null);
return variable;
}
}
......@@ -31,13 +31,20 @@ import org.eclipse.osgi.util.NLS;
public class Externalization extends NLS {
private static final String BUNDLE_NAME = "lu.list.itis.dkd.tui.cps.utility.externalization";
public static String EXECUTOR_NAMESPACE;
public static String NAMESPACE_SEPARATOR;
public static String EXECUTOR_POSTFIX;
public static String EXECUTOR_CLASS;
public static String NUMERIC_VARIABLE_CLASS;
public static String LOGIC_VARIABLE_CLASS;
public static String TEXT_VARIABLE_CLASS;
public static String SPATIAL_VARIABLE_CLASS;
public static String VECTOR_VARIABLE_CLASS;
public static String EQUATION_ELEMENT;
public static String EQUATIONS_ELEMENT;
public static String INVOKE_ELEMENT;
public static String EXECUTOR_ATTRIBUTE;
public static String NAME_ATTRIBUTE;
public static String OUTPUT_ELEMENT;
public static String OUTPUTS_ELEMENT;
......@@ -64,6 +71,9 @@ public class Externalization extends NLS {
public static final String EMPTY_STRING = "";
public static final String LOGIC_TYPE = "logic";
public static final String NUMERIC_TYPE = "numeric";
public static final String SPATIAL_TYPE = "spatial";
public static final String TEXT_TYPE = "text";
public static final String VECTOR_TYPE = "vector";
static {
......
EXECUTOR_CLASS=executor.class
NUMERIC_VARIABLE_CLASS=numeric.variable.class
LOGIC_VARIABLE_CLASS=logic.variable.class
TEXT_VARIABLE_CLASS=text.variable.class
SPATIAL_VARIABLE_CLASS=spatial.variable.class
VECTOR_VARIABLE_CLASS=vector.variable.class
EXECUTOR_NAMESPACE=lu.list.itis.dkd.tui.cps.system.executor
NAMESPACE_SEPARATOR=.
EXECUTOR_POSTFIX=Executor
EQUATIONS_ELEMENT=equations
EQUATION_ELEMENT=equation
INVOKE_ELEMENT=invoke
EXECUTOR_ATTRIBUTE=executor
NAME_ATTRIBUTE=name
OUTPUTS_ELEMENT=outputs
OUTPUT_ELEMENT=output
......
......@@ -20,10 +20,12 @@
*/
package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Vector;
/**
......@@ -31,7 +33,7 @@ import java.util.Vector;
* @since 1.1
* @version 1.3.1
*/
public class BooleanVariable extends Variable {
public class BooleanVariable extends Variable<Boolean> {
protected boolean value;
......@@ -39,6 +41,8 @@ public class BooleanVariable extends Variable {
* @param name
* @param value
*/
private static final Logger LOGGER = LoggerFactory.getLogger(BooleanVariable.class.getSimpleName());
public BooleanVariable(String name, boolean value) {
super(Externalization.LOGIC_TYPE, name, "boolean"); //$NON-NLS-1$
......@@ -53,21 +57,20 @@ public class BooleanVariable extends Variable {
/** {@inheritDoc} */
@Override
public void setValue(Object value) {
if (value instanceof Boolean) {
this.value = (Boolean) value;
} else {
this.value = (Boolean) valueFromString(value.toString());
}
public void setValue(Boolean newValue) {
this.value = newValue;
this.notifyInputChangeListeners(new InputEvent(this));
}
for (InputChangeListener listener : listeners) {
listener.inputChanged(new InputEvent(this));
}
/** {@inheritDoc} */
@Override
public void setValueFromObject(Object object) {
this.setValue(this.valueFromObject(object));
}
/** {@inheritDoc} */
@Override
public Variable clone() {
public Variable<Boolean> clone() {
BooleanVariable variable = new BooleanVariable(name, value);
variable.listeners = new Vector<>(listeners);
return variable;
......@@ -75,7 +78,25 @@ public class BooleanVariable extends Variable {
/** {@inheritDoc} */
@Override
public Object valueFromString(String stringValue) {
public Boolean valueFromString(String stringValue) {
return Boolean.parseBoolean(stringValue);
}
@Override
public Boolean valueFromObject(Object objectValue) {
Boolean converted = null;
if (objectValue == null) {
LOGGER.warn("Null value specified!"); //$NON-NLS-1$
return null;
}
if (objectValue instanceof Boolean) {
converted = (Boolean) objectValue;
} else {
converted = this.valueFromString(objectValue.toString());
}
return converted;
}
}
\ No newline at end of file
......@@ -22,7 +22,6 @@ package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
......@@ -41,7 +40,7 @@ import java.util.Vector;
* @param <T>
*/
@NonNullByDefault
public class NumericalVariable extends Variable {
public class NumericalVariable extends Variable<Double> {
protected double value;
protected double minValue;
protected double maxValue;
......@@ -68,6 +67,7 @@ public class NumericalVariable extends Variable {
format = new DecimalFormat();
format.setDecimalSeparatorAlwaysShown(false);
format.setMaximumFractionDigits(0);
format.setGroupingUsed(false);
minValue = -Double.MAX_VALUE;
......@@ -106,7 +106,7 @@ public class NumericalVariable extends Variable {
StringBuilder builder = new StringBuilder(format.format(value));
if ((unit != null) && (unit.length() > 0)) {
builder.append(" ").append(unit); //$NON-NLS-1$
}
}
return builder.toString();
}
......@@ -147,9 +147,9 @@ public class NumericalVariable extends Variable {
/** {@inheritDoc} */
@Override
public void setValue(Object value) {
Double newValue;
newValue = (Double) this.valueFromString(value.toString());
public void setValue(Double newValue) {
// Double newValue;
// newValue = (Double) this.valueFromString(value.toString());
if (newValue < this.minValue)
this.value = this.minValue;
else if (newValue > this.maxValue)
......@@ -157,16 +157,18 @@ public class NumericalVariable extends Variable {
else
this.value = newValue;
InputEvent event = new InputEvent(this);
for (InputChangeListener listener : listeners) {
// listener.inputChanged(new InputEvent(this));
listener.inputChanged(event);
}
this.notifyInputChangeListeners(new InputEvent(this));
}
/** {@inheritDoc} */
@Override
public void setValueFromObject(Object object) {
this.setValue(this.valueFromObject(object));
}
/** {@inheritDoc} */
@Override
public Object getValue() {
public Double getValue() {
return this.value;
}
......@@ -249,7 +251,7 @@ public class NumericalVariable extends Variable {
/** {@inheritDoc} */
@Override
public Object valueFromString(String stringValue) {
public Double valueFromString(String stringValue) {
Double newValue = Double.valueOf(0);
try {
newValue = Double.parseDouble(stringValue);
......@@ -259,4 +261,19 @@ public class NumericalVariable extends Variable {
}
return newValue;
}
@Override
public Double valueFromObject(Object objectValue) {
Double converted = null;
if (objectValue == null)
return null;
if (objectValue instanceof Double) {
converted = (Double) objectValue;
} else
converted = this.valueFromString(objectValue.toString());
return converted;
}
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.cps.variable;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.utility.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
public class SpatialVariable extends Variable<Point> {
private Point point;
private static final Logger LOGGER = LoggerFactory.getLogger(SpatialVariable.class.getSimpleName());
private static final Pattern SPATIAL_STRING_PATTERN = Pattern.compile("([0-9]+\\.?[0-9]*)\\s*,\\s*([0-9]+\\.?[0-9]*)(\\s*,\\s*([0-9]+\\.?[0-9]*))?", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
/**
* @param type
* @param name
* @param unit
*/
public SpatialVariable(String name, String unit, Point value) {
super(Externalization.SPATIAL_TYPE, name, unit);
this.point = value;
}
/**
* {@inheritDoc}<br>
* <br>
*
* The hash code is based on the <code>toString()</code> representation of this class.
*/
@Override
public int hashCode() {
return this.point.hashCode();
}
/**
* {@inheritDoc}<br>
* <br>
*
* The equality test is base on equality of name, unit, and value.
*/
@Override
public boolean equals(@Nullable Object object) {
if (object == null)
return false;
if (object == this)
return true;
if (object instanceof SpatialVariable) {
SpatialVariable variable = (SpatialVariable) object;
if (name.equals(variable.getName()) && unit.equals(variable.getUnit()) && variable.getValue().equals(point)) {
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public Point getValue() {
return this.point;
}
/** {@inheritDoc} */
@Override
public void setValue(Point value) {
this.point = value;
this.notifyInputChangeListeners(new InputEvent(this));
}
/** {@inheritDoc} */
@Override
public void setValueFromObject(Object object) {
this.setValue(this.valueFromObject(object));
}
/** {@inheritDoc} */
@Override
public Variable<Point> clone() {
SpatialVariable variable = new SpatialVariable(name, unit, point);
variable.listeners = new Vector<>(listeners);
return variable;
}
/** {@inheritDoc} */
@Override
public Point valueFromString(String stringValue) {
Point newPoint = null;
Matcher pointMatcher = SPATIAL_STRING_PATTERN.matcher(stringValue);
if (pointMatcher.matches()) {
try {
float a = 0;
float x = (float) Double.parseDouble(pointMatcher.group(1));
float y = (float) Double.parseDouble(pointMatcher.group(2));