    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    }