/*
* Copyright (c) 2012 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.common.scripting.scripts.mathematical;
import javax.script.ScriptException;
import org.springframework.core.convert.ConversionException;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.iabcinc.jmep.Environment;
import com.iabcinc.jmep.Expression;
import com.iabcinc.jmep.XExpression;
import com.iabcinc.jmep.hooks.Constant;
import eu.esdihumboldt.hale.common.align.model.ChildContext;
import eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition;
import eu.esdihumboldt.hale.common.align.transformation.function.PropertyValue;
import eu.esdihumboldt.hale.common.core.service.ServiceProvider;
import eu.esdihumboldt.hale.common.scripting.Script;
/**
* Mathematical formula script implementation.
*
* @author Kai Schwierczek
*/
public class MathScript implements Script {
/**
* @see Script#evaluate(String, Iterable, ServiceProvider)
*/
@Override
public Object evaluate(String script, Iterable<PropertyValue> variables,
ServiceProvider provider) throws ScriptException {
Object result;
try {
Expression ex = new Expression(script, createEnvironment(variables));
result = ex.evaluate();
} catch (XExpression e) {
throw new ScriptException(e); // XXX message + exception?
}
return result;
}
private Environment createEnvironment(Iterable<PropertyValue> variables) {
Environment env = new Environment();
for (PropertyValue var : variables) {
// add the variable to the environment
// determine the variable value
Object value = var.getValue();
Number number;
if (value instanceof Number) {
number = (Number) value;
}
else {
// try conversion to Double as default
try {
number = var.getValueAs(Double.class);
} catch (ConversionException ce) {
// currently not convertible values are ignored.
// maybe they should be checked whether they are used in the
// expression for better exception messages
continue;
}
}
// the JMEP library only supports Integer and Doubles, but e.g. no
// Floats
if (!(number instanceof Integer) && !(number instanceof Double)) {
number = number.doubleValue();
}
Constant varValue = new Constant(number);
// add with short name, if it does not override something
String name = var.getProperty().getDefinition().getName().getLocalPart();
if (!env.getVariables().containsKey(name))
env.addVariable(name, varValue);
// add with full name
env.addVariable(getVariableName(var.getProperty()), varValue);
}
return env;
}
/**
* @see eu.esdihumboldt.hale.common.scripting.Script#getVariableName(eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition)
*/
@Override
public String getVariableName(PropertyEntityDefinition entityDefinition) {
return Joiner.on('.').join(Lists.transform(entityDefinition.getPropertyPath(),
new Function<ChildContext, String>() {
@Override
public String apply(ChildContext input) {
return input.getChild().getName().getLocalPart();
}
}));
}
/**
* @see Script#validate(String, Iterable, ServiceProvider)
*/
@Override
public String validate(String script, Iterable<PropertyValue> variables,
ServiceProvider provider) {
try {
// without evaluate no check is done whether the used variables are
// actually available
new Expression(script, createEnvironment(variables)).evaluate();
} catch (Exception e) {
String message = e.getLocalizedMessage();
if (message == null || message.isEmpty())
message = "Invalid variable";
return message;
}
return null;
}
/**
* @see eu.esdihumboldt.hale.common.scripting.Script#getId()
*/
@Override
public String getId() {
return "eu.esdihumboldt.hale.common.scripting.math";
}
@Override
public boolean requiresReplacedTransformationVariables() {
return true;
}
}