src/jdk/nashorn/api/scripting/NashornScriptEngine.java

Fri, 09 Aug 2013 20:48:44 +0530

author
sundar
date
Fri, 09 Aug 2013 20:48:44 +0530
changeset 492
47e2b609fe31
parent 472
f22ca0f9b6ee
child 514
54f60d91024c
permissions
-rw-r--r--

8022707: Revisit all doPrivileged blocks
Reviewed-by: jlaskey, hannesw

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.api.scripting;
jlaskey@3 27
jlaskey@3 28 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
jlaskey@3 29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
jlaskey@3 30
jlaskey@3 31 import java.io.IOException;
jlaskey@3 32 import java.io.InputStream;
jlaskey@3 33 import java.io.InputStreamReader;
jlaskey@3 34 import java.io.Reader;
sundar@142 35 import java.lang.reflect.Method;
sundar@427 36 import java.lang.reflect.Modifier;
jlaskey@3 37 import java.net.URL;
sundar@353 38 import java.nio.charset.Charset;
sundar@492 39 import java.security.AccessControlContext;
jlaskey@3 40 import java.security.AccessController;
sundar@492 41 import java.security.Permissions;
jlaskey@3 42 import java.security.PrivilegedAction;
jlaskey@3 43 import java.security.PrivilegedActionException;
jlaskey@3 44 import java.security.PrivilegedExceptionAction;
sundar@492 45 import java.security.ProtectionDomain;
sundar@472 46 import java.text.MessageFormat;
sundar@472 47 import java.util.Locale;
sundar@472 48 import java.util.ResourceBundle;
jlaskey@3 49 import javax.script.AbstractScriptEngine;
jlaskey@3 50 import javax.script.Bindings;
jlaskey@3 51 import javax.script.Compilable;
jlaskey@3 52 import javax.script.CompiledScript;
jlaskey@3 53 import javax.script.Invocable;
jlaskey@3 54 import javax.script.ScriptContext;
jlaskey@3 55 import javax.script.ScriptEngine;
jlaskey@3 56 import javax.script.ScriptEngineFactory;
jlaskey@3 57 import javax.script.ScriptException;
jlaskey@3 58 import jdk.nashorn.internal.runtime.Context;
jlaskey@3 59 import jdk.nashorn.internal.runtime.ErrorManager;
jlaskey@3 60 import jdk.nashorn.internal.runtime.GlobalObject;
jlaskey@3 61 import jdk.nashorn.internal.runtime.Property;
jlaskey@3 62 import jdk.nashorn.internal.runtime.ScriptFunction;
jlaskey@3 63 import jdk.nashorn.internal.runtime.ScriptObject;
jlaskey@3 64 import jdk.nashorn.internal.runtime.ScriptRuntime;
jlaskey@3 65 import jdk.nashorn.internal.runtime.Source;
jlaskey@3 66 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
jlaskey@3 67 import jdk.nashorn.internal.runtime.options.Options;
jlaskey@3 68
jlaskey@3 69 /**
jlaskey@3 70 * JSR-223 compliant script engine for Nashorn. Instances are not created directly, but rather returned through
jlaskey@3 71 * {@link NashornScriptEngineFactory#getScriptEngine()}. Note that this engine implements the {@link Compilable} and
jlaskey@3 72 * {@link Invocable} interfaces, allowing for efficient precompilation and repeated execution of scripts.
jlaskey@3 73 * @see NashornScriptEngineFactory
jlaskey@3 74 */
jlaskey@3 75
jlaskey@3 76 public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable {
sundar@492 77 private static AccessControlContext createPermAccCtxt(final String permName) {
sundar@492 78 final Permissions perms = new Permissions();
sundar@492 79 perms.add(new RuntimePermission(permName));
sundar@492 80 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
sundar@492 81 }
sundar@492 82
sundar@492 83 private static final AccessControlContext CREATE_CONTEXT_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_CONTEXT);
sundar@492 84 private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_GLOBAL);
jlaskey@3 85
jlaskey@3 86 private final ScriptEngineFactory factory;
jlaskey@3 87 private final Context nashornContext;
jlaskey@3 88 private final ScriptObject global;
sundar@377 89 // initialized bit late to be made 'final'. Property object for "context"
sundar@377 90 // property of global object
sundar@377 91 private Property contextProperty;
jlaskey@3 92
jlaskey@3 93 // default options passed to Nashorn Options object
sundar@351 94 private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-doe" };
jlaskey@3 95
sundar@472 96 private static final String MESSAGES_RESOURCE = "jdk.nashorn.api.scripting.resources.Messages";
sundar@472 97
sundar@472 98 private static final ResourceBundle MESSAGES_BUNDLE;
sundar@472 99 static {
sundar@492 100 MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault());
sundar@472 101 }
sundar@472 102
sundar@472 103 private static String getMessage(final String msgId, final String... args) {
sundar@472 104 try {
sundar@472 105 return new MessageFormat(MESSAGES_BUNDLE.getString(msgId)).format(args);
sundar@472 106 } catch (final java.util.MissingResourceException e) {
sundar@472 107 throw new RuntimeException("no message resource found for message id: "+ msgId);
sundar@472 108 }
sundar@472 109 }
sundar@472 110
sundar@53 111 NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) {
sundar@53 112 this(factory, DEFAULT_OPTIONS, appLoader);
jlaskey@3 113 }
jlaskey@3 114
sundar@53 115 NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) {
jlaskey@3 116 this.factory = factory;
jlaskey@3 117 final Options options = new Options("nashorn");
jlaskey@3 118 options.process(args);
jlaskey@3 119
jlaskey@3 120 // throw ParseException on first error from script
sundar@41 121 final ErrorManager errMgr = new Context.ThrowErrorManager();
sundar@36 122 // create new Nashorn Context
jlaskey@3 123 this.nashornContext = AccessController.doPrivileged(new PrivilegedAction<Context>() {
jlaskey@3 124 @Override
jlaskey@3 125 public Context run() {
jlaskey@3 126 try {
sundar@41 127 return new Context(options, errMgr, appLoader);
jlaskey@3 128 } catch (final RuntimeException e) {
jlaskey@3 129 if (Context.DEBUG) {
jlaskey@3 130 e.printStackTrace();
jlaskey@3 131 }
jlaskey@3 132 throw e;
jlaskey@3 133 }
jlaskey@3 134 }
sundar@492 135 }, CREATE_CONTEXT_ACC_CTXT);
jlaskey@3 136
jlaskey@3 137 // create new global object
lagergren@252 138 this.global = createNashornGlobal();
sundar@45 139 // set the default engine scope for the default context
sundar@45 140 context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
jlaskey@3 141
jlaskey@3 142 // evaluate engine initial script
jlaskey@3 143 try {
sundar@36 144 evalEngineScript();
sundar@36 145 } catch (final ScriptException e) {
jlaskey@3 146 if (Context.DEBUG) {
jlaskey@3 147 e.printStackTrace();
jlaskey@3 148 }
jlaskey@3 149 throw new RuntimeException(e);
jlaskey@3 150 }
jlaskey@3 151 }
jlaskey@3 152
jlaskey@3 153 @Override
jlaskey@3 154 public Object eval(final Reader reader, final ScriptContext ctxt) throws ScriptException {
jlaskey@3 155 try {
sundar@99 156 if (reader instanceof URLReader) {
sundar@99 157 final URL url = ((URLReader)reader).getURL();
sundar@353 158 final Charset cs = ((URLReader)reader).getCharset();
sundar@353 159 return evalImpl(compileImpl(new Source(url.toString(), url, cs), ctxt), ctxt);
sundar@99 160 }
lagergren@112 161 return evalImpl(Source.readFully(reader), ctxt);
jlaskey@3 162 } catch (final IOException e) {
jlaskey@3 163 throw new ScriptException(e);
jlaskey@3 164 }
jlaskey@3 165 }
jlaskey@3 166
jlaskey@3 167 @Override
jlaskey@3 168 public Object eval(final String script, final ScriptContext ctxt) throws ScriptException {
jlaskey@3 169 return evalImpl(script.toCharArray(), ctxt);
jlaskey@3 170 }
jlaskey@3 171
jlaskey@3 172 @Override
jlaskey@3 173 public ScriptEngineFactory getFactory() {
jlaskey@3 174 return factory;
jlaskey@3 175 }
jlaskey@3 176
jlaskey@3 177 @Override
jlaskey@3 178 public Bindings createBindings() {
sundar@45 179 final ScriptObject newGlobal = createNashornGlobal();
sundar@45 180 return new ScriptObjectMirror(newGlobal, newGlobal);
jlaskey@3 181 }
jlaskey@3 182
jlaskey@3 183 // Compilable methods
jlaskey@3 184
jlaskey@3 185 @Override
jlaskey@3 186 public CompiledScript compile(final Reader reader) throws ScriptException {
jlaskey@3 187 try {
jlaskey@3 188 return asCompiledScript(compileImpl(Source.readFully(reader), context));
jlaskey@3 189 } catch (final IOException e) {
jlaskey@3 190 throw new ScriptException(e);
jlaskey@3 191 }
jlaskey@3 192 }
jlaskey@3 193
jlaskey@3 194 @Override
jlaskey@3 195 public CompiledScript compile(final String str) throws ScriptException {
jlaskey@3 196 return asCompiledScript(compileImpl(str.toCharArray(), context));
jlaskey@3 197 }
jlaskey@3 198
jlaskey@3 199 // Invocable methods
jlaskey@3 200
jlaskey@3 201 @Override
jlaskey@3 202 public Object invokeFunction(final String name, final Object... args)
jlaskey@3 203 throws ScriptException, NoSuchMethodException {
jlaskey@3 204 return invokeImpl(null, name, args);
jlaskey@3 205 }
jlaskey@3 206
jlaskey@3 207 @Override
sundar@472 208 public Object invokeMethod(final Object thiz, final String name, final Object... args)
jlaskey@3 209 throws ScriptException, NoSuchMethodException {
sundar@472 210 if (thiz == null) {
sundar@472 211 throw new IllegalArgumentException(getMessage("thiz.cannot.be.null"));
jlaskey@3 212 }
sundar@472 213 return invokeImpl(thiz, name, args);
jlaskey@3 214 }
jlaskey@3 215
sundar@472 216 private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) {
sundar@427 217 if (clazz == null || !clazz.isInterface()) {
sundar@472 218 throw new IllegalArgumentException(getMessage("interface.class.expected"));
sundar@427 219 }
sundar@427 220
sundar@427 221 // perform security access check as early as possible
sundar@427 222 final SecurityManager sm = System.getSecurityManager();
sundar@427 223 if (sm != null) {
sundar@427 224 if (! Modifier.isPublic(clazz.getModifiers())) {
sundar@472 225 throw new SecurityException(getMessage("implementing.non.public.interface", clazz.getName()));
sundar@427 226 }
sundar@428 227 Context.checkPackageAccess(clazz.getName());
sundar@427 228 }
sundar@427 229
sundar@472 230 ScriptObject realSelf = null;
sundar@472 231 ScriptObject realGlobal = null;
sundar@472 232 if(thiz == null) {
sundar@472 233 // making interface out of global functions
sundar@472 234 realSelf = realGlobal = getNashornGlobalFrom(context);
sundar@472 235 } else if (thiz instanceof ScriptObjectMirror) {
sundar@472 236 final ScriptObjectMirror mirror = (ScriptObjectMirror)thiz;
sundar@472 237 realSelf = mirror.getScriptObject();
sundar@472 238 realGlobal = mirror.getHomeGlobal();
sundar@472 239 if (! realGlobal.isOfContext(nashornContext)) {
sundar@472 240 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
sundar@472 241 }
sundar@472 242 } else if (thiz instanceof ScriptObject) {
sundar@472 243 // called from script code.
sundar@472 244 realSelf = (ScriptObject)thiz;
sundar@472 245 realGlobal = Context.getGlobal();
sundar@472 246 if (realGlobal == null) {
sundar@472 247 throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
sundar@472 248 }
sundar@472 249
sundar@472 250 if (! realGlobal.isOfContext(nashornContext)) {
sundar@472 251 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
sundar@472 252 }
sundar@472 253 }
sundar@472 254
sundar@472 255 if (realSelf == null) {
sundar@472 256 throw new IllegalArgumentException(getMessage("interface.on.non.script.object"));
jlaskey@3 257 }
sundar@427 258
jlaskey@3 259 try {
sundar@456 260 final ScriptObject oldGlobal = Context.getGlobal();
sundar@472 261 final boolean globalChanged = (oldGlobal != realGlobal);
jlaskey@3 262 try {
sundar@472 263 if (globalChanged) {
sundar@472 264 Context.setGlobal(realGlobal);
jlaskey@3 265 }
sundar@142 266
sundar@142 267 if (! isInterfaceImplemented(clazz, realSelf)) {
sundar@142 268 return null;
sundar@142 269 }
jlaskey@3 270 return clazz.cast(JavaAdapterFactory.getConstructor(realSelf.getClass(), clazz).invoke(realSelf));
jlaskey@3 271 } finally {
sundar@472 272 if (globalChanged) {
sundar@456 273 Context.setGlobal(oldGlobal);
jlaskey@3 274 }
jlaskey@3 275 }
jlaskey@3 276 } catch(final RuntimeException|Error e) {
jlaskey@3 277 throw e;
jlaskey@3 278 } catch(final Throwable t) {
jlaskey@3 279 throw new RuntimeException(t);
jlaskey@3 280 }
jlaskey@3 281 }
jlaskey@3 282
jlaskey@3 283 @Override
jlaskey@3 284 public <T> T getInterface(final Class<T> clazz) {
jlaskey@3 285 return getInterfaceInner(null, clazz);
jlaskey@3 286 }
jlaskey@3 287
jlaskey@3 288 @Override
sundar@472 289 public <T> T getInterface(final Object thiz, final Class<T> clazz) {
sundar@472 290 if (thiz == null) {
sundar@472 291 throw new IllegalArgumentException(getMessage("thiz.cannot.be.null"));
jlaskey@3 292 }
sundar@472 293 return getInterfaceInner(thiz, clazz);
jlaskey@3 294 }
jlaskey@3 295
jlaskey@3 296 // These are called from the "engine.js" script
jlaskey@3 297
jlaskey@3 298 /**
jlaskey@3 299 * This hook is used to search js global variables exposed from Java code.
jlaskey@3 300 *
jlaskey@3 301 * @param self 'this' passed from the script
jlaskey@3 302 * @param ctxt current ScriptContext in which name is searched
jlaskey@3 303 * @param name name of the variable searched
jlaskey@3 304 * @return the value of the named variable
jlaskey@3 305 */
jlaskey@3 306 public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
jlaskey@3 307 final int scope = ctxt.getAttributesScope(name);
sundar@45 308 final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
jlaskey@3 309 if (scope != -1) {
sundar@45 310 return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal);
jlaskey@3 311 }
jlaskey@3 312
jlaskey@3 313 if (self == UNDEFINED) {
jlaskey@3 314 // scope access and so throw ReferenceError
lagergren@112 315 throw referenceError(ctxtGlobal, "not.defined", name);
jlaskey@3 316 }
jlaskey@3 317
jlaskey@3 318 return UNDEFINED;
jlaskey@3 319 }
jlaskey@3 320
sundar@45 321 private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) {
sundar@45 322 final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE);
sundar@45 323 if (bindings instanceof ScriptObjectMirror) {
sundar@45 324 ScriptObject sobj = ((ScriptObjectMirror)bindings).getScriptObject();
sundar@45 325 if (sobj instanceof GlobalObject) {
sundar@45 326 return sobj;
sundar@45 327 }
sundar@45 328 }
sundar@45 329
sundar@45 330 // didn't find global object from context given - return the engine-wide global
sundar@45 331 return global;
sundar@45 332 }
sundar@45 333
sundar@45 334 private ScriptObject createNashornGlobal() {
sundar@45 335 final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction<ScriptObject>() {
sundar@45 336 @Override
sundar@45 337 public ScriptObject run() {
sundar@45 338 try {
jlaskey@67 339 return nashornContext.newGlobal();
sundar@45 340 } catch (final RuntimeException e) {
sundar@45 341 if (Context.DEBUG) {
sundar@45 342 e.printStackTrace();
sundar@45 343 }
sundar@45 344 throw e;
sundar@45 345 }
sundar@45 346 }
sundar@492 347 }, CREATE_GLOBAL_ACC_CTXT);
sundar@45 348
jlaskey@67 349 nashornContext.initGlobal(newGlobal);
jlaskey@67 350
sundar@377 351 final int NON_ENUMERABLE_CONSTANT = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE;
sundar@45 352 // current ScriptContext exposed as "context"
sundar@377 353 // "context" is non-writable from script - but script engine still
sundar@377 354 // needs to set it and so save the context Property object
sundar@377 355 contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, UNDEFINED);
sundar@45 356 // current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as
sundar@45 357 // NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property
sundar@45 358 // in the Global of a Context we just created - both the Context and the Global were just created and can not be
sundar@45 359 // seen from another thread outside of this constructor.
sundar@377 360 newGlobal.addOwnProperty("engine", NON_ENUMERABLE_CONSTANT, this);
sundar@45 361 // global script arguments with undefined value
sundar@45 362 newGlobal.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED);
sundar@45 363 // file name default is null
sundar@45 364 newGlobal.addOwnProperty(ScriptEngine.FILENAME, Property.NOT_ENUMERABLE, null);
sundar@45 365 return newGlobal;
sundar@45 366 }
sundar@45 367
jlaskey@3 368 private void evalEngineScript() throws ScriptException {
sundar@492 369 final String script = "resources/engine.js";
sundar@492 370 final String name = NashornException.ENGINE_SCRIPT_SOURCE_NAME;
jlaskey@3 371 try {
sundar@36 372 final InputStream is = AccessController.doPrivileged(
sundar@36 373 new PrivilegedExceptionAction<InputStream>() {
lagergren@57 374 @Override
sundar@36 375 public InputStream run() throws Exception {
sundar@36 376 final URL url = NashornScriptEngine.class.getResource(script);
sundar@36 377 return url.openStream();
sundar@36 378 }
sundar@36 379 });
sundar@61 380 put(ScriptEngine.FILENAME, name);
jlaskey@3 381 try (final InputStreamReader isr = new InputStreamReader(is)) {
jlaskey@3 382 eval(isr);
jlaskey@3 383 }
sundar@36 384 } catch (final PrivilegedActionException | IOException e) {
sundar@492 385 if (Context.DEBUG) {
sundar@492 386 e.printStackTrace();
sundar@492 387 }
jlaskey@3 388 throw new ScriptException(e);
jlaskey@3 389 } finally {
jlaskey@3 390 put(ScriptEngine.FILENAME, null);
jlaskey@3 391 }
jlaskey@3 392 }
jlaskey@3 393
jlaskey@3 394 // scripts should see "context" and "engine" as variables
jlaskey@3 395 private void setContextVariables(final ScriptContext ctxt) {
sundar@45 396 final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
sundar@377 397 // set "context" global variable via contextProperty - because this
sundar@377 398 // property is non-writable
sundar@377 399 contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false);
sundar@45 400 Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), ctxtGlobal);
sundar@38 401 if (args == null || args == UNDEFINED) {
jlaskey@3 402 args = ScriptRuntime.EMPTY_ARRAY;
jlaskey@3 403 }
sundar@38 404 // if no arguments passed, expose it
sundar@45 405 args = ((GlobalObject)ctxtGlobal).wrapAsObject(args);
sundar@45 406 ctxtGlobal.set("arguments", args, false);
jlaskey@3 407 }
jlaskey@3 408
jlaskey@3 409 private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
sundar@470 410 name.getClass(); // null check
jlaskey@3 411
sundar@470 412 ScriptObjectMirror selfMirror = null;
sundar@470 413 if (selfObject instanceof ScriptObjectMirror) {
sundar@470 414 selfMirror = (ScriptObjectMirror)selfObject;
sundar@472 415 if (! selfMirror.getHomeGlobal().isOfContext(nashornContext)) {
sundar@472 416 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
sundar@472 417 }
sundar@470 418 } else if (selfObject instanceof ScriptObject) {
sundar@470 419 // invokeMethod called from script code - in which case we may get 'naked' ScriptObject
sundar@470 420 // Wrap it with oldGlobal to make a ScriptObjectMirror for the same.
sundar@470 421 final ScriptObject oldGlobal = Context.getGlobal();
sundar@472 422 if (oldGlobal == null) {
sundar@472 423 throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
sundar@470 424 }
sundar@472 425
sundar@472 426 if (! oldGlobal.isOfContext(nashornContext)) {
sundar@472 427 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
sundar@472 428 }
sundar@472 429
sundar@472 430 selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal);
sundar@470 431 } else if (selfObject == null) {
sundar@470 432 // selfObject is null => global function call
sundar@470 433 final ScriptObject ctxtGlobal = getNashornGlobalFrom(context);
sundar@470 434 selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(ctxtGlobal, ctxtGlobal);
sundar@470 435 }
jlaskey@3 436
sundar@470 437 if (selfMirror != null) {
sundar@470 438 try {
sundar@470 439 return ScriptObjectMirror.translateUndefined(selfMirror.call(name, args));
sundar@470 440 } catch (final Exception e) {
sundar@470 441 final Throwable cause = e.getCause();
sundar@470 442 if (cause instanceof NoSuchMethodException) {
sundar@470 443 throw (NoSuchMethodException)cause;
jlaskey@3 444 }
sundar@470 445 throwAsScriptException(e);
sundar@470 446 throw new AssertionError("should not reach here");
jlaskey@3 447 }
jlaskey@3 448 }
sundar@470 449
sundar@470 450 // Non-script object passed as selfObject
sundar@472 451 throw new IllegalArgumentException(getMessage("interface.on.non.script.object"));
jlaskey@3 452 }
jlaskey@3 453
jlaskey@3 454 private Object evalImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException {
jlaskey@3 455 return evalImpl(compileImpl(buf, ctxt), ctxt);
jlaskey@3 456 }
jlaskey@3 457
jlaskey@3 458 private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException {
jlaskey@3 459 if (script == null) {
jlaskey@3 460 return null;
jlaskey@3 461 }
sundar@456 462 final ScriptObject oldGlobal = Context.getGlobal();
sundar@45 463 final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
sundar@45 464 final boolean globalChanged = (oldGlobal != ctxtGlobal);
jlaskey@3 465 try {
jlaskey@3 466 if (globalChanged) {
sundar@456 467 Context.setGlobal(ctxtGlobal);
jlaskey@3 468 }
jlaskey@3 469
jlaskey@3 470 setContextVariables(ctxt);
lagergren@211 471 return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
jlaskey@3 472 } catch (final Exception e) {
jlaskey@3 473 throwAsScriptException(e);
jlaskey@3 474 throw new AssertionError("should not reach here");
jlaskey@3 475 } finally {
jlaskey@3 476 if (globalChanged) {
sundar@456 477 Context.setGlobal(oldGlobal);
jlaskey@3 478 }
jlaskey@3 479 }
jlaskey@3 480 }
jlaskey@3 481
jlaskey@3 482 private static void throwAsScriptException(final Exception e) throws ScriptException {
jlaskey@3 483 if (e instanceof ScriptException) {
jlaskey@3 484 throw (ScriptException)e;
jlaskey@3 485 } else if (e instanceof NashornException) {
jlaskey@3 486 final NashornException ne = (NashornException)e;
jlaskey@3 487 final ScriptException se = new ScriptException(
jlaskey@3 488 ne.getMessage(), ne.getFileName(),
jlaskey@3 489 ne.getLineNumber(), ne.getColumnNumber());
jlaskey@3 490 se.initCause(e);
jlaskey@3 491 throw se;
jlaskey@3 492 } else if (e instanceof RuntimeException) {
jlaskey@3 493 throw (RuntimeException)e;
jlaskey@3 494 } else {
jlaskey@3 495 // wrap any other exception as ScriptException
jlaskey@3 496 throw new ScriptException(e);
jlaskey@3 497 }
jlaskey@3 498 }
jlaskey@3 499
jlaskey@3 500 private CompiledScript asCompiledScript(final ScriptFunction script) {
jlaskey@3 501 return new CompiledScript() {
jlaskey@3 502 @Override
jlaskey@3 503 public Object eval(final ScriptContext ctxt) throws ScriptException {
jlaskey@3 504 return evalImpl(script, ctxt);
jlaskey@3 505 }
jlaskey@3 506 @Override
jlaskey@3 507 public ScriptEngine getEngine() {
jlaskey@3 508 return NashornScriptEngine.this;
jlaskey@3 509 }
jlaskey@3 510 };
jlaskey@3 511 }
jlaskey@3 512
jlaskey@3 513 private ScriptFunction compileImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException {
sundar@99 514 final Object val = ctxt.getAttribute(ScriptEngine.FILENAME);
sundar@99 515 final String fileName = (val != null) ? val.toString() : "<eval>";
sundar@99 516 return compileImpl(new Source(fileName, buf), ctxt);
sundar@99 517 }
sundar@99 518
sundar@99 519 private ScriptFunction compileImpl(final Source source, final ScriptContext ctxt) throws ScriptException {
sundar@456 520 final ScriptObject oldGlobal = Context.getGlobal();
sundar@45 521 final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
sundar@45 522 final boolean globalChanged = (oldGlobal != ctxtGlobal);
jlaskey@3 523 try {
jlaskey@3 524 if (globalChanged) {
sundar@456 525 Context.setGlobal(ctxtGlobal);
jlaskey@3 526 }
jlaskey@3 527
sundar@86 528 return nashornContext.compileScript(source, ctxtGlobal);
jlaskey@3 529 } catch (final Exception e) {
jlaskey@3 530 throwAsScriptException(e);
jlaskey@3 531 throw new AssertionError("should not reach here");
jlaskey@3 532 } finally {
jlaskey@3 533 if (globalChanged) {
sundar@456 534 Context.setGlobal(oldGlobal);
jlaskey@3 535 }
jlaskey@3 536 }
jlaskey@3 537 }
jlaskey@3 538
sundar@142 539 private static boolean isInterfaceImplemented(final Class<?> iface, final ScriptObject sobj) {
sundar@142 540 for (final Method method : iface.getMethods()) {
sundar@142 541 // ignore methods of java.lang.Object class
sundar@142 542 if (method.getDeclaringClass() == Object.class) {
sundar@142 543 continue;
sundar@142 544 }
sundar@142 545
sundar@142 546 Object obj = sobj.get(method.getName());
sundar@142 547 if (! (obj instanceof ScriptFunction)) {
sundar@142 548 return false;
sundar@142 549 }
sundar@142 550 }
sundar@142 551 return true;
sundar@142 552 }
jlaskey@3 553 }

mercurial