001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.jexl2.scripting;
019
020 import java.util.Arrays;
021 import java.util.Collections;
022 import java.util.List;
023
024 import javax.script.ScriptEngine;
025 import javax.script.ScriptEngineFactory;
026 import org.apache.commons.jexl2.JexlEngine;
027 import org.apache.commons.jexl2.parser.StringParser;
028
029 /**
030 * Implements the Jexl ScriptEngineFactory for JSF-223.
031 * <p>
032 * Supports the following:<br.>
033 * Language short names: "JEXL", "Jexl", "jexl", "JEXL2", "Jexl2", "jexl2" <br/>
034 * File Extensions: ".jexl", ".jexl2"<br/>
035 * "jexl2" etc. were added for engineVersion="2.0".
036 * </p>
037 * <p>
038 * See
039 * <a href="http://java.sun.com/javase/6/docs/api/javax/script/package-summary.html">Java Scripting API</a>
040 * Javadoc.
041 * @since 2.0
042 */
043 public class JexlScriptEngineFactory implements ScriptEngineFactory {
044
045 /** {@inheritDoc} */
046 public String getEngineName() {
047 return "JEXL Engine";
048 }
049
050 /** {@inheritDoc} */
051 public String getEngineVersion() {
052 return "2.0"; // ensure this is updated if function changes are made to this class
053 }
054
055 /** {@inheritDoc} */
056 public String getLanguageName() {
057 return "JEXL";
058 }
059
060 /** {@inheritDoc} */
061 public String getLanguageVersion() {
062 return "2.0"; // TODO this should be derived from the actual version
063 }
064
065 /** {@inheritDoc} */
066 public String getMethodCallSyntax(String obj, String m, String[] args) {
067 StringBuilder sb = new StringBuilder();
068 sb.append(obj);
069 sb.append('.');
070 sb.append(m);
071 sb.append('(');
072 boolean needComma = false;
073 for(String arg : args){
074 if (needComma) {
075 sb.append(',');
076 }
077 sb.append(arg);
078 needComma = true;
079 }
080 sb.append(')');
081 return sb.toString();
082 }
083
084 /** {@inheritDoc} */
085 public List<String> getExtensions() {
086 return Collections.unmodifiableList(Arrays.asList("jexl", "jexl2"));
087 }
088
089 /** {@inheritDoc} */
090 public List<String> getMimeTypes() {
091 return Collections.unmodifiableList(Arrays.asList("application/x-jexl", "application/x-jexl2"));
092 }
093
094 /** {@inheritDoc} */
095 public List<String> getNames() {
096 return Collections.unmodifiableList(Arrays.asList("JEXL", "Jexl", "jexl", "JEXL2", "Jexl2", "jexl2"));
097 }
098
099 /** {@inheritDoc} */
100 public String getOutputStatement(String toDisplay) {
101 if (toDisplay == null) {
102 return "JEXL.out.print(null)";
103 } else {
104 return "JEXL.out.print("+StringParser.escapeString(toDisplay, '\'')+")";
105 }
106 }
107
108 /** {@inheritDoc} */
109 public Object getParameter(String key) {
110 if (key.equals(ScriptEngine.ENGINE)) {
111 return getEngineName();
112 } else if (key.equals(ScriptEngine.ENGINE_VERSION)) {
113 return getEngineVersion();
114 } else if (key.equals(ScriptEngine.NAME)) {
115 return getNames();
116 } else if (key.equals(ScriptEngine.LANGUAGE)) {
117 return getLanguageName();
118 } else if(key.equals(ScriptEngine.LANGUAGE_VERSION)) {
119 return getLanguageVersion();
120 } else if (key.equals("THREADING")) {
121 /*
122 * To implement multithreading, the scripting engine context (inherited from AbstractScriptEngine)
123 * would need to be made thread-safe; so would the setContext/getContext methods.
124 * It is easier to share the underlying Uberspect and JEXL engine instance, especially
125 * with an expression cache.
126 */
127 return null;
128 }
129 return null;
130 }
131
132 /** {@inheritDoc} */
133 public String getProgram(String[] statements) {
134 StringBuilder sb = new StringBuilder();
135 for(String statement : statements){
136 sb.append(JexlEngine.cleanExpression(statement));
137 if (!statement.endsWith(";")){
138 sb.append(';');
139 }
140 }
141 return sb.toString();
142 }
143
144 /** {@inheritDoc} */
145 public ScriptEngine getScriptEngine() {
146 JexlScriptEngine engine = new JexlScriptEngine(this);
147 return engine;
148 }
149
150 }