    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" <br/>
    034     * Extension: "jexl"
    035     * </p>
    036     * <p>
    037     * See
    038     * <a href="http://java.sun.com/javase/6/docs/api/javax/script/package-summary.html">Java Scripting API</a>
    039     * Javadoc.
    040     * @since 2.0
    041     */
    042    public class JexlScriptEngineFactory implements ScriptEngineFactory {
    043
    044        /** {@inheritDoc} */
    045        public String getEngineName() {
    046            return "JEXL Engine";
    047        }
    048
    049        /** {@inheritDoc} */
    050        public String getEngineVersion() {
    051            return "1.0"; // ensure this is updated if function changes are made to this class
    052        }
    053
    054        /** {@inheritDoc} */
    055        public String getLanguageName() {
    056            return "JEXL";
    057        }
    058
    059        /** {@inheritDoc} */
    060        public String getLanguageVersion() {
    061            return "2.0"; // TODO this should be derived from the actual version
    062        }
    063
    064        /** {@inheritDoc} */
    065        public String getMethodCallSyntax(String obj, String m, String... args) {
    066            StringBuilder sb = new StringBuilder();
    067            sb.append(obj);
    068            sb.append('.');
    069            sb.append(m);
    070            sb.append('(');
    071            boolean needComma = false;
    072            for(String arg : args){
    073                if (needComma) {
    074                    sb.append(',');
    075                }
    076                sb.append(arg);
    077                needComma = true;
    078            }
    079            sb.append(')');
    080            return sb.toString();
    081        }
    082
    083        /** {@inheritDoc} */
    084        public List<String> getExtensions() {
    085            return Collections.unmodifiableList(Arrays.asList("jexl"));
    086        }
    087
    088        /** {@inheritDoc} */
    089        public List<String> getMimeTypes() {
    090            return Collections.unmodifiableList(Arrays.asList("application/x-jexl"));
    091        }
    092
    093        /** {@inheritDoc} */
    094        public List<String> getNames() {
    095            return Collections.unmodifiableList(Arrays.asList("JEXL", "Jexl", "jexl"));
    096        }
    097
    098        /** {@inheritDoc} */
    099        public String getOutputStatement(String toDisplay) {
    100            if (toDisplay == null) {
    101                return "JEXL.out.print(null)";
    102            } else {
    103                return "JEXL.out.print("+StringParser.escapeString(toDisplay)+")";
    104            }
    105        }
    106
    107        /** {@inheritDoc} */
    108        public Object getParameter(String key) {
    109            if (key.equals(ScriptEngine.ENGINE)) {
    110                return getEngineName();
    111            } else if (key.equals(ScriptEngine.ENGINE_VERSION)) {
    112                return getEngineVersion();
    113            } else if (key.equals(ScriptEngine.NAME)) {
    114                return getNames();
    115            } else if (key.equals(ScriptEngine.LANGUAGE)) {
    116                return getLanguageName();
    117            } else if(key.equals(ScriptEngine.LANGUAGE_VERSION)) {
    118                return getLanguageVersion();
    119            } else if (key.equals("THREADING")) {
    120                /*
    121                 * To implement multithreading, the scripting engine context (inherited from AbstractScriptEngine)
    122                 * would need to be made thread-safe; so would the setContext/getContext methods.
    123                 * It is easier to share the underlying Uberspect and JEXL engine instance, especially
    124                 * with an expression cache.
    125                 */
    126                return null;
    127            }
    128            return null;
    129        }
    130
    131        /** {@inheritDoc} */
    132        public String getProgram(String... statements) {
    133            StringBuilder sb = new StringBuilder();
    134            for(String statement : statements){
    135                sb.append(JexlEngine.cleanExpression(statement));
    136                if (!statement.endsWith(";")){
    137                    sb.append(';');
    138                }
    139            }
    140            return sb.toString();
    141        }
    142
    143        /** {@inheritDoc} */
    144        public ScriptEngine getScriptEngine() {
    145            JexlScriptEngine engine = new JexlScriptEngine(this);
    146            return engine;
    147        }
    148
    149    }