1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * 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 26 package jdk.nashorn.api.scripting; 27 28 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; 29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 30 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.InputStreamReader; 34 import java.io.Reader; 35 import java.lang.reflect.Method; 36 import java.lang.reflect.Modifier; 37 import java.net.URL; 38 import java.nio.charset.Charset; 39 import java.security.AccessControlContext; 40 import java.security.AccessController; 41 import java.security.Permissions; 42 import java.security.PrivilegedAction; 43 import java.security.PrivilegedActionException; 44 import java.security.PrivilegedExceptionAction; 45 import java.security.ProtectionDomain; 46 import java.text.MessageFormat; 47 import java.util.Locale; 48 import java.util.ResourceBundle; 49 import javax.script.AbstractScriptEngine; 50 import javax.script.Bindings; 51 import javax.script.Compilable; 52 import javax.script.CompiledScript; 53 import javax.script.Invocable; 54 import javax.script.ScriptContext; 55 import javax.script.ScriptEngine; 56 import javax.script.ScriptEngineFactory; 57 import javax.script.ScriptException; 58 import javax.script.SimpleBindings; 59 import jdk.nashorn.internal.runtime.Context; 60 import jdk.nashorn.internal.runtime.ErrorManager; 61 import jdk.nashorn.internal.runtime.GlobalObject; 62 import jdk.nashorn.internal.runtime.Property; 63 import jdk.nashorn.internal.runtime.ScriptFunction; 64 import jdk.nashorn.internal.runtime.ScriptObject; 65 import jdk.nashorn.internal.runtime.ScriptRuntime; 66 import jdk.nashorn.internal.runtime.Source; 67 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; 68 import jdk.nashorn.internal.runtime.options.Options; 69 70 /** 71 * JSR-223 compliant script engine for Nashorn. Instances are not created directly, but rather returned through 72 * {@link NashornScriptEngineFactory#getScriptEngine()}. Note that this engine implements the {@link Compilable} and 73 * {@link Invocable} interfaces, allowing for efficient precompilation and repeated execution of scripts. 74 * @see NashornScriptEngineFactory 75 */ 76 77 public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable { 78 /** 79 * Key used to associate Nashorn global object mirror with arbitrary Bindings instance. 80 */ 81 public static final String NASHORN_GLOBAL = "nashorn.global"; 82 83 // commonly used access control context objects 84 private static AccessControlContext createPermAccCtxt(final String permName) { 85 final Permissions perms = new Permissions(); 86 perms.add(new RuntimePermission(permName)); 87 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); 88 } 89 90 private static final AccessControlContext CREATE_CONTEXT_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_CONTEXT); 91 private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_GLOBAL); 92 93 // the factory that created this engine 94 private final ScriptEngineFactory factory; 95 // underlying nashorn Context - 1:1 with engine instance 96 private final Context nashornContext; 97 // do we want to share single Nashorn global instance across ENGINE_SCOPEs? 98 private final boolean _global_per_engine; 99 // This is the initial default Nashorn global object. 100 // This is used as "shared" global if above option is true. 101 private final ScriptObject global; 102 // initialized bit late to be made 'final'. 103 // Property object for "context" property of global object. 104 private volatile Property contextProperty; 105 106 // default options passed to Nashorn Options object 107 private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-doe" }; 108 109 // Nashorn script engine error message management 110 private static final String MESSAGES_RESOURCE = "jdk.nashorn.api.scripting.resources.Messages"; 111 112 private static final ResourceBundle MESSAGES_BUNDLE; 113 static { 114 MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); 115 } 116 117 // helper to get Nashorn script engine error message 118 private static String getMessage(final String msgId, final String... args) { 119 try { 120 return new MessageFormat(MESSAGES_BUNDLE.getString(msgId)).format(args); 121 } catch (final java.util.MissingResourceException e) { 122 throw new RuntimeException("no message resource found for message id: "+ msgId); 123 } 124 } 125 126 // load engine.js and return content as a char[] 127 @SuppressWarnings("resource") 128 private static char[] loadEngineJSSource() { 129 final String script = "resources/engine.js"; 130 try { 131 final InputStream is = AccessController.doPrivileged( 132 new PrivilegedExceptionAction<InputStream>() { 133 @Override 134 public InputStream run() throws Exception { 135 final URL url = NashornScriptEngine.class.getResource(script); 136 return url.openStream(); 137 } 138 }); 139 return Source.readFully(new InputStreamReader(is)); 140 } catch (final PrivilegedActionException | IOException e) { 141 if (Context.DEBUG) { 142 e.printStackTrace(); 143 } 144 throw new RuntimeException(e); 145 } 146 } 147 148 // Source object for engine.js 149 private static final Source ENGINE_SCRIPT_SRC = new Source(NashornException.ENGINE_SCRIPT_SOURCE_NAME, loadEngineJSSource()); 150 151 NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) { 152 this(factory, DEFAULT_OPTIONS, appLoader); 153 } 154 155 NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) { 156 this.factory = factory; 157 final Options options = new Options("nashorn"); 158 options.process(args); 159 160 // throw ParseException on first error from script 161 final ErrorManager errMgr = new Context.ThrowErrorManager(); 162 // create new Nashorn Context 163 this.nashornContext = AccessController.doPrivileged(new PrivilegedAction<Context>() { 164 @Override 165 public Context run() { 166 try { 167 return new Context(options, errMgr, appLoader); 168 } catch (final RuntimeException e) { 169 if (Context.DEBUG) { 170 e.printStackTrace(); 171 } 172 throw e; 173 } 174 } 175 }, CREATE_CONTEXT_ACC_CTXT); 176 177 // cache this option that is used often 178 this._global_per_engine = nashornContext.getEnv()._global_per_engine; 179 180 // create new global object 181 this.global = createNashornGlobal(context); 182 // set the default ENGINE_SCOPE object for the default context 183 context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE); 184 } 185 186 @Override 187 public Object eval(final Reader reader, final ScriptContext ctxt) throws ScriptException { 188 return evalImpl(makeSource(reader, ctxt), ctxt); 189 } 190 191 @Override 192 public Object eval(final String script, final ScriptContext ctxt) throws ScriptException { 193 return evalImpl(makeSource(script, ctxt), ctxt); 194 } 195 196 @Override 197 public ScriptEngineFactory getFactory() { 198 return factory; 199 } 200 201 @Override 202 public Bindings createBindings() { 203 if (_global_per_engine) { 204 // just create normal SimpleBindings. 205 // We use same 'global' for all Bindings. 206 return new SimpleBindings(); 207 } 208 return createGlobalMirror(null); 209 } 210 211 // Compilable methods 212 213 @Override 214 public CompiledScript compile(final Reader reader) throws ScriptException { 215 return asCompiledScript(makeSource(reader, context)); 216 } 217 218 @Override 219 public CompiledScript compile(final String str) throws ScriptException { 220 return asCompiledScript(makeSource(str, context)); 221 } 222 223 // Invocable methods 224 225 @Override 226 public Object invokeFunction(final String name, final Object... args) 227 throws ScriptException, NoSuchMethodException { 228 return invokeImpl(null, name, args); 229 } 230 231 @Override 232 public Object invokeMethod(final Object thiz, final String name, final Object... args) 233 throws ScriptException, NoSuchMethodException { 234 if (thiz == null) { 235 throw new IllegalArgumentException(getMessage("thiz.cannot.be.null")); 236 } 237 return invokeImpl(thiz, name, args); 238 } 239 240 @Override 241 public <T> T getInterface(final Class<T> clazz) { 242 return getInterfaceInner(null, clazz); 243 } 244 245 @Override 246 public <T> T getInterface(final Object thiz, final Class<T> clazz) { 247 if (thiz == null) { 248 throw new IllegalArgumentException(getMessage("thiz.cannot.be.null")); 249 } 250 return getInterfaceInner(thiz, clazz); 251 } 252 253 // These are called from the "engine.js" script 254 255 /** 256 * This hook is used to search js global variables exposed from Java code. 257 * 258 * @param self 'this' passed from the script 259 * @param ctxt current ScriptContext in which name is searched 260 * @param name name of the variable searched 261 * @return the value of the named variable 262 */ 263 public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) { 264 if (ctxt != null) { 265 final int scope = ctxt.getAttributesScope(name); 266 final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt); 267 if (scope != -1) { 268 return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal); 269 } 270 271 if (self == UNDEFINED) { 272 // scope access and so throw ReferenceError 273 throw referenceError(ctxtGlobal, "not.defined", name); 274 } 275 } 276 277 return UNDEFINED; 278 } 279 280 // Implementation only below this point 281 282 private static Source makeSource(final Reader reader, final ScriptContext ctxt) throws ScriptException { 283 try { 284 if (reader instanceof URLReader) { 285 final URL url = ((URLReader)reader).getURL(); 286 final Charset cs = ((URLReader)reader).getCharset(); 287 return new Source(url.toString(), url, cs); 288 } 289 return new Source(getScriptName(ctxt), Source.readFully(reader)); 290 } catch (final IOException e) { 291 throw new ScriptException(e); 292 } 293 } 294 295 private static Source makeSource(final String src, final ScriptContext ctxt) { 296 return new Source(getScriptName(ctxt), src); 297 } 298 299 private static String getScriptName(final ScriptContext ctxt) { 300 final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); 301 return (val != null) ? val.toString() : "<eval>"; 302 } 303 304 private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) { 305 if (clazz == null || !clazz.isInterface()) { 306 throw new IllegalArgumentException(getMessage("interface.class.expected")); 307 } 308 309 // perform security access check as early as possible 310 final SecurityManager sm = System.getSecurityManager(); 311 if (sm != null) { 312 if (! Modifier.isPublic(clazz.getModifiers())) { 313 throw new SecurityException(getMessage("implementing.non.public.interface", clazz.getName())); 314 } 315 Context.checkPackageAccess(clazz); 316 } 317 318 ScriptObject realSelf = null; 319 ScriptObject realGlobal = null; 320 if(thiz == null) { 321 // making interface out of global functions 322 realSelf = realGlobal = getNashornGlobalFrom(context); 323 } else if (thiz instanceof ScriptObjectMirror) { 324 final ScriptObjectMirror mirror = (ScriptObjectMirror)thiz; 325 realSelf = mirror.getScriptObject(); 326 realGlobal = mirror.getHomeGlobal(); 327 if (! isOfContext(realGlobal, nashornContext)) { 328 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 329 } 330 } else if (thiz instanceof ScriptObject) { 331 // called from script code. 332 realSelf = (ScriptObject)thiz; 333 realGlobal = Context.getGlobal(); 334 if (realGlobal == null) { 335 throw new IllegalArgumentException(getMessage("no.current.nashorn.global")); 336 } 337 338 if (! isOfContext(realGlobal, nashornContext)) { 339 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 340 } 341 } 342 343 if (realSelf == null) { 344 throw new IllegalArgumentException(getMessage("interface.on.non.script.object")); 345 } 346 347 try { 348 final ScriptObject oldGlobal = Context.getGlobal(); 349 final boolean globalChanged = (oldGlobal != realGlobal); 350 try { 351 if (globalChanged) { 352 Context.setGlobal(realGlobal); 353 } 354 355 if (! isInterfaceImplemented(clazz, realSelf)) { 356 return null; 357 } 358 return clazz.cast(JavaAdapterFactory.getConstructor(realSelf.getClass(), clazz).invoke(realSelf)); 359 } finally { 360 if (globalChanged) { 361 Context.setGlobal(oldGlobal); 362 } 363 } 364 } catch(final RuntimeException|Error e) { 365 throw e; 366 } catch(final Throwable t) { 367 throw new RuntimeException(t); 368 } 369 } 370 371 // Retrieve nashorn Global object for a given ScriptContext object 372 private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) { 373 if (_global_per_engine) { 374 // shared single global object for all ENGINE_SCOPE Bindings 375 return global; 376 } 377 378 final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE); 379 // is this Nashorn's own Bindings implementation? 380 if (bindings instanceof ScriptObjectMirror) { 381 final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)bindings); 382 if (sobj != null) { 383 return sobj; 384 } 385 } 386 387 // Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it! 388 Object scope = bindings.get(NASHORN_GLOBAL); 389 if (scope instanceof ScriptObjectMirror) { 390 final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)scope); 391 if (sobj != null) { 392 return sobj; 393 } 394 } 395 396 // We didn't find associated nashorn global mirror in the Bindings given! 397 // Create new global instance mirror and associate with the Bindings. 398 final ScriptObjectMirror mirror = createGlobalMirror(ctxt); 399 bindings.put(NASHORN_GLOBAL, mirror); 400 return mirror.getScriptObject(); 401 } 402 403 // Retrieve nashorn Global object from a given ScriptObjectMirror 404 private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) { 405 ScriptObject sobj = mirror.getScriptObject(); 406 if (sobj instanceof GlobalObject && isOfContext(sobj, nashornContext)) { 407 return sobj; 408 } 409 410 return null; 411 } 412 413 // Create a new ScriptObjectMirror wrapping a newly created Nashorn Global object 414 private ScriptObjectMirror createGlobalMirror(final ScriptContext ctxt) { 415 final ScriptObject newGlobal = createNashornGlobal(ctxt); 416 return new ScriptObjectMirror(newGlobal, newGlobal); 417 } 418 419 // Create a new Nashorn Global object 420 private ScriptObject createNashornGlobal(final ScriptContext ctxt) { 421 final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction<ScriptObject>() { 422 @Override 423 public ScriptObject run() { 424 try { 425 return nashornContext.newGlobal(); 426 } catch (final RuntimeException e) { 427 if (Context.DEBUG) { 428 e.printStackTrace(); 429 } 430 throw e; 431 } 432 } 433 }, CREATE_GLOBAL_ACC_CTXT); 434 435 nashornContext.initGlobal(newGlobal); 436 437 final int NON_ENUMERABLE_CONSTANT = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE; 438 // current ScriptContext exposed as "context" 439 // "context" is non-writable from script - but script engine still 440 // needs to set it and so save the context Property object 441 contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, ctxt); 442 // current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as 443 // NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property 444 // in the Global of a Context we just created - both the Context and the Global were just created and can not be 445 // seen from another thread outside of this constructor. 446 newGlobal.addOwnProperty("engine", NON_ENUMERABLE_CONSTANT, this); 447 // global script arguments with undefined value 448 newGlobal.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED); 449 // file name default is null 450 newGlobal.addOwnProperty(ScriptEngine.FILENAME, Property.NOT_ENUMERABLE, null); 451 // evaluate engine.js initialization script this new global object 452 try { 453 evalImpl(compileImpl(ENGINE_SCRIPT_SRC, newGlobal), ctxt, newGlobal); 454 } catch (final ScriptException exp) { 455 throw new RuntimeException(exp); 456 } 457 return newGlobal; 458 } 459 460 // scripts should see "context" and "engine" as variables in the given global object 461 private void setContextVariables(final ScriptObject ctxtGlobal, final ScriptContext ctxt) { 462 // set "context" global variable via contextProperty - because this 463 // property is non-writable 464 contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false); 465 Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), ctxtGlobal); 466 if (args == null || args == UNDEFINED) { 467 args = ScriptRuntime.EMPTY_ARRAY; 468 } 469 // if no arguments passed, expose it 470 if (! (args instanceof ScriptObject)) { 471 args = ((GlobalObject)ctxtGlobal).wrapAsObject(args); 472 ctxtGlobal.set("arguments", args, false); 473 } 474 } 475 476 private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException { 477 name.getClass(); // null check 478 479 ScriptObject invokeGlobal = null; 480 ScriptObjectMirror selfMirror = null; 481 if (selfObject instanceof ScriptObjectMirror) { 482 selfMirror = (ScriptObjectMirror)selfObject; 483 if (! isOfContext(selfMirror.getHomeGlobal(), nashornContext)) { 484 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 485 } 486 invokeGlobal = selfMirror.getHomeGlobal(); 487 } else if (selfObject instanceof ScriptObject) { 488 // invokeMethod called from script code - in which case we may get 'naked' ScriptObject 489 // Wrap it with oldGlobal to make a ScriptObjectMirror for the same. 490 final ScriptObject oldGlobal = Context.getGlobal(); 491 invokeGlobal = oldGlobal; 492 if (oldGlobal == null) { 493 throw new IllegalArgumentException(getMessage("no.current.nashorn.global")); 494 } 495 496 if (! isOfContext(oldGlobal, nashornContext)) { 497 throw new IllegalArgumentException(getMessage("script.object.from.another.engine")); 498 } 499 500 selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal); 501 } else if (selfObject == null) { 502 // selfObject is null => global function call 503 final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); 504 invokeGlobal = ctxtGlobal; 505 selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(ctxtGlobal, ctxtGlobal); 506 } 507 508 if (selfMirror != null) { 509 try { 510 return ScriptObjectMirror.translateUndefined(selfMirror.callMember(name, args)); 511 } catch (final Exception e) { 512 final Throwable cause = e.getCause(); 513 if (cause instanceof NoSuchMethodException) { 514 throw (NoSuchMethodException)cause; 515 } 516 throwAsScriptException(e, invokeGlobal); 517 throw new AssertionError("should not reach here"); 518 } 519 } 520 521 // Non-script object passed as selfObject 522 throw new IllegalArgumentException(getMessage("interface.on.non.script.object")); 523 } 524 525 private Object evalImpl(final Source src, final ScriptContext ctxt) throws ScriptException { 526 return evalImpl(compileImpl(src, ctxt), ctxt); 527 } 528 529 private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException { 530 return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt)); 531 } 532 533 private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final ScriptObject ctxtGlobal) throws ScriptException { 534 if (script == null) { 535 return null; 536 } 537 final ScriptObject oldGlobal = Context.getGlobal(); 538 final boolean globalChanged = (oldGlobal != ctxtGlobal); 539 try { 540 if (globalChanged) { 541 Context.setGlobal(ctxtGlobal); 542 } 543 544 // set ScriptContext variables if ctxt is non-null 545 if (ctxt != null) { 546 setContextVariables(ctxtGlobal, ctxt); 547 } 548 return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); 549 } catch (final Exception e) { 550 throwAsScriptException(e, ctxtGlobal); 551 throw new AssertionError("should not reach here"); 552 } finally { 553 if (globalChanged) { 554 Context.setGlobal(oldGlobal); 555 } 556 } 557 } 558 559 private static void throwAsScriptException(final Exception e, final ScriptObject global) throws ScriptException { 560 if (e instanceof ScriptException) { 561 throw (ScriptException)e; 562 } else if (e instanceof NashornException) { 563 final NashornException ne = (NashornException)e; 564 final ScriptException se = new ScriptException( 565 ne.getMessage(), ne.getFileName(), 566 ne.getLineNumber(), ne.getColumnNumber()); 567 ne.initEcmaError(global); 568 se.initCause(e); 569 throw se; 570 } else if (e instanceof RuntimeException) { 571 throw (RuntimeException)e; 572 } else { 573 // wrap any other exception as ScriptException 574 throw new ScriptException(e); 575 } 576 } 577 578 private CompiledScript asCompiledScript(final Source source) throws ScriptException { 579 final ScriptFunction func = compileImpl(source, context); 580 return new CompiledScript() { 581 @Override 582 public Object eval(final ScriptContext ctxt) throws ScriptException { 583 final ScriptObject globalObject = getNashornGlobalFrom(ctxt); 584 // Are we running the script in the correct global? 585 if (func.getScope() == globalObject) { 586 return evalImpl(func, ctxt, globalObject); 587 } 588 // ScriptContext with a different global. Compile again! 589 // Note that we may still hit per-global compilation cache. 590 return evalImpl(compileImpl(source, ctxt), ctxt, globalObject); 591 } 592 @Override 593 public ScriptEngine getEngine() { 594 return NashornScriptEngine.this; 595 } 596 }; 597 } 598 599 private ScriptFunction compileImpl(final Source source, final ScriptContext ctxt) throws ScriptException { 600 return compileImpl(source, getNashornGlobalFrom(ctxt)); 601 } 602 603 private ScriptFunction compileImpl(final Source source, final ScriptObject newGlobal) throws ScriptException { 604 final ScriptObject oldGlobal = Context.getGlobal(); 605 final boolean globalChanged = (oldGlobal != newGlobal); 606 try { 607 if (globalChanged) { 608 Context.setGlobal(newGlobal); 609 } 610 611 return nashornContext.compileScript(source, newGlobal); 612 } catch (final Exception e) { 613 throwAsScriptException(e, newGlobal); 614 throw new AssertionError("should not reach here"); 615 } finally { 616 if (globalChanged) { 617 Context.setGlobal(oldGlobal); 618 } 619 } 620 } 621 622 private static boolean isInterfaceImplemented(final Class<?> iface, final ScriptObject sobj) { 623 for (final Method method : iface.getMethods()) { 624 // ignore methods of java.lang.Object class 625 if (method.getDeclaringClass() == Object.class) { 626 continue; 627 } 628 629 Object obj = sobj.get(method.getName()); 630 if (! (obj instanceof ScriptFunction)) { 631 return false; 632 } 633 } 634 return true; 635 } 636 637 private static boolean isOfContext(final ScriptObject global, final Context context) { 638 assert global instanceof GlobalObject: "Not a Global object"; 639 return ((GlobalObject)global).isOfContext(context); 640 } 641 }