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