1 /* 2 * Copyright (c) 2005, 2010, 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 com.sun.script.javascript; 27 28 import sun.org.mozilla.javascript.internal.*; 29 import javax.script.*; 30 31 /** 32 * This class serves as top level scope for Rhino. This class adds 33 * 3 top level functions (bindings, scope, sync) and two constructors 34 * (JSAdapter, JavaAdapter). 35 * 36 * @author A. Sundararajan 37 * @since 1.6 38 */ 39 public final class RhinoTopLevel extends ImporterTopLevel { 40 RhinoTopLevel(Context cx, RhinoScriptEngine engine) { 41 super(cx); 42 this.engine = engine; 43 44 45 // initialize JSAdapter lazily. Reduces footprint & startup time. 46 new LazilyLoadedCtor(this, "JSAdapter", 47 "com.sun.script.javascript.JSAdapter", 48 false); 49 50 /* 51 * initialize JavaAdapter. We can't lazy initialize this because 52 * lazy initializer attempts to define a new property. But, JavaAdapter 53 * is an exisiting property that we overwrite. 54 */ 55 JavaAdapter.init(cx, this, false); 56 57 // add top level functions 58 String names[] = { "bindings", "scope", "sync" }; 59 defineFunctionProperties(names, RhinoTopLevel.class, 60 ScriptableObject.DONTENUM); 61 } 62 63 /** 64 * The bindings function takes a JavaScript scope object 65 * of type ExternalScriptable and returns the underlying Bindings 66 * instance. 67 * 68 * var page = scope(pageBindings); 69 * with (page) { 70 * // code that uses page scope 71 * } 72 * var b = bindings(page); 73 * // operate on bindings here. 74 */ 75 public static Object bindings(Context cx, Scriptable thisObj, Object[] args, 76 Function funObj) { 77 if (args.length == 1) { 78 Object arg = args[0]; 79 if (arg instanceof Wrapper) { 80 arg = ((Wrapper)arg).unwrap(); 81 } 82 if (arg instanceof ExternalScriptable) { 83 ScriptContext ctx = ((ExternalScriptable)arg).getContext(); 84 Bindings bind = ctx.getBindings(ScriptContext.ENGINE_SCOPE); 85 return Context.javaToJS(bind, 86 ScriptableObject.getTopLevelScope(thisObj)); 87 } 88 } 89 return cx.getUndefinedValue(); 90 } 91 92 /** 93 * The scope function creates a new JavaScript scope object 94 * with given Bindings object as backing store. This can be used 95 * to create a script scope based on arbitrary Bindings instance. 96 * For example, in webapp scenario, a 'page' level Bindings instance 97 * may be wrapped as a scope and code can be run in JavaScripe 'with' 98 * statement: 99 * 100 * var page = scope(pageBindings); 101 * with (page) { 102 * // code that uses page scope 103 * } 104 */ 105 public static Object scope(Context cx, Scriptable thisObj, Object[] args, 106 Function funObj) { 107 if (args.length == 1) { 108 Object arg = args[0]; 109 if (arg instanceof Wrapper) { 110 arg = ((Wrapper)arg).unwrap(); 111 } 112 if (arg instanceof Bindings) { 113 ScriptContext ctx = new SimpleScriptContext(); 114 ctx.setBindings((Bindings)arg, ScriptContext.ENGINE_SCOPE); 115 Scriptable res = new ExternalScriptable(ctx); 116 res.setPrototype(ScriptableObject.getObjectPrototype(thisObj)); 117 res.setParentScope(ScriptableObject.getTopLevelScope(thisObj)); 118 return res; 119 } 120 } 121 return cx.getUndefinedValue(); 122 } 123 124 /** 125 * The sync function creates a synchronized function (in the sense 126 * of a Java synchronized method) from an existing function. The 127 * new function synchronizes on the <code>this</code> object of 128 * its invocation. 129 * js> var o = { f : sync(function(x) { 130 * print("entry"); 131 * Packages.java.lang.Thread.sleep(x*1000); 132 * print("exit"); 133 * })}; 134 * js> thread(function() {o.f(5);}); 135 * entry 136 * js> thread(function() {o.f(5);}); 137 * js> 138 * exit 139 * entry 140 * exit 141 */ 142 public static Object sync(Context cx, Scriptable thisObj, Object[] args, 143 Function funObj) { 144 if (args.length == 1 && args[0] instanceof Function) { 145 return new Synchronizer((Function)args[0]); 146 } else { 147 throw Context.reportRuntimeError("wrong argument(s) for sync"); 148 } 149 } 150 151 RhinoScriptEngine getScriptEngine() { 152 return engine; 153 } 154 155 private RhinoScriptEngine engine; 156 }