/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2013, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.filter.function.groovy;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.codehaus.groovy.control.CompilationFailedException;
import org.geotoolkit.filter.DefaultPropertyName;
import org.geotoolkit.filter.function.AbstractFunction;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.PropertyName;
import org.apache.sis.util.logging.Logging;
/**
* Groovy function.
* First parameter is the function equation, following parameters hold the list of all
* requiered feature properties.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public class GroovyFunction extends AbstractFunction {
private static final char VAR_CHARACTER = '$';
private static final Set<Character> END_CHARACTERS = new HashSet<Character>();
static{
//commun formating characters
END_CHARACTERS.add(' ');
END_CHARACTERS.add('\t');
END_CHARACTERS.add('\r');
//math caracters
END_CHARACTERS.add('+');
END_CHARACTERS.add('-');
END_CHARACTERS.add('/');
END_CHARACTERS.add('*');
END_CHARACTERS.add('%');
END_CHARACTERS.add(',');
END_CHARACTERS.add(';');
END_CHARACTERS.add(':');
END_CHARACTERS.add('<');
END_CHARACTERS.add('>');
//others
END_CHARACTERS.add('(');
END_CHARACTERS.add(')');
END_CHARACTERS.add('[');
END_CHARACTERS.add(']');
END_CHARACTERS.add('{');
END_CHARACTERS.add('}');
END_CHARACTERS.add('.');
}
private final String groovy;
private Script compiled;
public GroovyFunction(final Expression expression) {
super(GroovyFunctionFactory.GROOVY, prepare(expression), null);
groovy = expression.evaluate(null, String.class);
}
/**
* Map groovy parameters to PropertyNames.
* @param gvFunction
* @return Expression[]
*/
private static Expression[] prepare(final Expression gvFunction){
final String str = gvFunction.evaluate(null, String.class);
final List<Expression> properties = new ArrayList<Expression>();
properties.add(gvFunction);
String current = null;
for(int i=0,n=str.length(); i<n; i++){
char c = str.charAt(i);
if(current != null){
if(END_CHARACTERS.contains(c)){
if(!current.isEmpty()){
properties.add(new DefaultPropertyName(current));
}
current = null;
}else{
current += c;
}
}else{
if(c == VAR_CHARACTER){
current = "";
}
}
}
if(current != null && !current.isEmpty()){
properties.add(new DefaultPropertyName(current));
}
return properties.toArray(new Expression[properties.size()]);
}
private Script getCompiled() throws CompilationFailedException {
if(compiled == null){
final GroovyShell shell = new GroovyShell(this.getClass().getClassLoader());
compiled = shell.parse(groovy);
}
return compiled;
}
@Override
public Object evaluate(final Object feature) {
Binding bindings = new Binding();
for(int i=1,n=parameters.size(); i<n; i++){
final PropertyName property = (PropertyName) parameters.get(i);
final Object value = property.evaluate(feature);
bindings.setVariable(VAR_CHARACTER+property.getPropertyName(), value);
}
try {
final Script script = getCompiled();
script.setBinding(bindings);
return script.run();
} catch (CompilationFailedException ex) {
Logging.getLogger("org.geotoolkit.filter.function.groovy").log(Level.WARNING, null, ex);
}
return "";
}
}