View Javadoc
1   /*******************************************************************************
2    * Portions created by Sebastian Thomschke are copyright (c) 2005-2015 Sebastian
3    * Thomschke.
4    *
5    * All Rights Reserved. This program and the accompanying materials
6    * are made available under the terms of the Eclipse Public License v1.0
7    * which accompanies this distribution, and is available at
8    * http://www.eclipse.org/legal/epl-v10.html
9    *
10   * Contributors:
11   *     Sebastian Thomschke - initial implementation.
12   *******************************************************************************/
13  package net.sf.oval.expression;
14  
15  import java.util.List;
16  import java.util.Map;
17  import java.util.Map.Entry;
18  
19  import javax.script.Bindings;
20  import javax.script.Compilable;
21  import javax.script.CompiledScript;
22  import javax.script.ScriptEngine;
23  import javax.script.ScriptEngineFactory;
24  import javax.script.ScriptEngineManager;
25  import javax.script.ScriptException;
26  
27  import net.sf.oval.Validator;
28  import net.sf.oval.exception.ExpressionEvaluationException;
29  import net.sf.oval.internal.Log;
30  import net.sf.oval.internal.util.ObjectCache;
31  
32  /**
33   * JSR223 Support
34   *
35   * @author Sebastian Thomschke
36   */
37  public class ExpressionLanguageScriptEngineImpl extends AbstractExpressionLanguage
38  {
39  	private static final Log LOG = Log.getLog(ExpressionLanguageScriptEngineImpl.class);
40  
41  	private static final ScriptEngineManager FACTORY = new ScriptEngineManager();
42  
43  	static
44  	{
45  		final List<Object> languages = Validator.getCollectionFactory().createList();
46  		for (final ScriptEngineFactory ef : FACTORY.getEngineFactories())
47  		{
48  			languages.add(ef.getNames());
49  		}
50  		LOG.info("Available ScriptEngine language names: {1}", languages);
51  	}
52  
53  	public static ExpressionLanguageScriptEngineImpl get(final String languageId)
54  	{
55  		final ScriptEngine engine = FACTORY.getEngineByName(languageId);
56  		return engine == null ? null : new ExpressionLanguageScriptEngineImpl(engine);
57  	}
58  
59  	private final Compilable compilable;
60  	private final ScriptEngine engine;
61  	private final ObjectCache<String, CompiledScript> compiledCache;
62  
63  	private ExpressionLanguageScriptEngineImpl(final ScriptEngine engine)
64  	{
65  		this.engine = engine;
66  		if (engine instanceof Compilable)
67  		{
68  			compilable = (Compilable) engine;
69  			compiledCache = new ObjectCache<String, CompiledScript>();
70  		}
71  		else
72  		{
73  			compilable = null;
74  			compiledCache = null;
75  		}
76  	}
77  
78  	public Object evaluate(final String expression, final Map<String, ? > values) throws ExpressionEvaluationException
79  	{
80  		LOG.debug("Evaluating JavaScript expression: {1}", expression);
81  		try
82  		{
83  			final Bindings scope = engine.createBindings();
84  			for (final Entry<String, ? > entry : values.entrySet())
85  			{
86  				scope.put(entry.getKey(), entry.getValue());
87  			}
88  
89  			if (compilable != null)
90  			{
91  				CompiledScript compiled = compiledCache.get(expression);
92  				if (compiled == null)
93  				{
94  					compiled = compilable.compile(expression);
95  					compiledCache.put(expression, compiled);
96  				}
97  				return compiled.eval(scope);
98  			}
99  			return engine.eval(expression, scope);
100 		}
101 		catch (final ScriptException ex)
102 		{
103 			throw new ExpressionEvaluationException("Evaluating JavaScript expression failed: " + expression, ex);
104 		}
105 	}
106 }