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  package org.example;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.concurrent.atomic.AtomicInteger;
24  
25  import org.apache.commons.jexl3.JexlBuilder;
26  import org.apache.commons.jexl3.JexlContext;
27  import org.apache.commons.jexl3.JexlEngine;
28  import org.apache.commons.jexl3.JexlExpression;
29  import org.apache.commons.jexl3.JexlScript;
30  import org.apache.commons.jexl3.MapContext;
31  import org.apache.commons.jexl3.internal.Engine;
32  import org.apache.commons.jexl3.internal.TemplateInterpreter;
33  import org.apache.commons.jexl3.introspection.JexlPermissions;
34  import org.apache.commons.jexl3.parser.JexlNode;
35  import org.junit.jupiter.api.Test;
36  
37  public class SomeTest {
38  
39    /**
40     * Engine creating dedicated template interpreter.
41     */
42    public static class Engine406 extends Engine {
43      public Engine406(final JexlBuilder conf) {
44        super(conf);
45      }
46      @Override public TemplateInterpreter createTemplateInterpreter(final TemplateInterpreter.Arguments args) {
47        return new TemplateInterpreter406(args);
48      }
49    }
50  
51    public static class MyMath {
52      public double cos(final double x) {
53        return Math.cos(x);
54      }
55    }
56  
57    public static class TemplateInterpreter406 extends TemplateInterpreter {
58      protected TemplateInterpreter406(final Arguments args) {
59        super(args);
60      }
61      @Override
62      public Object interpret(final JexlNode node) {
63        CALL406.incrementAndGet();
64        return super.interpret(node);
65      }
66    }
67  
68    /** Counting the number of node interpretation calls. */
69    static AtomicInteger CALL406 = new AtomicInteger();
70  
71    @Test
72    public void test406b() {
73      final JexlEngine jexl = new JexlBuilder() {
74        @Override
75        public JexlEngine create() {
76          return new Engine406(this);
77        }
78      }.cache(64).strict(true).safe(false).create();
79      final String src = "`Call ${x}`";
80      final JexlScript script = jexl.createScript(src, "x");
81      Object result = script.execute(null, 406);
82      assertEquals("Call 406", result);
83      assertEquals(1, CALL406.get());
84      result = script.execute(null, 42);
85      assertEquals("Call 42", result);
86      assertEquals(2, CALL406.get());
87    }
88  
89    /**
90     * User namespace needs to be allowed through permissions.
91     */
92    @Test
93    public void testCustomFunctionPermissions() {
94        final Map<String, Object> funcs = new HashMap<>();
95        funcs.put("math", new MyMath());
96        final JexlPermissions permissions = JexlPermissions.parse("org.example.*");
97        final JexlEngine jexl = new JexlBuilder().permissions(permissions).namespaces(funcs).create();
98        final JexlContext jc = new MapContext();
99        jc.set("pi", Math.PI);
100       final JexlExpression e = jexl.createExpression("math:cos(pi)");
101       final Number result = (Number) e.evaluate(jc);
102       assertEquals(-1, result.intValue());
103   }
104 }