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);
}
......
......@@ -26,6 +26,7 @@ import lu.list.itis.dkd.tui.cps.system.executor.Executor;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.variable.NumericalVariable;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.utility.Point;
import com.google.common.base.Strings;
......@@ -64,11 +65,13 @@ import java.util.regex.Pattern;
public class EquationSystemBuilder {
private Properties properties;
private Document equationDocument;
private Executor scriptExecutor;
private Executor defaultExecutor;
private ConcurrentHashMap<String, Variable> independentVariables;
private ConcurrentHashMap<String, Variable> dependentVariables;
private ConcurrentHashMap<String, Variable> outputVariables;
private HashMap<String, Executor> executors;
private ConcurrentHashMap<String, Variable<?>> independentVariables;
private ConcurrentHashMap<String, Variable<?>> dependentVariables;
private ConcurrentHashMap<String, Variable<?>> outputVariables;
private ConcurrentHashMap<String, LinearEquationSystem> rootEquations;
// TODO Refactor to use Multimaps
......@@ -80,6 +83,8 @@ public class EquationSystemBuilder {
private ConcurrentHashMap<String, LinearEquationSystem> equations;
private ConcurrentHashMap<String, Phenomenon> phenomena;
private static final String DEFAULT_EXECUTOR = "Default"; //$NON-NLS-1$
private static final Pattern booleanPattern = Pattern.compile("true|yes|1", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
private static final Logger logger = LoggerFactory.getLogger(EquationSystemBuilder.class.getSimpleName());
......@@ -88,11 +93,14 @@ public class EquationSystemBuilder {
*/
public EquationSystemBuilder(Properties properties) {
this.properties = properties;
this.scriptExecutor = this.instantiateExecutor(properties);
this.defaultExecutor = this.instantiateDefaultExecutor(properties);
independentVariables = new ConcurrentHashMap<String, Variable>();
dependentVariables = new ConcurrentHashMap<String, Variable>();
outputVariables = new ConcurrentHashMap<String, Variable>();
executors = new HashMap<String, Executor>();
executors.put(DEFAULT_EXECUTOR, this.defaultExecutor);
independentVariables = new ConcurrentHashMap<String, Variable<?>>();
dependentVariables = new ConcurrentHashMap<String, Variable<?>>();
outputVariables = new ConcurrentHashMap<String, Variable<?>>();
rootEquations = new ConcurrentHashMap<String, LinearEquationSystem>();
parameterDependencies = new ConcurrentHashMap<String, List<String>>();
......@@ -110,7 +118,31 @@ public class EquationSystemBuilder {
// ***************************************************************************
// ---------------------------------------------------------------------------
private Executor instantiateExecutor(Properties props) {
private Integer getIntegerValue(String valueAsString) {
Integer value = null;
try {
value = Integer.parseInt(valueAsString);
} catch (NumberFormatException exception) {
logger.error("Failed to convert {} to an integer value!", valueAsString); //$NON-NLS-1$
}
return value;
}
// ---------------------------------------------------------------------------
private Double getDoubleValue(String valueAsString) {
Double value = null;
try {
value = Double.parseDouble(valueAsString);
} catch (NumberFormatException exception) {
logger.error("Failed to convert {} to an double value!", valueAsString); //$NON-NLS-1$
}
return value;
}
// ---------------------------------------------------------------------------
private Executor instantiateDefaultExecutor(Properties props) {
Executor executor = null;
String executorClass = props.getProperty(Externalization.EXECUTOR_CLASS);
......@@ -127,8 +159,26 @@ public class EquationSystemBuilder {
// ---------------------------------------------------------------------------
private Variable instantiateVariable(String name, String type, String unit, String value) {
Variable variable = null;
private Executor instantiateExecutor(Properties props, String ExecutorName) {
Executor executor = null;
String executorClass = Externalization.EXECUTOR_NAMESPACE + Externalization.NAMESPACE_SEPARATOR + ExecutorName + Externalization.EXECUTOR_POSTFIX;
try {
executor = (Executor) Class.forName(executorClass)
.getConstructor(Properties.class)
.newInstance(props);
} catch (Exception exception) {
logger.error("Failed to instantiate executor class {}!", executorClass, exception); //$NON-NLS-1$
}
return executor;
}
// ---------------------------------------------------------------------------
@SuppressWarnings({"unchecked"})
private <T> Variable<T> instantiateVariable(String name, String type, String unit, String value) {
Variable<T> variable = null;
String variableClass = "undefined"; //$NON-NLS-1$
try {
switch (type) {
......@@ -136,7 +186,7 @@ public class EquationSystemBuilder {
default:
variableClass = properties.getProperty(Externalization.LOGIC_VARIABLE_CLASS);
variable = (Variable) Class.forName(variableClass)
variable = (Variable<T>) Class.forName(variableClass)
.getConstructor(String.class, String.class, boolean.class)
.newInstance(name, unit, false);
if (!Strings.isNullOrEmpty(value))
......@@ -147,11 +197,41 @@ public class EquationSystemBuilder {
case Externalization.NUMERIC_TYPE:
variableClass = properties.getProperty(Externalization.NUMERIC_VARIABLE_CLASS);
variable = (Variable) Class.forName(variableClass)
variable = (Variable<T>) Class.forName(variableClass)
.getConstructor(String.class, String.class, double.class)
.newInstance(name, unit, 0);
.newInstance(name, unit, 0d);
if (!Strings.isNullOrEmpty(value))
variable.setValue(variable.valueFromString(value));
break;
case Externalization.TEXT_TYPE:
variableClass = properties.getProperty(Externalization.TEXT_VARIABLE_CLASS);
variable = (Variable<T>) Class.forName(variableClass)
.getConstructor(String.class, String.class)
.newInstance(name, value);
break;
case Externalization.SPATIAL_TYPE:
variableClass = properties.getProperty(Externalization.SPATIAL_VARIABLE_CLASS);
variable = (Variable<T>) Class.forName(variableClass)
.getConstructor(String.class, String.class, Point.class)
.newInstance(name, unit, null);
if (!Strings.isNullOrEmpty(value))
variable.setValue(variable.valueFromString(value));
break;
case Externalization.VECTOR_TYPE:
variableClass = properties.getProperty(Externalization.VECTOR_VARIABLE_CLASS);
variable = (Variable<T>) Class.forName(variableClass)
.getConstructor(String.class, String.class)
.newInstance(name, unit);
break;
}
} catch (Exception exception) {
logger.error("Failed to instantiate variable class {}!", variableClass, exception); //$NON-NLS-1$
......@@ -206,14 +286,19 @@ public class EquationSystemBuilder {
attribute = element.getAttributeValue(Externalization.EQUATE_ATTRIBUTE);
attributes.put(Externalization.EQUATE_ATTRIBUTE, attribute);
attribute = element.getChildText(Externalization.DECIMALS_ATTRIBUTE);
if (Strings.isNullOrEmpty(attribute))
attribute = element.getAttributeValue(Externalization.DECIMALS_ATTRIBUTE);
attributes.put(Externalization.DECIMALS_ATTRIBUTE, attribute);
return attributes;
}
// ---------------------------------------------------------------------------
private Variable createVariable(HashMap<String, String> attributes) {
Variable variable;
private Variable<?> createVariable(HashMap<String, String> attributes) {
Variable<?> variable;
// String scale = xmlElement.getAttributeValue(Externalization.SCALE_ATTRIBUTE);
// String decimals = xmlElement.getAttributeValue(Externalization.DECIMALS_ATTRIBUTE);
......@@ -227,14 +312,17 @@ public class EquationSystemBuilder {
NumericalVariable numericVariable = (NumericalVariable) variable;
if (!Strings.isNullOrEmpty(attributes.get(Externalization.MINIMUM_ATTRIBUTE)))
numericVariable.setMinValue((Double) numericVariable.valueFromString(attributes.get(Externalization.MINIMUM_ATTRIBUTE)));
numericVariable.setMinValue(this.getDoubleValue(attributes.get(Externalization.MINIMUM_ATTRIBUTE)));
if (!Strings.isNullOrEmpty(attributes.get(Externalization.MAXIMUM_ATTRIBUTE)))
numericVariable.setMinValue((Double) numericVariable.valueFromString(attributes.get(Externalization.MAXIMUM_ATTRIBUTE)));
numericVariable.setMinValue(this.getDoubleValue(attributes.get(Externalization.MAXIMUM_ATTRIBUTE)));
if (!Strings.isNullOrEmpty(attributes.get(Externalization.EQUATE_ATTRIBUTE)))
numericVariable.setEquate(attributes.get(Externalization.EQUATE_ATTRIBUTE));
if (!Strings.isNullOrEmpty(attributes.get(Externalization.DECIMALS_ATTRIBUTE)))
numericVariable.setNumberOfDecimals(this.getIntegerValue(attributes.get(Externalization.DECIMALS_ATTRIBUTE)));
variable = numericVariable;
}
......@@ -449,7 +537,7 @@ public class EquationSystemBuilder {
}
if (!dependentVariables.containsKey(identifier)) {
Variable output = null;
Variable<?> output = null;
if (outputVariables.containsKey(identifier)) {
output = outputVariables.get(identifier);
output.setEquate(resultAttributes.get(Externalization.EQUATE_ATTRIBUTE));
......@@ -491,8 +579,8 @@ public class EquationSystemBuilder {
if (Strings.isNullOrEmpty(equationName))
equationName = equation.getAttributeValue(Externalization.NAME_ATTRIBUTE);
LinkedHashSet<Variable> equationInputs = new LinkedHashSet<>();
LinkedHashSet<Variable> equationOutputs = new LinkedHashSet<>();
LinkedHashSet<Variable<?>> equationInputs = new LinkedHashSet<>();
LinkedHashSet<Variable<?>> equationOutputs = new LinkedHashSet<>();
boolean lockToNesting = true;
String periodicity = equation.getAttributeValue(Externalization.PERIODIC_ATTRIBUTE);
boolean periodic = false;
......@@ -527,27 +615,43 @@ public class EquationSystemBuilder {
}
}
String script = equation.getChildText(Externalization.INVOKE_ELEMENT);
String script = null;
String executor = null;
Element invokeTag = equation.getChild(Externalization.INVOKE_ELEMENT);
if (invokeTag != null) {
script = invokeTag.getText();
executor = invokeTag.getAttributeValue(Externalization.EXECUTOR_ATTRIBUTE);
if (!Strings.isNullOrEmpty(executor)) {
if (!executors.containsKey(executor)) {
executors.put(executor, this.instantiateExecutor(properties, executor));
}
} else {
executor = DEFAULT_EXECUTOR;
}
}
Mapping variableMapping = new Mapping(equationInputs, equationOutputs);
final LinearEquationSystem equationSystem = new LinearEquationSystem(lockToNesting);
Equation newEquation = new Equation(variableMapping, script);
newEquation.setExecutor(this.scriptExecutor);
newEquation.setExecutor(executors.get(executor));
equationSystem.addEquation(newEquation);
if (!periodic) {
for (Variable parameter : equationInputs) {
for (Variable<?> parameter : equationInputs) {
parameter.addListener(equationSystem);
}
equations.put(equationName, equationSystem);
} else {
ConcurrentHashMap<String, Variable> inputs = new ConcurrentHashMap<String, Variable>();
ConcurrentHashMap<String, Variable> outputs = new ConcurrentHashMap<String, Variable>();
ConcurrentHashMap<String, Variable<?>> inputs = new ConcurrentHashMap<String, Variable<?>>();
ConcurrentHashMap<String, Variable<?>> outputs = new ConcurrentHashMap<String, Variable<?>>();
for (Variable input : equationInputs) {
for (Variable<?> input : equationInputs) {
inputs.put(input.getName(), input);
}
for (Variable output : equationOutputs) {
for (Variable<?> output : equationOutputs) {
outputs.put(output.getName(), output);
}
......@@ -562,7 +666,7 @@ public class EquationSystemBuilder {
for (String equationName : this.equations.keySet()) {
if (equationImports.containsKey(equationName)) {
this.scriptExecutor.resolve(equationImports.get(equationName));
this.defaultExecutor.resolve(equationImports.get(equationName));
}
equation = this.equations.get(equationName);
......@@ -590,7 +694,7 @@ public class EquationSystemBuilder {
for (String phenomenonName : this.phenomena.keySet()) {
if (equationImports.containsKey(phenomenonName)) {
this.scriptExecutor.resolve(equationImports.get(phenomenonName));
this.defaultExecutor.resolve(equationImports.get(phenomenonName));
}
}
}
......@@ -648,7 +752,7 @@ public class EquationSystemBuilder {
*
* @return The map of input variables.
*/
public Map<String, Variable> getInputVariables() {
public Map<String, Variable<?>> getInputVariables() {
return independentVariables;
}
......@@ -658,7 +762,7 @@ public class EquationSystemBuilder {
*
* @return The map of output variables.
*/
public Map<String, Variable> getOutputVariables() {
public Map<String, Variable<?>> getOutputVariables() {
return outputVariables;
}
......
......@@ -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);