View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jexl3.scripting;
19  
20  import java.io.Reader;
21  import java.util.Arrays;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.script.CompiledScript;
26  import javax.script.ScriptContext;
27  import javax.script.ScriptEngine;
28  import javax.script.ScriptEngineManager;
29  import javax.script.ScriptException;
30  
31  import org.apache.commons.jexl3.JexlBuilder;
32  import org.apache.commons.jexl3.JexlException;
33  import org.apache.commons.jexl3.introspection.JexlPermissions;
34  import org.apache.commons.logging.LogFactory;
35  import org.junit.After;
36  import org.junit.Assert;
37  import org.junit.Before;
38  import org.junit.Test;
39  
40  public class JexlScriptEngineTest {
41      private static final List<String> NAMES = Arrays.asList("JEXL", "Jexl", "jexl",
42                                                              "JEXL2", "Jexl2", "jexl2",
43                                                              "JEXL3", "Jexl3", "jexl3");
44      private static final List<String> EXTENSIONS = Arrays.asList("jexl", "jexl2", "jexl3");
45      private static final List<String> MIMES = Arrays.asList("application/x-jexl",
46                                                              "application/x-jexl2",
47                                                              "application/x-jexl3");
48  
49      @Before
50      public void setUp() {
51      }
52  
53      @After
54      public void tearDown() {
55          JexlBuilder.setDefaultPermissions(null);
56          JexlScriptEngine.setInstance(null);
57          JexlScriptEngine.setPermissions(null);
58      }
59  
60      @Test
61      public void testScriptEngineFactory() throws Exception {
62          final JexlScriptEngineFactory factory = new JexlScriptEngineFactory();
63          Assert.assertEquals("JEXL Engine", factory.getParameter(ScriptEngine.ENGINE));
64          Assert.assertEquals("3.3", factory.getParameter(ScriptEngine.ENGINE_VERSION));
65          Assert.assertEquals("JEXL", factory.getParameter(ScriptEngine.LANGUAGE));
66          Assert.assertEquals("3.3", factory.getParameter(ScriptEngine.LANGUAGE_VERSION));
67          Assert.assertNull(factory.getParameter("THREADING"));
68          Assert.assertEquals(NAMES, factory.getParameter(ScriptEngine.NAME));
69          Assert.assertEquals(EXTENSIONS, factory.getExtensions());
70          Assert.assertEquals(MIMES, factory.getMimeTypes());
71  
72          Assert.assertEquals("42;", factory.getProgram("42"));
73          Assert.assertEquals("str.substring(3,4)", factory.getMethodCallSyntax("str", "substring", "3", "4"));
74      }
75  
76      @Test
77      public void testScriptingGetBy() throws Exception {
78          final ScriptEngineManager manager = new ScriptEngineManager();
79          Assert.assertNotNull("Manager should not be null", manager);
80          for (final String name : NAMES) {
81              final ScriptEngine engine = manager.getEngineByName(name);
82              Assert.assertNotNull("Engine should not be null (name)", engine);
83          }
84          for (final String extension : EXTENSIONS) {
85              final ScriptEngine engine = manager.getEngineByExtension(extension);
86              Assert.assertNotNull("Engine should not be null (extension)", engine);
87          }
88          for (final String mime : MIMES) {
89              final ScriptEngine engine = manager.getEngineByMimeType(mime);
90              Assert.assertNotNull("Engine should not be null (mime)", engine);
91          }
92      }
93  
94      @Test
95      public void testScripting() throws Exception {
96          final ScriptEngineManager manager = new ScriptEngineManager();
97          Assert.assertNotNull("Manager should not be null", manager);
98          final ScriptEngine engine = manager.getEngineByName("jexl3");
99          final Integer initialValue = 123;
100         Assert.assertEquals(initialValue,engine.eval("123"));
101         Assert.assertEquals(initialValue,engine.eval("0;123"));// multiple statements
102         try {
103             final Long time2 = (Long) engine.eval(
104                     "sys=context.class.forName(\"java.lang.System\");"
105                             + "now=sys.currentTimeMillis();"
106             );
107             Assert.fail("default engine no longer accesses System classes");
108         } catch(ScriptException xscript) {
109             JexlException.Method xjexl = (JexlException.Method) xscript.getCause();
110             Assert.assertEquals("forName", xjexl.getMethod());
111         }
112         engine.put("value", initialValue);
113         Assert.assertEquals(initialValue,engine.get("value"));
114         final Integer newValue = 124;
115         Assert.assertEquals(newValue,engine.eval("old=value;value=value+1"));
116         Assert.assertEquals(initialValue,engine.get("old"));
117         Assert.assertEquals(newValue,engine.get("value"));
118         Assert.assertEquals(engine.getContext(),engine.get(JexlScriptEngine.CONTEXT_KEY));
119         // Check behavior of JEXL object
120         Assert.assertEquals(engine.getContext().getReader(),engine.eval("JEXL.in"));
121         Assert.assertEquals(engine.getContext().getWriter(),engine.eval("JEXL.out"));
122         Assert.assertEquals(engine.getContext().getErrorWriter(),engine.eval("JEXL.err"));
123         Assert.assertEquals(System.class,engine.eval("JEXL.System"));
124     }
125 
126     @Test
127     public void testScriptingInstance0() throws Exception {
128         JexlScriptEngine.setPermissions(JexlPermissions.UNRESTRICTED);
129         final ScriptEngineManager manager = new ScriptEngineManager();
130         final ScriptEngine engine = manager.getEngineByName("jexl3");
131         Long time2 = (Long) engine.eval(
132                 "sys=context.class.forName(\"java.lang.System\");"
133                         + "now=sys.currentTimeMillis();");
134         Assert.assertTrue(time2 <= System.currentTimeMillis());
135     }
136 
137     @Test
138     public void testScriptingPermissions1() throws Exception {
139         JexlBuilder.setDefaultPermissions(JexlPermissions.UNRESTRICTED);
140         JexlScriptEngine.setPermissions(null);
141         final ScriptEngineManager manager = new ScriptEngineManager();
142         final ScriptEngine engine = manager.getEngineByName("jexl3");
143         Long time2 = (Long) engine.eval(
144                 "sys=context.class.forName(\"java.lang.System\");"
145                         + "now=sys.currentTimeMillis();");
146         Assert.assertTrue(time2 <= System.currentTimeMillis());
147     }
148 
149     @Test
150     public void testNulls() throws Exception {
151         final ScriptEngineManager manager = new ScriptEngineManager();
152         Assert.assertNotNull("Manager should not be null", manager);
153         final ScriptEngine engine = manager.getEngineByName("jexl3");
154         Assert.assertNotNull("Engine should not be null (name)", engine);
155         Assert.assertNotNull(engine.getFactory());
156         try {
157             engine.eval((String) null);
158             Assert.fail("Should have caused NPE");
159         } catch (final NullPointerException e) {
160             // NOOP
161         }
162         try {
163             engine.eval((Reader) null);
164             Assert.fail("Should have caused NPE");
165         } catch (final NullPointerException e) {
166             // NOOP
167         }
168         ScriptContext ctxt = null;
169         try {
170             engine.eval((String) null, ctxt);
171             Assert.fail("Should have caused NPE");
172         } catch (final NullPointerException e) {
173             //NOOP
174         }
175         try {
176             engine.eval((Reader) null, ctxt);
177             Assert.fail("Should have caused NPE");
178         } catch (final NullPointerException e) {
179             //NOOP
180         }
181     }
182 
183     @Test
184     public void testScopes() throws Exception {
185         final ScriptEngineManager manager = new ScriptEngineManager();
186         Assert.assertNotNull("Manager should not be null", manager);
187         final ScriptEngine engine = manager.getEngineByName("JEXL");
188         Assert.assertNotNull("Engine should not be null (JEXL)", engine);
189         manager.put("global", 1);
190         engine.put("local", 10);
191         manager.put("both", 7);
192         engine.put("both", 7);
193         engine.eval("local=local+1");
194         engine.eval("global=global+1");
195         engine.eval("both=both+1"); // should update engine value only
196         engine.eval("newvar=42;");
197         Assert.assertEquals(2,manager.get("global"));
198         Assert.assertEquals(11,engine.get("local"));
199         Assert.assertEquals(7,manager.get("both"));
200         Assert.assertEquals(8,engine.get("both"));
201         Assert.assertEquals(42,engine.get("newvar"));
202         Assert.assertNull(manager.get("newvar"));
203     }
204 
205     public static class Errors {
206         public int npe() {
207             throw new NullPointerException("jexl");
208         }
209         public int illegal() {
210             throw new IllegalArgumentException("jexl");
211         }
212     }
213 
214     @Test
215     public void testErrors() throws Exception {
216         final ScriptEngineManager manager = new ScriptEngineManager();
217         final JexlScriptEngine engine = (JexlScriptEngine) manager.getEngineByName("JEXL");
218         ScriptContext ctxt = engine.getContext();
219         engine.put("errors", new Errors());
220         try {
221             engine.eval("errors.npe()");
222         } catch(ScriptException xscript) {
223             Assert.assertTrue(xscript.getCause() instanceof NullPointerException);
224         }
225         try {
226             engine.eval("errors.illegal()", ctxt);
227         } catch(ScriptException xscript) {
228             Assert.assertTrue(xscript.getCause() instanceof IllegalArgumentException);
229         }
230         CompiledScript script0 = engine.compile("errors.npe()");
231         try {
232             script0.eval();
233         } catch(ScriptException xscript) {
234             Assert.assertTrue(xscript.getCause() instanceof NullPointerException);
235         }
236         CompiledScript script1 = engine.compile("errors.illegal()");
237         try {
238             script1.eval(ctxt);
239         } catch(ScriptException xscript) {
240             Assert.assertTrue(xscript.getCause() instanceof IllegalArgumentException);
241         }
242     }
243 
244 
245     @Test
246     public void testCompile() throws Exception {
247         final ScriptEngineManager manager = new ScriptEngineManager();
248         final JexlScriptEngine engine = (JexlScriptEngine) manager.getEngineByName("JEXL");
249         ScriptContext ctxt = engine.getContext();
250         String str = null;
251         String reader = null;
252         try {
253             CompiledScript script0 = engine.compile(str);
254             Assert.fail("should have thrown npe");
255         } catch(NullPointerException npe) {
256             Assert.assertNotNull(npe);
257         }
258         try {
259             CompiledScript script0 = engine.compile(reader);
260             Assert.fail("should have thrown npe");
261         } catch(NullPointerException npe) {
262             Assert.assertNotNull(npe);
263         }
264         try {
265             CompiledScript script0 = engine.compile("3 + 4");
266             Assert.assertEquals(engine, script0.getEngine());
267             Object result = script0.eval();
268             Assert.assertEquals(7, result);
269             result = script0.eval();
270             Assert.assertEquals(7, result);
271         } catch(ScriptException xscript) {
272             Assert.assertTrue(xscript.getCause() instanceof NullPointerException);
273         }
274         try {
275             ctxt.setAttribute("x", 20, ScriptContext.ENGINE_SCOPE);
276             ctxt.setAttribute("y", 22, ScriptContext.ENGINE_SCOPE);
277             CompiledScript script0 = engine.compile("x + y");
278             Object result = script0.eval();
279             Assert.assertEquals(42, result);
280             ctxt.setAttribute("x", -20, ScriptContext.ENGINE_SCOPE);
281             ctxt.setAttribute("y", -22, ScriptContext.ENGINE_SCOPE);
282             result = script0.eval();
283             Assert.assertEquals(-42, result);
284         } catch(ScriptException xscript) {
285             Assert.assertTrue(xscript.getCause() instanceof NullPointerException);
286         }
287 
288     }
289     @Test
290     public void testDottedNames() throws Exception {
291         final ScriptEngineManager manager = new ScriptEngineManager();
292         Assert.assertNotNull("Manager should not be null", manager);
293         final ScriptEngine engine = manager.getEngineByName("JEXL");
294         Assert.assertNotNull("Engine should not be null (JEXL)", engine);
295         engine.eval("this.is.a.test=null");
296         Assert.assertNull(engine.get("this.is.a.test"));
297         Assert.assertEquals(Boolean.TRUE, engine.eval("empty(this.is.a.test)"));
298         final Object mymap = engine.eval("testmap={ 'key1' : 'value1', 'key2' : 'value2' }");
299         Assert.assertTrue(mymap instanceof Map<?, ?>);
300         Assert.assertEquals(2,((Map<?, ?>)mymap).size());
301     }
302 
303     @Test
304     public void testDirectNew() throws Exception {
305         final ScriptEngine engine = new JexlScriptEngine();
306         final Integer initialValue = 123;
307         Assert.assertEquals(initialValue,engine.eval("123"));
308     }
309 }