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