/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2009, 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.javascript; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import javax.script.Bindings; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; 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; /** * Javascript function. * First parameter is the function equation, following parameters hold the list of all * requiered feature properties. * * @author Johann Sorel (Geomatys) * @module */ public class JavaScriptFunction 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('}'); } private final String javascript; private transient ScriptEngine engine; private transient CompiledScript compiled = null; public JavaScriptFunction(final Expression expression) throws ScriptException { super(JavaScriptFunctionFactory.JAVASCRIPT, prepare(expression), null); javascript = expression.evaluate(null, String.class); } private ScriptEngine getEngine(){ if(engine == null){ ScriptEngineManager manager = new ScriptEngineManager(); engine = manager.getEngineByName("js"); } return engine; } private CompiledScript getCompiled() throws ScriptException { if(compiled == null){ compiled = ((Compilable)getEngine()).compile(javascript); } return compiled; } private static Expression[] prepare(final Expression jsFunction){ final String str = jsFunction.evaluate(null, String.class); final List<Expression> properties = new ArrayList<Expression>(); properties.add(jsFunction); 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()]); } @Override public Object evaluate(final Object feature) { final Bindings bindings = getEngine().createBindings(); for(int i=1,n=parameters.size(); i<n; i++){ final PropertyName property = (PropertyName) parameters.get(i); final Object value = property.evaluate(feature); bindings.put(VAR_CHARACTER+property.getPropertyName(), value); } try { return getCompiled().eval(bindings); } catch (ScriptException ex) { Logging.getLogger("org.geotoolkit.filter.function.javascript").log(Level.WARNING, null, ex); } return ""; } }