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.util.Arrays;
21  import java.util.Collections;
22  import java.util.List;
23  
24  import javax.script.ScriptEngine;
25  import javax.script.ScriptEngineFactory;
26  
27  import org.apache.commons.jexl3.parser.StringParser;
28  
29  /**
30   * Implements the JEXL ScriptEngineFactory for JSF-223.
31   * <p>
32   * Supports the following:<br>
33   * Language short names: "JEXL", "Jexl", "jexl", "JEXL2", "Jexl2", "jexl2", "JEXL3", "Jexl3", "jexl3" <br>
34   * File Extensions: ".jexl", ".jexl2", ".jexl3"<br>
35   * "jexl3" etc. were added for engineVersion="3.0".
36   * </p>
37   * <p>
38   * See
39   * <a href="https://java.sun.com/javase/6/docs/api/javax/script/package-summary.html">Java Scripting API</a>
40   * Javadoc.
41   *
42   * @since 2.0
43   */
44  public class JexlScriptEngineFactory implements ScriptEngineFactory {
45  
46      @Override
47      public String getEngineName() {
48          return "JEXL Engine";
49      }
50  
51      @Override
52      public String getEngineVersion() {
53          return "3.4"; // ensure this is updated if function changes are made to this class
54      }
55  
56      @Override
57      public List<String> getExtensions() {
58          return Collections.unmodifiableList(Arrays.asList("jexl", "jexl2", "jexl3"));
59      }
60  
61      @Override
62      public String getLanguageName() {
63          return "JEXL";
64      }
65  
66      @Override
67      public String getLanguageVersion() {
68          return "3.4"; // this should be derived from the actual version
69      }
70  
71      @Override
72      public String getMethodCallSyntax(final String obj, final String m, final String... args) {
73          final StringBuilder sb = new StringBuilder();
74          sb.append(obj);
75          sb.append('.');
76          sb.append(m);
77          sb.append('(');
78          boolean needComma = false;
79          for(final String arg : args){
80              if (needComma) {
81                  sb.append(',');
82              }
83              sb.append(arg);
84              needComma = true;
85          }
86          sb.append(')');
87          return sb.toString();
88      }
89  
90      @Override
91      public List<String> getMimeTypes() {
92          return Collections.unmodifiableList(Arrays.asList("application/x-jexl",
93                                                            "application/x-jexl2",
94                                                            "application/x-jexl3"));
95      }
96  
97      @Override
98      public List<String> getNames() {
99          return Collections.unmodifiableList(Arrays.asList("JEXL", "Jexl", "jexl",
100                                                           "JEXL2", "Jexl2", "jexl2",
101                                                           "JEXL3", "Jexl3", "jexl3"));
102     }
103 
104     @Override
105     public String getOutputStatement(final String toDisplay) {
106         if (toDisplay == null) {
107             return "JEXL.out.print(null)";
108         }
109         return "JEXL.out.print("+StringParser.escapeString(toDisplay, '\'')+")";
110     }
111 
112     @Override
113     public Object getParameter(final String key) {
114         switch (key) {
115             case ScriptEngine.ENGINE:
116                 return getEngineName();
117             case ScriptEngine.ENGINE_VERSION:
118                 return getEngineVersion();
119             case ScriptEngine.NAME:
120                 return getNames();
121             case ScriptEngine.LANGUAGE:
122                 return getLanguageName();
123             case ScriptEngine.LANGUAGE_VERSION:
124                 return getLanguageVersion();
125             case "THREADING":
126                 /*
127                  * To implement multithreading, the scripting engine context (inherited from AbstractScriptEngine)
128                  * would need to be made thread-safe; so would the setContext/getContext methods.
129                  * It is easier to share the underlying Uberspect and JEXL engine instance, especially
130                  * with an expression cache.
131                  */
132             default:
133                 return null;
134         }
135     }
136 
137     @Override
138     public String getProgram(final String... statements) {
139         final StringBuilder sb = new StringBuilder();
140         for(final String statement : statements){
141             sb.append(statement.trim());
142             if (!statement.endsWith(";")){
143                 sb.append(';');
144             }
145         }
146         return sb.toString();
147     }
148 
149     @Override
150     public ScriptEngine getScriptEngine() {
151         return new JexlScriptEngine(this);
152     }
153 
154 }