001: package org.openlaszlo.iv.flash.js;
002:
003: import java.io.*;
004: import java.lang.reflect.*;
005: import org.mozilla.javascript.*;
006: import org.mozilla.javascript.serialize.*;
007: import org.mozilla.javascript.tools.shell.Environment;
008:
009: /**
010: * This class provides for sharing functions across multiple threads.
011: * This is of particular interest to server applications.
012: *
013: * @author Norris Boyd
014: * @author Dmitry Skavish
015: */
016: public class Global extends ImporterTopLevel {
017:
018: public Global(Context cx) {
019: this (cx, null);
020: }
021:
022: public Global(Context cx,
023: org.openlaszlo.iv.flash.context.Context genContext) {
024: // Define some global functions particular to the shell. Note
025: // that these functions are not part of ECMA.
026: super (cx);
027:
028: this .genContext = genContext;
029:
030: String[] names = { "print", "println", "version", "load",
031: "loadClass", "defineClass", "spawn", "sync",
032: "serialize", "deserialize", "getVar", "setVar" };
033: try {
034: defineFunctionProperties(names, Global.class,
035: ScriptableObject.DONTENUM);
036: } catch (PropertyException e) {
037: throw new Error(); // shouldn't occur.
038: }
039: defineProperty(privateName, this , ScriptableObject.DONTENUM);
040:
041: // Set up "environment" in the global scope to provide access to the
042: // System environment variables.
043: Environment.defineClass(this );
044: Environment environment = new Environment(this );
045: defineProperty("environment", environment,
046: ScriptableObject.DONTENUM);
047:
048: history = (NativeArray) cx.newArray(this , 0);
049: defineProperty("history", history, ScriptableObject.DONTENUM);
050: }
051:
052: /**
053: * Print the string values of its arguments.
054: *
055: * This method is defined as a JavaScript function.
056: * Note that its arguments are of the "varargs" form, which
057: * allows it to handle an arbitrary number of arguments
058: * supplied to the JavaScript function.
059: *
060: */
061: public static Object print(Context cx, Scriptable this Obj,
062: Object[] args, Function funObj) {
063: PrintStream out = getInstance(this Obj).getOut();
064: for (int i = 0; i < args.length; i++) {
065: // Convert the arbitrary JavaScript value into a string form.
066: String s = Context.toString(args[i]);
067: out.print(s);
068: }
069: return Context.getUndefinedValue();
070: }
071:
072: /**
073: * Println the string values of its arguments.
074: *
075: * This method is defined as a JavaScript function.
076: * Note that its arguments are of the "varargs" form, which
077: * allows it to handle an arbitrary number of arguments
078: * supplied to the JavaScript function.
079: *
080: */
081: public static Object println(Context cx, Scriptable this Obj,
082: Object[] args, Function funObj) {
083: PrintStream out = getInstance(this Obj).getOut();
084: for (int i = 0; i < args.length; i++) {
085: // Convert the arbitrary JavaScript value into a string form.
086: String s = Context.toString(args[i]);
087: out.print(s);
088: }
089: out.println();
090: return Context.getUndefinedValue();
091: }
092:
093: /**
094: * Returns variable from associated generator context
095: */
096: public static Object getVar(Context cx, Scriptable this Obj,
097: Object[] args, Function funObj) {
098: org.openlaszlo.iv.flash.context.Context myContext = (org.openlaszlo.iv.flash.context.Context) getInstance(this Obj).genContext;
099: //System.out.println("getVar: myContext="+myContext+", args.length="+args.length);
100: if (args.length > 0 && myContext != null) {
101: String value = myContext
102: .getValue(Context.toString(args[0]));
103: if (value == null) {
104: return Context.getUndefinedValue();
105: } else {
106: return value;
107: }
108: } else {
109: return Context.getUndefinedValue();
110: }
111: }
112:
113: /**
114: * Sets variable to associated standard generator context
115: */
116: public static Object setVar(Context cx, Scriptable this Obj,
117: Object[] args, Function funObj) {
118: org.openlaszlo.iv.flash.context.Context myContext = (org.openlaszlo.iv.flash.context.Context) getInstance(this Obj).genContext;
119: if (args.length > 1
120: && myContext instanceof org.openlaszlo.iv.flash.context.StandardContext) {
121: org.openlaszlo.iv.flash.context.StandardContext myContext1 = (org.openlaszlo.iv.flash.context.StandardContext) myContext;
122: String name = Context.toString(args[0]);
123: String value = Context.toString(args[1]);
124: myContext1.setValue(name, value);
125: }
126: return Context.getUndefinedValue();
127: }
128:
129: /**
130: * Get and set the language version.
131: *
132: * This method is defined as a JavaScript function.
133: */
134: public static double version(Context cx, Scriptable this Obj,
135: Object[] args, Function funObj) {
136: double result = (double) cx.getLanguageVersion();
137: if (args.length > 0) {
138: double d = cx.toNumber(args[0]);
139: cx.setLanguageVersion((int) d);
140: }
141: return result;
142: }
143:
144: /**
145: * Load and execute a set of JavaScript source files.
146: *
147: * This method is defined as a JavaScript function.
148: *
149: */
150: public static void load(Context cx, Scriptable this Obj,
151: Object[] args, Function funObj) {
152: for (int i = 0; i < args.length; i++) {
153: JSHelper.processFile(cx, this Obj, cx.toString(args[i]));
154: }
155: }
156:
157: /**
158: * Load a Java class that defines a JavaScript object using the
159: * conventions outlined in ScriptableObject.defineClass.
160: * <p>
161: * This method is defined as a JavaScript function.
162: * @exception IllegalAccessException if access is not available
163: * to a reflected class member
164: * @exception InstantiationException if unable to instantiate
165: * the named class
166: * @exception InvocationTargetException if an exception is thrown
167: * during execution of methods of the named class
168: * @exception ClassDefinitionException if the format of the
169: * class causes this exception in ScriptableObject.defineClass
170: * @exception PropertyException if the format of the
171: * class causes this exception in ScriptableObject.defineClass
172: * @see org.mozilla.javascript.ScriptableObject#defineClass
173: */
174: public static void defineClass(Context cx, Scriptable this Obj,
175: Object[] args, Function funObj)
176: throws IllegalAccessException, InstantiationException,
177: InvocationTargetException, ClassDefinitionException,
178: PropertyException {
179: Class clazz = getClass(args);
180: ScriptableObject.defineClass(this Obj, clazz);
181: }
182:
183: /**
184: * Load and execute a script compiled to a class file.
185: * <p>
186: * This method is defined as a JavaScript function.
187: * When called as a JavaScript function, a single argument is
188: * expected. This argument should be the name of a class that
189: * implements the Script interface, as will any script
190: * compiled by jsc.
191: *
192: * @exception IllegalAccessException if access is not available
193: * to the class
194: * @exception InstantiationException if unable to instantiate
195: * the named class
196: * @exception InvocationTargetException if an exception is thrown
197: * during execution of methods of the named class
198: * @exception JavaScriptException if a JavaScript exception is thrown
199: * during execution of the compiled script
200: * @see org.mozilla.javascript.ScriptableObject#defineClass
201: */
202: public static void loadClass(Context cx, Scriptable this Obj,
203: Object[] args, Function funObj)
204: throws IllegalAccessException, InstantiationException,
205: InvocationTargetException, JavaScriptException {
206: Class clazz = getClass(args);
207: if (!Script.class.isAssignableFrom(clazz)) {
208: throw Context.reportRuntimeError(IVErrorReporter
209: .getMessage("msg.must.implement.Script"));
210: }
211: Script script = (Script) clazz.newInstance();
212: script.exec(cx, this Obj);
213: }
214:
215: private static Class getClass(Object[] args)
216: throws IllegalAccessException, InstantiationException,
217: InvocationTargetException {
218: if (args.length == 0) {
219: throw Context.reportRuntimeError(IVErrorReporter
220: .getMessage("msg.expected.string.arg"));
221: }
222: String className = Context.toString(args[0]);
223: try {
224: return Class.forName(className);
225: } catch (ClassNotFoundException cnfe) {
226: throw Context.reportRuntimeError(IVErrorReporter
227: .getMessage("msg.class.not.found", className));
228: }
229: }
230:
231: public static void serialize(Context cx, Scriptable this Obj,
232: Object[] args, Function funObj) throws IOException {
233: if (args.length < 2) {
234: throw Context
235: .reportRuntimeError("Expected an object to serialize and a filename to write "
236: + "the serialization to");
237: }
238: Object obj = args[0];
239: String filename = cx.toString(args[1]);
240: FileOutputStream fos = new FileOutputStream(filename);
241: Scriptable scope = ScriptableObject.getTopLevelScope(this Obj);
242: ScriptableOutputStream out = new ScriptableOutputStream(fos,
243: scope);
244: out.writeObject(obj);
245: out.close();
246: }
247:
248: public static Object deserialize(Context cx, Scriptable this Obj,
249: Object[] args, Function funObj) throws IOException,
250: ClassNotFoundException {
251: if (args.length < 1) {
252: throw Context
253: .reportRuntimeError("Expected a filename to read the serialization from");
254: }
255: String filename = cx.toString(args[0]);
256: FileInputStream fis = new FileInputStream(filename);
257: Scriptable scope = ScriptableObject.getTopLevelScope(this Obj);
258: ObjectInputStream in = new ScriptableInputStream(fis, scope);
259: Object deserialized = in.readObject();
260: in.close();
261: return cx.toObject(deserialized, scope);
262: }
263:
264: /**
265: * The spawn function runs a given function or script in a different
266: * thread.
267: *
268: * js> function g() { a = 7; }
269: * js> a = 3;
270: * 3
271: * js> spawn(g)
272: * Thread[Thread-1,5,main]
273: * js> a
274: * 3
275: */
276: public static Object spawn(Context cx, Scriptable this Obj,
277: Object[] args, Function funObj) {
278: Scriptable scope = funObj.getParentScope();
279: Runner runner;
280: if (args.length != 0 && args[0] instanceof Function) {
281: Object[] newArgs = null;
282: if (args.length > 1 && args[1] instanceof Scriptable) {
283: newArgs = cx.getElements((Scriptable) args[1]);
284: }
285: runner = new Runner(scope, (Function) args[0], newArgs);
286: } else if (args.length != 0 && args[0] instanceof Script) {
287: runner = new Runner(scope, (Script) args[0]);
288: } else {
289: throw Context.reportRuntimeError(IVErrorReporter
290: .getMessage("msg.spawn.args"));
291: }
292: Thread thread = new Thread(runner);
293: thread.start();
294: return thread;
295: }
296:
297: /**
298: * The sync function creates a synchronized function (in the sense
299: * of a Java synchronized method) from an existing function. The
300: * new function synchronizes on the <code>this</code> object of
301: * its invocation.
302: * js> var o = { f : sync(function(x) {
303: * print("entry");
304: * Packages.java.lang.Thread.sleep(x*1000);
305: * print("exit");
306: * })};
307: * js> spawn(function() {o.f(5);});
308: * Thread[Thread-0,5,main]
309: * entry
310: * js> spawn(function() {o.f(5);});
311: * Thread[Thread-1,5,main]
312: * js>
313: * exit
314: * entry
315: * exit
316: */
317: public static Object sync(Context cx, Scriptable this Obj,
318: Object[] args, Function funObj) {
319: if (args.length == 1 && args[0] instanceof Function) {
320: return new Synchronizer((Function) args[0]);
321: } else {
322: throw Context.reportRuntimeError(IVErrorReporter
323: .getMessage("msg.spawn.args"));
324: }
325: }
326:
327: public InputStream getIn() {
328: return inStream == null ? System.in : inStream;
329: }
330:
331: public void setIn(InputStream in) {
332: inStream = in;
333: }
334:
335: public PrintStream getOut() {
336: return outStream == null ? System.out : outStream;
337: }
338:
339: public void setOut(PrintStream out) {
340: outStream = out;
341: }
342:
343: public PrintStream getErr() {
344: return errStream == null ? System.err : errStream;
345: }
346:
347: public void setErr(PrintStream err) {
348: errStream = err;
349: }
350:
351: static final String privateName = "org.openlaszlo.iv.flash.js.Global private";
352:
353: public static Global getInstance(Scriptable scope) {
354: Object v = ScriptableObject.getProperty(scope, privateName);
355: if (v instanceof Global)
356: return (Global) v;
357: return null;
358: }
359:
360: NativeArray history;
361: public InputStream inStream;
362: public PrintStream outStream;
363: public PrintStream errStream;
364: public org.openlaszlo.iv.flash.context.Context genContext;
365: }
366:
367: class Runner implements Runnable {
368:
369: Runner(Scriptable scope, Function func, Object[] args) {
370: this .scope = scope;
371: f = func;
372: this .args = args;
373: }
374:
375: Runner(Scriptable scope, Script script) {
376: this .scope = scope;
377: s = script;
378: }
379:
380: public void run() {
381: Context cx = Context.enter();
382:
383: try {
384: if (f != null)
385: f.call(cx, scope, scope, args);
386: else
387: s.exec(cx, scope);
388: } catch (JavaScriptException e) {
389: Context.reportError(IVErrorReporter.getMessage(
390: "msg.uncaughtJSException", e.getMessage()));
391: }
392:
393: cx.exit();
394: }
395:
396: private Scriptable scope;
397: private Function f;
398: private Script s;
399: private Object[] args;
400: }
|