KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > es > Script


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.es;
30
31 import com.caucho.java.LineMap;
32 import com.caucho.util.Exit;
33 import com.caucho.vfs.Path;
34
35 import java.util.HashMap JavaDoc;
36
37 /**
38  * The Script object represents a compiled JavaScript. Executing it
39  * is thread safe. To create a Script, use the Parser class to parse
40  * a file.
41  *
42  * <p>Java programs set JavaScript Global properties by adding objects to
43  * a HashMap. Typically you will at least assign the 'File' and
44  * the 'out' objects. The running script will
45  * see these objects as properties of the Global object. If you set the
46  * 'out' object, the script can use the bare bones 'writeln("foo")' to
47  * write to 'out'.
48  *
49  * <pre><code>
50  * HashMap map = new HashMap();
51  * map.put("File", Vfs.lookup());
52  * map.put("out", System.out);
53  * map.put("myObject", myObject);
54  *
55  * script.execute(map, null);
56  * </code></pre>
57  *
58  * <p>You can also make any Java object be the global prototype.
59  * Essentially, the effect is similar to the HashMap technique, but
60  * it's a little simpler.
61  *
62  * <p>Scripts are thread-safe. Multiple script instances can
63  * safely execute in separate threads. Script.execute creates the
64  * entire JavaScript global object hierarchy fresh for each execution.
65  * So one Script execution cannot interfere with another, even by doing
66  * evil things like modifying the Object prototype.
67  *
68  * <p>Of course, wrapped Java objects shared by script invocations
69  * must still be synchronized.
70  */

71
72 abstract public class Script {
73   protected Path scriptPath;
74   protected Path classDir;
75   
76   /**
77    * Internal method to check if the source files have changed.
78    */

79   public boolean isModified()
80   {
81     return true;
82   }
83
84   /**
85    * Internal method to set the script search path for imported
86    * scripts.
87    */

88   public void setScriptPath(Path scriptPath)
89   {
90     this.scriptPath = scriptPath;
91   }
92
93   /**
94    * Internal method to set the work directory for generated *.java
95    * and *.class.
96    */

97   public void setClassDir(Path classDir)
98   {
99     this.classDir = classDir;
100   }
101
102   /**
103    * Returns the map from source file line numbers to the generated
104    * java line numbers.
105    */

106   public LineMap getLineMap()
107   {
108     return null;
109   }
110
111   /**
112    * Execute the script; the main useful entry.
113    *
114    * <p>Calling programs can make Java objects available as properties
115    * of the global object by creating a property hash map or assigning
116    * a global prototype.
117    *
118    * <pre><code>
119    * HashMap map = new HashMap();
120    * map.put("File", Vfs.lookup());
121    * map.put("out", System.out);
122    * map.put("myObject", myObject);
123    * script.execute(map, null);
124    * </code></pre>
125    *
126    * Then the JavaScript can use the defined objects:
127    * <pre><code>
128    * out.println(myObject.myMethod("foo"));
129    * </code></pre>
130    *
131    * @param properties A hash map of global properties.
132    * @param proto Global prototype. Gives the script direct access to
133    * the java methods of the object.
134    *
135    * @return String value of the last expression, like the JavaScript eval.
136    * This is useful only for testing.
137    */

138   public String JavaDoc execute(HashMap JavaDoc properties, Object JavaDoc proto) throws Throwable JavaDoc
139   {
140     Global oldGlobal = Global.getGlobalProto();
141     boolean doExit = Exit.addExit();
142
143     try {
144       Global resin = new Global(properties, proto, classDir,
145                 scriptPath, getClass().getClassLoader());
146     
147       resin.begin();
148       
149       ESGlobal global = initClass(resin);
150
151       ESBase value = global.execute();
152
153       if (value == null)
154     return null;
155       else
156     return value.toStr().toString();
157     } finally {
158       Global.end(oldGlobal);
159       
160       if (doExit)
161         Exit.exit();
162     }
163   }
164   
165   /**
166    * Execute the program, returning a closure of the global state.
167    * <code>executeClosure</code> will execute the global script.
168    *
169    * <p>Later routines can then call into the closure. The closure
170    * is not thread-safe. So only a single thread may execute the
171    * closure.
172    *
173    * @param properties A hash map of global properties.
174    * @param proto Global prototype. Gives the script direct access to
175    * the java methods of the object.
176    *
177    * @return the closure
178    */

179   public ScriptClosure executeClosure(HashMap JavaDoc properties, Object JavaDoc proto)
180     throws Throwable JavaDoc
181   {
182     Global resin = new Global(properties, proto, classDir,
183                               scriptPath, getClass().getClassLoader());
184     boolean doExit = Exit.addExit();
185     Global oldGlobal = resin.begin();
186
187     try {
188       ESGlobal global = initClass(resin);
189
190       global.execute();
191
192       return new ScriptClosure(resin, global, this);
193     } finally {
194       resin.end(oldGlobal);
195       if (doExit)
196     Exit.exit();
197     }
198   }
199
200   /**
201    * Internal method to initialize the script after loading it.
202    */

203   public ESGlobal initClass(Global resin, ESObject global)
204     throws Throwable JavaDoc
205   {
206     return initClass(resin);
207   }
208
209   /**
210    * Internal method implemented by the generated script for initialization.
211    */

212   public abstract ESGlobal initClass(Global resin)
213     throws Throwable JavaDoc;
214
215   /**
216    * Internal method to export objects.
217    */

218   public void export(ESObject dest, ESObject src)
219     throws Throwable JavaDoc
220   {
221   }
222 }
223
Popular Tags