/*
* 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.transformation;
import java.text.MessageFormat;
import java.util.Map;
import javax.script.ScriptException;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import eu.esdihumboldt.hale.common.align.model.ParameterValue;
import eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition;
import eu.esdihumboldt.hale.common.align.transformation.engine.TransformationEngine;
import eu.esdihumboldt.hale.common.align.transformation.function.PropertyTransformation;
import eu.esdihumboldt.hale.common.align.transformation.function.PropertyValue;
import eu.esdihumboldt.hale.common.align.transformation.function.TransformationException;
import eu.esdihumboldt.hale.common.align.transformation.function.impl.AbstractPropertyTransformation;
import eu.esdihumboldt.hale.common.align.transformation.report.TransformationLog;
import eu.esdihumboldt.hale.common.core.io.Value;
import eu.esdihumboldt.hale.common.scripting.Script;
import eu.esdihumboldt.hale.common.scripting.ScriptExtension;
import eu.esdihumboldt.hale.common.scripting.ScriptFactory;
/**
* Base class for {@link PropertyTransformation} that supports evaluating
* scripted parameters.
*
* @param <E> the transformation engine type
* @author Kai Schwierczek
*/
public abstract class AbstractScriptedPropertyTransformation<E extends TransformationEngine>
extends AbstractPropertyTransformation<E> {
private ListMultimap<String, Value> transformedParameters;
@Override
protected final ListMultimap<String, Object> evaluate(String transformationIdentifier, E engine,
ListMultimap<String, PropertyValue> variables,
ListMultimap<String, PropertyEntityDefinition> resultNames,
Map<String, String> executionParameters, TransformationLog log)
throws TransformationException {
ListMultimap<String, ParameterValue> originalParameters = getParameters();
ListMultimap<String, Value> transformedParameters = ArrayListMultimap.create();
if (originalParameters != null) {
for (Map.Entry<String, ParameterValue> entry : originalParameters.entries()) {
if (!entry.getValue().needsProcessing()) {
Value value = entry.getValue().intern();
if (!value.isRepresentedAsDOM()) {
value = Value.simple(getExecutionContext().getVariables()
.replaceVariables(value.getStringRepresentation()));
}
transformedParameters.put(entry.getKey(), value);
}
else {
// type is a script
ScriptFactory factory = ScriptExtension.getInstance()
.getFactory(entry.getValue().getType());
if (factory == null)
throw new TransformationException("Couldn't find factory for script id "
+ entry.getValue().getType());
Script script;
try {
script = factory.createExtensionObject();
} catch (Exception e) {
throw new TransformationException("Couldn't create script from factory", e);
}
Object result;
try {
String scriptStr = entry.getValue().as(String.class);
if (script.requiresReplacedTransformationVariables()) {
// replace transformation variables
scriptStr = getExecutionContext().getVariables()
.replaceVariables(scriptStr);
}
result = script.evaluate(scriptStr, variables.values(),
getExecutionContext());
} catch (ScriptException e) {
throw new TransformationException(
"Couldn't evaluate a transformation parameter", e);
}
// XXX use conversion service instead of valueOf?
transformedParameters.put(entry.getKey(), Value.simple(result));
}
}
}
this.transformedParameters = Multimaps.unmodifiableListMultimap(transformedParameters);
return evaluateImpl(transformationIdentifier, engine, variables, resultNames,
executionParameters, log);
}
/**
* Execute the evaluation function as configured. The transformed parameters
* are available in here.
*
* @param transformationIdentifier the transformation function identifier
* @param engine the transformation engine that may be used for the function
* execution
* @param variables the input variables
* @param resultNames the expected results (names associated with the
* corresponding entity definitions)
* @param executionParameters additional parameters for the execution, may
* be <code>null</code>
* @param log the transformation log to report any information about the
* execution of the transformation to
* @return the evaluation result
* @throws TransformationException if an unrecoverable error occurs during
* transformation
*/
protected abstract ListMultimap<String, Object> evaluateImpl(String transformationIdentifier,
E engine, ListMultimap<String, PropertyValue> variables,
ListMultimap<String, PropertyEntityDefinition> resultNames,
Map<String, String> executionParameters, TransformationLog log)
throws TransformationException;
/**
* Returns the transformed parameters.
*
* @return the transformed parameters
*/
protected ListMultimap<String, Value> getTransformedParameters() {
return transformedParameters;
}
/**
* Get the first evaluated parameter defined with the given parameter name.
* Throws a {@link TransformationException} if such a parameter doesn't
* exist.
*
* @param parameterName the parameter name
* @return the parameter value
* @throws TransformationException if a parameter with the given name
* doesn't exist
*/
protected Value getTransformedParameterChecked(String parameterName)
throws TransformationException {
if (transformedParameters == null || transformedParameters.get(parameterName) == null
|| transformedParameters.get(parameterName).isEmpty()) {
throw new TransformationException(
MessageFormat.format("Mandatory parameter {0} not defined", parameterName));
}
return transformedParameters.get(parameterName).get(0);
}
/**
* Get the first evaluated parameter defined with the given parameter name.
* If no such parameter exists, the given default value is returned.
*
* @param parameterName the parameter name
* @param defaultValue the default value for the parameter
* @return the parameter value, or the default if none is specified
*/
protected Value getTransformedOptionalParameter(String parameterName, Value defaultValue) {
if (transformedParameters == null || transformedParameters.get(parameterName) == null
|| transformedParameters.get(parameterName).isEmpty()) {
return defaultValue;
}
return transformedParameters.get(parameterName).get(0);
}
}