NashornScriptEngineFactory.java revision 1590:1916a2c680d8
14Srgrimes/* 2247047Skib * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 34Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4247047Skib * 54Srgrimes * This code is free software; you can redistribute it and/or modify it 6247047Skib * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.api.scripting; 27 28import java.util.Arrays; 29import java.util.Collections; 30import java.util.List; 31import java.util.Objects; 32import javax.script.ScriptEngine; 33import javax.script.ScriptEngineFactory; 34import jdk.nashorn.internal.runtime.Context; 35import jdk.nashorn.internal.runtime.Version; 36 37/** 38 * JSR-223 compliant script engine factory for Nashorn. The engine answers for: 39 * <ul> 40 * <li>names {@code "nashorn"}, {@code "Nashorn"}, {@code "js"}, {@code "JS"}, {@code "JavaScript"}, 41 * {@code "javascript"}, {@code "ECMAScript"}, and {@code "ecmascript"};</li> 42 * <li>MIME types {@code "application/javascript"}, {@code "application/ecmascript"}, {@code "text/javascript"}, and 43 * {@code "text/ecmascript"};</li> 44 * <li>as well as for the extension {@code "js"}.</li> 45 * </ul> 46 * Programs executing in engines created using {@link #getScriptEngine(String[])} will have the passed arguments 47 * accessible as a global variable named {@code "arguments"}. 48 * 49 * @since 1.8u40 50 */ 51public final class NashornScriptEngineFactory implements ScriptEngineFactory { 52 @Override 53 public String getEngineName() { 54 return (String) getParameter(ScriptEngine.ENGINE); 55 } 56 57 @Override 58 public String getEngineVersion() { 59 return (String) getParameter(ScriptEngine.ENGINE_VERSION); 60 } 61 62 @Override 63 public List<String> getExtensions() { 64 return Collections.unmodifiableList(extensions); 65 } 66 67 @Override 68 public String getLanguageName() { 69 return (String) getParameter(ScriptEngine.LANGUAGE); 70 } 71 72 @Override 73 public String getLanguageVersion() { 74 return (String) getParameter(ScriptEngine.LANGUAGE_VERSION); 75 } 76 77 @Override 78 public String getMethodCallSyntax(final String obj, final String method, final String... args) { 79 final StringBuilder sb = new StringBuilder().append(obj).append('.').append(method).append('('); 80 final int len = args.length; 81 82 if (len > 0) { 83 sb.append(args[0]); 84 } 85 for (int i = 1; i < len; i++) { 86 sb.append(',').append(args[i]); 87 } 88 sb.append(')'); 89 90 return sb.toString(); 91 } 92 93 @Override 94 public List<String> getMimeTypes() { 95 return Collections.unmodifiableList(mimeTypes); 96 } 97 98 @Override 99 public List<String> getNames() { 100 return Collections.unmodifiableList(names); 101 } 102 103 @Override 104 public String getOutputStatement(final String toDisplay) { 105 return "print(" + toDisplay + ")"; 106 } 107 108 @Override 109 public Object getParameter(final String key) { 110 switch (key) { 111 case ScriptEngine.NAME: 112 return "javascript"; 113 case ScriptEngine.ENGINE: 114 return "Oracle Nashorn"; 115 case ScriptEngine.ENGINE_VERSION: 116 return Version.version(); 117 case ScriptEngine.LANGUAGE: 118 return "ECMAScript"; 119 case ScriptEngine.LANGUAGE_VERSION: 120 return "ECMA - 262 Edition 5.1"; 121 case "THREADING": 122 // The engine implementation is not thread-safe. Can't be 123 // used to execute scripts concurrently on multiple threads. 124 return null; 125 default: 126 return null; 127 } 128 } 129 130 @Override 131 public String getProgram(final String... statements) { 132 final StringBuilder sb = new StringBuilder(); 133 134 for (final String statement : statements) { 135 sb.append(statement).append(';'); 136 } 137 138 return sb.toString(); 139 } 140 141 // default options passed to Nashorn script engine 142 private static final String[] DEFAULT_OPTIONS = new String[] { "-doe" }; 143 144 @Override 145 public ScriptEngine getScriptEngine() { 146 try { 147 return new NashornScriptEngine(this, DEFAULT_OPTIONS, getAppClassLoader(), null); 148 } catch (final RuntimeException e) { 149 if (Context.DEBUG) { 150 e.printStackTrace(); 151 } 152 throw e; 153 } 154 } 155 156 /** 157 * Create a new Script engine initialized by given class loader. 158 * 159 * @param appLoader class loader to be used as script "app" class loader. 160 * @return newly created script engine. 161 * @throws SecurityException 162 * if the security manager's {@code checkPermission} 163 * denies {@code RuntimePermission("nashorn.setConfig")} 164 */ 165 public ScriptEngine getScriptEngine(final ClassLoader appLoader) { 166 return newEngine(DEFAULT_OPTIONS, appLoader, null); 167 } 168 169 /** 170 * Create a new Script engine initialized by given class filter. 171 * 172 * @param classFilter class filter to use. 173 * @return newly created script engine. 174 * @throws NullPointerException if {@code classFilter} is {@code null} 175 * @throws SecurityException 176 * if the security manager's {@code checkPermission} 177 * denies {@code RuntimePermission("nashorn.setConfig")} 178 */ 179 public ScriptEngine getScriptEngine(final ClassFilter classFilter) { 180 return newEngine(DEFAULT_OPTIONS, getAppClassLoader(), Objects.requireNonNull(classFilter)); 181 } 182 183 /** 184 * Create a new Script engine initialized by given arguments. 185 * 186 * @param args arguments array passed to script engine. 187 * @return newly created script engine. 188 * @throws NullPointerException if {@code args} is {@code null} 189 * @throws SecurityException 190 * if the security manager's {@code checkPermission} 191 * denies {@code RuntimePermission("nashorn.setConfig")} 192 */ 193 public ScriptEngine getScriptEngine(final String... args) { 194 return newEngine(Objects.requireNonNull(args), getAppClassLoader(), null); 195 } 196 197 /** 198 * Create a new Script engine initialized by given arguments. 199 * 200 * @param args arguments array passed to script engine. 201 * @param appLoader class loader to be used as script "app" class loader. 202 * @return newly created script engine. 203 * @throws NullPointerException if {@code args} is {@code null} 204 * @throws SecurityException 205 * if the security manager's {@code checkPermission} 206 * denies {@code RuntimePermission("nashorn.setConfig")} 207 */ 208 public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) { 209 return newEngine(Objects.requireNonNull(args), appLoader, null); 210 } 211 212 /** 213 * Create a new Script engine initialized by given arguments. 214 * 215 * @param args arguments array passed to script engine. 216 * @param appLoader class loader to be used as script "app" class loader. 217 * @param classFilter class filter to use. 218 * @return newly created script engine. 219 * @throws NullPointerException if {@code args} or {@code classFilter} is {@code null} 220 * @throws SecurityException 221 * if the security manager's {@code checkPermission} 222 * denies {@code RuntimePermission("nashorn.setConfig")} 223 */ 224 public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) { 225 return newEngine(Objects.requireNonNull(args), appLoader, Objects.requireNonNull(classFilter)); 226 } 227 228 private ScriptEngine newEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) { 229 checkConfigPermission(); 230 try { 231 return new NashornScriptEngine(this, args, appLoader, classFilter); 232 } catch (final RuntimeException e) { 233 if (Context.DEBUG) { 234 e.printStackTrace(); 235 } 236 throw e; 237 } 238 } 239 240 // -- Internals only below this point 241 242 private static void checkConfigPermission() { 243 final SecurityManager sm = System.getSecurityManager(); 244 if (sm != null) { 245 sm.checkPermission(new RuntimePermission(Context.NASHORN_SET_CONFIG)); 246 } 247 } 248 249 private static final List<String> names; 250 private static final List<String> mimeTypes; 251 private static final List<String> extensions; 252 253 static { 254 names = immutableList( 255 "nashorn", "Nashorn", 256 "js", "JS", 257 "JavaScript", "javascript", 258 "ECMAScript", "ecmascript" 259 ); 260 261 mimeTypes = immutableList( 262 "application/javascript", 263 "application/ecmascript", 264 "text/javascript", 265 "text/ecmascript" 266 ); 267 268 extensions = immutableList("js"); 269 } 270 271 private static List<String> immutableList(final String... elements) { 272 return Collections.unmodifiableList(Arrays.asList(elements)); 273 } 274 275 private static ClassLoader getAppClassLoader() { 276 // Revisit: script engine implementation needs the capability to 277 // find the class loader of the context in which the script engine 278 // is running so that classes will be found and loaded properly 279 final ClassLoader ccl = Thread.currentThread().getContextClassLoader(); 280 return (ccl == null)? NashornScriptEngineFactory.class.getClassLoader() : ccl; 281 } 282} 283