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 * https://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 018package org.apache.commons.jexl3.scripting; 019 020import java.util.Arrays; 021import java.util.Collections; 022import java.util.List; 023 024import javax.script.ScriptEngine; 025import javax.script.ScriptEngineFactory; 026 027import org.apache.commons.jexl3.parser.StringParser; 028 029/** 030 * Implements the JEXL ScriptEngineFactory for JSF-223. 031 * <p> 032 * Supports the following:<br> 033 * </p> 034 * <ul> 035 * <li>Language short names: "JEXL", "Jexl", "jexl", "JEXL2", "Jexl2", "jexl2", "JEXL3", "Jexl3", "jexl3"</li> 036 * <li>File Extensions: ".jexl", ".jexl2", ".jexl3"</li> 037 * <li>"jexl3" etc. were added for engineVersion="3.0"</li> 038 * </ul> 039 * <p> 040 * See 041 * <a href="https://java.sun.com/javase/6/docs/api/javax/script/package-summary.html">Java Scripting API</a> 042 * Javadoc. 043 * 044 * @since 2.0 045 */ 046public class JexlScriptEngineFactory implements ScriptEngineFactory { 047 048 /** Default constructor */ 049 public JexlScriptEngineFactory() {} // Keep Javadoc happy 050 051 @Override 052 public String getEngineName() { 053 return "JEXL Engine"; 054 } 055 056 @Override 057 public String getEngineVersion() { 058 return "3.6"; // ensure this is updated if function changes are made to this class 059 } 060 061 @Override 062 public List<String> getExtensions() { 063 return Collections.unmodifiableList(Arrays.asList("jexl", "jexl2", "jexl3")); 064 } 065 066 @Override 067 public String getLanguageName() { 068 return "JEXL"; 069 } 070 071 @Override 072 public String getLanguageVersion() { 073 return "3.6"; // this should be derived from the actual version 074 } 075 076 @Override 077 public String getMethodCallSyntax(final String obj, final String m, final String... args) { 078 final StringBuilder sb = new StringBuilder(); 079 sb.append(obj); 080 sb.append('.'); 081 sb.append(m); 082 sb.append('('); 083 boolean needComma = false; 084 for(final String arg : args){ 085 if (needComma) { 086 sb.append(','); 087 } 088 sb.append(arg); 089 needComma = true; 090 } 091 sb.append(')'); 092 return sb.toString(); 093 } 094 095 @Override 096 public List<String> getMimeTypes() { 097 return Collections.unmodifiableList(Arrays.asList("application/x-jexl", 098 "application/x-jexl2", 099 "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}