NashornScriptEngineFactory.java revision 1590:1916a2c680d8
126497Sache/* 226497Sache * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 326497Sache * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 426497Sache * 526497Sache * This code is free software; you can redistribute it and/or modify it 626497Sache * under the terms of the GNU General Public License version 2 only, as 726497Sache * published by the Free Software Foundation. Oracle designates this 826497Sache * particular file as subject to the "Classpath" exception as provided 926497Sache * by Oracle in the LICENSE file that accompanied this code. 1026497Sache * 1126497Sache * This code is distributed in the hope that it will be useful, but WITHOUT 1226497Sache * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1326497Sache * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1426497Sache * version 2 for more details (a copy is included in the LICENSE file that 1526497Sache * accompanied this code). 1626497Sache * 1726497Sache * You should have received a copy of the GNU General Public License version 1826497Sache * 2 along with this work; if not, write to the Free Software Foundation, 1926497Sache * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2026497Sache * 2126497Sache * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2226497Sache * or visit www.oracle.com if you need additional information or have any 2326497Sache * questions. 2426497Sache */ 2526497Sache 2626497Sachepackage jdk.nashorn.api.scripting; 2726497Sache 2826497Sacheimport java.util.Arrays; 2926497Sacheimport java.util.Collections; 3026497Sacheimport java.util.List; 3126497Sacheimport java.util.Objects; 3226497Sacheimport javax.script.ScriptEngine; 3326497Sacheimport javax.script.ScriptEngineFactory; 3426497Sacheimport jdk.nashorn.internal.runtime.Context; 3526497Sacheimport jdk.nashorn.internal.runtime.Version; 3626497Sache 3726497Sache/** 3826497Sache * JSR-223 compliant script engine factory for Nashorn. The engine answers for: 3926497Sache * <ul> 4026497Sache * <li>names {@code "nashorn"}, {@code "Nashorn"}, {@code "js"}, {@code "JS"}, {@code "JavaScript"}, 4126497Sache * {@code "javascript"}, {@code "ECMAScript"}, and {@code "ecmascript"};</li> 4226497Sache * <li>MIME types {@code "application/javascript"}, {@code "application/ecmascript"}, {@code "text/javascript"}, and 4326497Sache * {@code "text/ecmascript"};</li> 4426497Sache * <li>as well as for the extension {@code "js"}.</li> 4526497Sache * </ul> 4626497Sache * Programs executing in engines created using {@link #getScriptEngine(String[])} will have the passed arguments 4726497Sache * accessible as a global variable named {@code "arguments"}. 4826497Sache * 4926497Sache * @since 1.8u40 5026497Sache */ 5126497Sachepublic final class NashornScriptEngineFactory implements ScriptEngineFactory { 5226497Sache @Override 5326497Sache public String getEngineName() { 5426497Sache return (String) getParameter(ScriptEngine.ENGINE); 5526497Sache } 5626497Sache 5726497Sache @Override 5826497Sache public String getEngineVersion() { 5926497Sache return (String) getParameter(ScriptEngine.ENGINE_VERSION); 6026497Sache } 6126497Sache 6226497Sache @Override 6326497Sache public List<String> getExtensions() { 6426497Sache return Collections.unmodifiableList(extensions); 6526497Sache } 6626497Sache 6726497Sache @Override 6826497Sache public String getLanguageName() { 6926497Sache return (String) getParameter(ScriptEngine.LANGUAGE); 7026497Sache } 7126497Sache 7226497Sache @Override 7326497Sache public String getLanguageVersion() { 7426497Sache return (String) getParameter(ScriptEngine.LANGUAGE_VERSION); 7526497Sache } 7626497Sache 7726497Sache @Override 7826497Sache public String getMethodCallSyntax(final String obj, final String method, final String... args) { 7926497Sache final StringBuilder sb = new StringBuilder().append(obj).append('.').append(method).append('('); 8026497Sache final int len = args.length; 8126497Sache 8226497Sache if (len > 0) { 8326497Sache sb.append(args[0]); 8426497Sache } 8526497Sache for (int i = 1; i < len; i++) { 8626497Sache sb.append(',').append(args[i]); 8726497Sache } 8826497Sache sb.append(')'); 8926497Sache 9026497Sache return sb.toString(); 9126497Sache } 9226497Sache 9326497Sache @Override 9426497Sache public List<String> getMimeTypes() { 9526497Sache return Collections.unmodifiableList(mimeTypes); 9626497Sache } 9726497Sache 9826497Sache @Override 9926497Sache public List<String> getNames() { 10026497Sache return Collections.unmodifiableList(names); 10126497Sache } 10226497Sache 10326497Sache @Override 10426497Sache public String getOutputStatement(final String toDisplay) { 10526497Sache return "print(" + toDisplay + ")"; 10626497Sache } 10726497Sache 10826497Sache @Override 10926497Sache public Object getParameter(final String key) { 11026497Sache switch (key) { 11126497Sache case ScriptEngine.NAME: 11226497Sache return "javascript"; 11326497Sache case ScriptEngine.ENGINE: 11426497Sache return "Oracle Nashorn"; 11526497Sache case ScriptEngine.ENGINE_VERSION: 11626497Sache return Version.version(); 11726497Sache case ScriptEngine.LANGUAGE: 11826497Sache return "ECMAScript"; 11926497Sache case ScriptEngine.LANGUAGE_VERSION: 12026497Sache return "ECMA - 262 Edition 5.1"; 12126497Sache case "THREADING": 12226497Sache // The engine implementation is not thread-safe. Can't be 12326497Sache // used to execute scripts concurrently on multiple threads. 12426497Sache return null; 12526497Sache default: 12626497Sache return null; 12726497Sache } 12826497Sache } 12926497Sache 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