/*
* 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:
* HUMBOLDT EU Integrated Project #030962
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.cst.functions.core;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.springframework.core.convert.ConversionException;
import com.google.common.base.Joiner;
import com.google.common.collect.ListMultimap;
import eu.esdihumboldt.hale.common.align.model.ChildContext;
import eu.esdihumboldt.hale.common.align.model.functions.FormattedStringFunction;
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.PropertyValue;
import eu.esdihumboldt.hale.common.align.transformation.function.TransformationException;
import eu.esdihumboldt.hale.common.align.transformation.function.impl.AbstractSingleTargetPropertyTransformation;
import eu.esdihumboldt.hale.common.align.transformation.function.impl.NoResultException;
import eu.esdihumboldt.hale.common.align.transformation.report.TransformationLog;
/**
* Function that creates a formatted string from a pattern and input variables.
*
* @author Simon Templer
*/
public class FormattedString
extends AbstractSingleTargetPropertyTransformation<TransformationEngine>
implements FormattedStringFunction {
@Override
protected Object evaluate(String transformationIdentifier, TransformationEngine engine,
ListMultimap<String, PropertyValue> variables, String resultName,
PropertyEntityDefinition resultProperty, Map<String, String> executionParameters,
TransformationLog log) throws TransformationException, NoResultException {
String pattern = getParameterChecked(PARAMETER_PATTERN).as(String.class);
// replace transformation variables
pattern = getExecutionContext().getVariables().replaceVariables(pattern);
// name/value mapping
Map<String, Object> values = new LinkedHashMap<String, Object>();
List<PropertyValue> vars = variables.get(ENTITY_VARIABLE);
for (PropertyValue var : vars) {
// determine the variable value
Object value;
try {
value = var.getValueAs(String.class);
} catch (ConversionException e) {
value = var.getValue();
}
addValue(values, value, var.getProperty());
}
// replace markers in pattern
// FIXME this is quick and dirty! does not handle escaping
int i = 0;
for (Entry<String, Object> entry : values.entrySet()) {
String name = entry.getKey();
pattern = pattern.replaceAll(Pattern.quote("{" + name + "}"), "{" + i + "}");
i++;
}
try {
return MessageFormat.format(pattern, values.values().toArray());
} catch (IllegalArgumentException e) {
// missing inputs result in an invalid pattern
// TODO better way to handle missing inputs
// FIXME an error should still be reported for invalid patterns
throw new NoResultException(e);
}
}
/**
* Add a value to the given map of values, with the variable names derived
* from the associated property definition.
*
* @param values the map associating variable names to values
* @param value the value
* @param property the associated property
*/
public static void addValue(Map<String, Object> values, Object value,
PropertyEntityDefinition property) {
// determine the variable name
String name = property.getDefinition().getName().getLocalPart();
// add with short name, but ensure no variable with only a short
// name is overridden
if (!values.keySet().contains(name) || property.getPropertyPath().size() == 1) {
values.put(name, value);
}
// add with long name if applicable
if (property.getPropertyPath().size() > 1) {
List<String> names = new ArrayList<String>();
for (ChildContext context : property.getPropertyPath()) {
names.add(context.getChild().getName().getLocalPart());
}
String longName = Joiner.on('.').join(names);
values.put(longName, value);
}
}
}