001: /*
002: * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.es;
030:
031: import com.caucho.util.Exit;
032:
033: /**
034: * ScriptClosure lets Java programs call JavaScript functions. It contains
035: * the state of an executing JavaScript program.
036: */
037: final public class ScriptClosure {
038: private Script script;
039: private Global resin;
040: private ESGlobal global;
041:
042: ScriptClosure(Global resin, ESGlobal global, Script script) {
043: this .script = script;
044: this .resin = resin;
045: this .global = global;
046: }
047:
048: /**
049: * Returns the lastModified time of the script. The last modified
050: * time is the maximum of all imported script modified times.
051: *
052: * <p>getLastModified is vital for dynamic applications like JSP
053: * which need to reload the script when it changes.
054: */
055: public boolean isModified() {
056: return script.isModified();
057: }
058:
059: /**
060: * Calls the JavaScript function 'name' with no arguments.
061: *
062: * @param name JavaScript function name.
063: * @return The Java object returned by the JavaScript function.
064: */
065: public synchronized Object call(String name) throws Throwable {
066: Call call = resin.getCall();
067: call.caller = call;
068: call.top = 1;
069: call.setArg(-1, global);
070:
071: Object value = call(getFunction(name), call, 0);
072:
073: resin.freeCall(call);
074:
075: return value;
076: }
077:
078: /**
079: * Calls the JavaScript function 'name' with a single argument.
080: * <p>Arguments are automatically wrapped, and return values automatically
081: * unwrapped.
082: *
083: * @param name JavaScript function name.
084: * @param a First argument passed to JavaScript.
085: * @return The Java object returned by the JavaScript function.
086: */
087: public synchronized Object call(String name, Object a)
088: throws Throwable {
089: Call call = resin.getCall();
090: call.caller = call;
091: call.top = 1;
092: call.setArg(-1, global);
093: call.setArg(0, resin.objectWrap(a));
094:
095: Object value = call(getFunction(name), call, 1);
096:
097: resin.freeCall(call);
098:
099: return value;
100: }
101:
102: /**
103: * Calls the JavaScript function 'name' with two arguments.
104: * <p>Arguments are automatically wrapped, and return values automatically
105: * unwrapped.
106: *
107: * @param name JavaScript function name.
108: * @param a First argument passed to JavaScript.
109: * @param b Second argument passed to JavaScript.
110: * @return The Java object returned by the JavaScript function.
111: */
112: public synchronized Object call(String name, Object a, Object b)
113: throws Throwable {
114: Call call = resin.getCall();
115: call.caller = call;
116: call.top = 1;
117: call.setArg(-1, global);
118: call.setArg(0, resin.objectWrap(a));
119: call.setArg(1, resin.objectWrap(b));
120:
121: Object value = call(getFunction(name), call, 2);
122:
123: resin.freeCall(call);
124:
125: return value;
126: }
127:
128: /**
129: * Calls the JavaScript function 'name' with three arguments.
130: * <p>Arguments are automatically wrapped, and return values automatically
131: * unwrapped.
132: *
133: * @param name JavaScript function name.
134: * @param a First argument passed to JavaScript.
135: * @param b Second argument passed to JavaScript.
136: * @param c Third argument passed to JavaScript.
137: * @return The Java object returned by the JavaScript function.
138: */
139: public synchronized Object call(String name, Object a, Object b,
140: Object c) throws Throwable {
141: Call call = resin.getCall();
142: call.caller = call;
143: call.top = 1;
144: call.setArg(-1, global);
145: call.setArg(0, resin.objectWrap(a));
146: call.setArg(1, resin.objectWrap(b));
147: call.setArg(2, resin.objectWrap(c));
148:
149: Object value = call(getFunction(name), call, 3);
150:
151: resin.freeCall(call);
152:
153: return value;
154: }
155:
156: /**
157: * Calls the JavaScript function 'name' with four arguments.
158: * <p>Arguments are automatically wrapped, and return values automatically
159: * unwrapped.
160: *
161: * @param name JavaScript function name.
162: * @param a First argument passed to JavaScript.
163: * @param b Second argument passed to JavaScript.
164: * @param c Third argument passed to JavaScript.
165: * @param d Fourth argument passed to JavaScript.
166: * @return The Java object returned by the JavaScript function.
167: */
168: public synchronized Object call(String name, Object a, Object b,
169: Object c, Object d) throws Throwable {
170: Call call = resin.getCall();
171: call.caller = call;
172: call.top = 1;
173: call.setArg(-1, global);
174: call.setArg(0, resin.objectWrap(a));
175: call.setArg(1, resin.objectWrap(b));
176: call.setArg(2, resin.objectWrap(c));
177: call.setArg(3, resin.objectWrap(d));
178:
179: Object value = call(getFunction(name), call, 4);
180:
181: resin.freeCall(call);
182:
183: return value;
184: }
185:
186: /**
187: * Calls the JavaScript function 'name' with an array of arguments.
188: * <p>Arguments are automatically wrapped, and return values automatically
189: * unwrapped.
190: *
191: * @param name JavaScript function name.
192: * @param args Arguments to pass to the JavaScript function.
193: * @return The Java object returned by the JavaScript function.
194: */
195: public synchronized Object call(String name, Object[] args)
196: throws Throwable {
197: Call call = resin.getCall();
198: call.caller = call;
199: call.setArg(0, global);
200: call.top = 1;
201: for (int i = 0; i < args.length; i++)
202: call.setArg(i, resin.objectWrap(args[i]));
203:
204: Object value = call(getFunction(name), call, args.length);
205:
206: resin.freeCall(call);
207:
208: return value;
209: }
210:
211: private ESClosure getFunction(String name) throws Throwable {
212: ESBase fun = global.hasProperty(ESString.create(name));
213:
214: if (fun == null)
215: throw new ESException("no such function `" + name + "'");
216:
217: if (!(fun instanceof ESClosure))
218: throw new ESException(name + " should be function: " + fun);
219:
220: return (ESClosure) fun;
221: }
222:
223: private Object call(ESClosure closure, Call call, int length)
224: throws Throwable {
225: int scopeLength = closure.scopeLength;
226: call.scopeLength = scopeLength;
227: for (int i = 0; i < scopeLength; i++)
228: call.scope[i] = closure.scope[i];
229:
230: /* XXX: use this to test the test.
231: call.scopeLength = closure.scopeLength;
232: call.scope = closure.scope;
233: */
234:
235: boolean doExit = Exit.addExit();
236: Global old = resin.begin();
237: try {
238: ESBase value = closure.call(call, length);
239:
240: return value == null ? null : value.toJavaObject();
241: } finally {
242: resin.end(old);
243: if (doExit)
244: Exit.exit();
245: }
246: }
247:
248: /**
249: * Returns a global property of the closure.
250: *
251: * @param name name of the global property
252: * @return unwrapped Java object of the global property.
253: */
254: public synchronized Object getProperty(String name) {
255: try {
256: ESBase object = global.getProperty(name);
257:
258: return object.toJavaObject();
259: } catch (Throwable e) {
260: return null;
261: }
262: }
263:
264: /**
265: * Sets a global property of the closure.
266: *
267: * @param name name of the global property
268: * @param value Java object to assign to the global property.
269: */
270: public synchronized void setProperty(String name, Object value) {
271: try {
272: global.setProperty(name, resin.objectWrap(value));
273: } catch (Throwable e) {
274: }
275: }
276: }
|