KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > groovy > util > GroovyScriptEngine


1 /*
2  * $Id: GroovyScriptEngine.java,v 1.6 2005/04/24 05:55:00 spullara Exp $version Jan 9, 2004 12:19:58 PM $user Exp $
3  *
4  * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
5  *
6  * Redistribution and use of this software and associated documentation
7  * ("Software"), with or without modification, are permitted provided that the
8  * following conditions are met: 1. Redistributions of source code must retain
9  * copyright statements and notices. Redistributions must also contain a copy
10  * of this document. 2. Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer in
12  * the documentation and/or other materials provided with the distribution. 3.
13  * The name "groovy" must not be used to endorse or promote products derived
14  * from this Software without prior written permission of The Codehaus. For
15  * written permission, please contact info@codehaus.org. 4. Products derived
16  * from this Software may not be called "groovy" nor may "groovy" appear in
17  * their names without prior written permission of The Codehaus. "groovy" is a
18  * registered trademark of The Codehaus. 5. Due credit should be given to The
19  * Codehaus - http://groovy.codehaus.org/
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
22  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31  * DAMAGE.
32  *
33  */

34 package groovy.util;
35
36 import groovy.lang.Binding;
37 import groovy.lang.GroovyClassLoader;
38 import groovy.lang.Script;
39
40 import java.io.BufferedReader JavaDoc;
41 import java.io.File JavaDoc;
42 import java.io.IOException JavaDoc;
43 import java.io.InputStreamReader JavaDoc;
44 import java.net.MalformedURLException JavaDoc;
45 import java.net.URL JavaDoc;
46 import java.net.URLConnection JavaDoc;
47 import java.security.AccessController JavaDoc;
48 import java.security.PrivilegedAction JavaDoc;
49 import java.util.Collections JavaDoc;
50 import java.util.HashMap JavaDoc;
51 import java.util.Iterator JavaDoc;
52 import java.util.Map JavaDoc;
53
54 import org.codehaus.groovy.control.CompilationFailedException;
55 import org.codehaus.groovy.runtime.InvokerHelper;
56
57 /**
58  * @author sam
59  *
60  * To change the template for this generated type comment go to Window -
61  * Preferences - Java - Code Generation - Code and Comments
62  */

63 public class GroovyScriptEngine implements ResourceConnector {
64
65     /**
66      * Simple testing harness for the GSE. Enter script roots as arguments and
67      * then input script names to run them.
68      *
69      * @param args
70      * @throws Exception
71      */

72     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
73         URL JavaDoc[] roots = new URL JavaDoc[args.length];
74         for (int i = 0; i < roots.length; i++) {
75             roots[i] = new File JavaDoc(args[i]).toURL();
76         }
77         GroovyScriptEngine gse = new GroovyScriptEngine(roots);
78         BufferedReader JavaDoc br = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(System.in));
79         String JavaDoc line;
80         while (true) {
81             System.out.print("groovy> ");
82             if ((line = br.readLine()) == null || line.equals("quit"))
83                 break;
84             try {
85                 System.out.println(gse.run(line, new Binding()));
86             } catch (Exception JavaDoc e) {
87                 e.printStackTrace();
88             }
89         }
90     }
91
92     private URL JavaDoc[] roots;
93     private Map JavaDoc scriptCache = Collections.synchronizedMap(new HashMap JavaDoc());
94     private ResourceConnector rc;
95
96     private static class ScriptCacheEntry {
97         private Class JavaDoc scriptClass;
98         private long lastModified;
99         private Map JavaDoc dependencies = new HashMap JavaDoc();
100     }
101
102     public URLConnection JavaDoc getResourceConnection(String JavaDoc resourceName) throws ResourceException {
103         // Get the URLConnection
104
URLConnection JavaDoc groovyScriptConn = null;
105
106         ResourceException se = null;
107         for (int i = 0; i < roots.length; i++) {
108             URL JavaDoc scriptURL = null;
109             try {
110                 scriptURL = new URL JavaDoc(roots[i], resourceName);
111                 groovyScriptConn = scriptURL.openConnection();
112             } catch (MalformedURLException JavaDoc e) {
113                 String JavaDoc message = "Malformed URL: " + roots[i] + ", " + resourceName;
114                 if (se == null) {
115                     se = new ResourceException(message);
116                 } else {
117                     se = new ResourceException(message, se);
118                 }
119             } catch (IOException JavaDoc e1) {
120                 String JavaDoc message = "Cannot open URL: " + scriptURL;
121                 if (se == null) {
122                     se = new ResourceException(message);
123                 } else {
124                     se = new ResourceException(message, se);
125                 }
126             }
127
128         }
129
130         // If we didn't find anything, report on all the exceptions that
131
// occurred.
132
if (groovyScriptConn == null) {
133             throw se;
134         }
135
136         return groovyScriptConn;
137     }
138
139     /**
140      * The groovy script engine will run groovy scripts and reload them and
141      * their dependencies when they are modified. This is useful for embedding
142      * groovy in other containers like games and application servers.
143      *
144      * @param roots This an array of URLs where Groovy scripts will be stored. They should
145      * be layed out using their package structure like Java classes
146      */

147     public GroovyScriptEngine(URL JavaDoc[] roots) {
148         this.roots = roots;
149         this.rc = this;
150     }
151
152     public GroovyScriptEngine(String JavaDoc[] args) throws IOException JavaDoc {
153         roots = new URL JavaDoc[args.length];
154         for (int i = 0; i < roots.length; i++) {
155             roots[i] = new File JavaDoc(args[i]).toURL();
156         }
157         this.rc = this;
158     }
159
160     public GroovyScriptEngine(String JavaDoc arg) throws IOException JavaDoc {
161         roots = new URL JavaDoc[1];
162         roots[0] = new File JavaDoc(arg).toURL();
163         this.rc = this;
164     }
165
166     public GroovyScriptEngine(ResourceConnector rc) {
167         this.rc = rc;
168     }
169
170     public String JavaDoc run(String JavaDoc script, String JavaDoc argument) throws ResourceException, ScriptException {
171         Binding binding = new Binding();
172         binding.setVariable("arg", argument);
173         Object JavaDoc result = run(script, binding);
174         return result == null ? "" : result.toString();
175     }
176
177     public Object JavaDoc run(String JavaDoc script, Binding binding) throws ResourceException, ScriptException {
178
179         ScriptCacheEntry entry;
180
181         script = script.intern();
182         synchronized (script) {
183
184             URLConnection JavaDoc groovyScriptConn = rc.getResourceConnection(script);
185
186             // URL last modified
187
long lastModified = groovyScriptConn.getLastModified();
188             // Check the cache for the script
189
entry = (ScriptCacheEntry) scriptCache.get(script);
190             // If the entry isn't null check all the dependencies
191
boolean dependencyOutOfDate = false;
192             if (entry != null) {
193                 for (Iterator JavaDoc i = entry.dependencies.keySet().iterator(); i.hasNext();) {
194                     URLConnection JavaDoc urlc = null;
195                     URL JavaDoc url = (URL JavaDoc) i.next();
196                     try {
197                         urlc = url.openConnection();
198                         urlc.setDoInput(false);
199                         urlc.setDoOutput(false);
200                         long dependentLastModified = urlc.getLastModified();
201                         if (dependentLastModified > ((Long JavaDoc) entry.dependencies.get(url)).longValue()) {
202                             dependencyOutOfDate = true;
203                             break;
204                         }
205                     } catch (IOException JavaDoc ioe) {
206                         dependencyOutOfDate = true;
207                         break;
208                     }
209                 }
210             }
211
212             if (entry == null || entry.lastModified < lastModified || dependencyOutOfDate) {
213                 // Make a new entry
214
entry = new ScriptCacheEntry();
215
216                 // Closure variable
217
final ScriptCacheEntry finalEntry = entry;
218
219                 // Compile the script into an object
220
GroovyClassLoader groovyLoader =
221                     (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
222                         public Object JavaDoc run() {
223                             return new GroovyClassLoader(getClass().getClassLoader()) {
224                                 protected Class JavaDoc findClass(String JavaDoc className) throws ClassNotFoundException JavaDoc {
225                                     String JavaDoc filename = className.replace('.', File.separatorChar) + ".groovy";
226                                     URLConnection JavaDoc dependentScriptConn = null;
227                                     try {
228                                         dependentScriptConn = rc.getResourceConnection(filename);
229                                         finalEntry.dependencies.put(
230                                             dependentScriptConn.getURL(),
231                                             new Long JavaDoc(dependentScriptConn.getLastModified()));
232                                     } catch (ResourceException e1) {
233                                         throw new ClassNotFoundException JavaDoc("Could not read " + className + ": " + e1);
234                                     }
235                                     try {
236                                         return parseClass(dependentScriptConn.getInputStream(), filename);
237                                     } catch (CompilationFailedException e2) {
238                                         throw new ClassNotFoundException JavaDoc("Syntax error in " + className + ": " + e2);
239                                     } catch (IOException JavaDoc e2) {
240                                         throw new ClassNotFoundException JavaDoc("Problem reading " + className + ": " + e2);
241                                     }
242                                 }
243                             };
244                         }
245                     });
246
247                 try {
248                     entry.scriptClass = groovyLoader.parseClass(groovyScriptConn.getInputStream(), script);
249                 } catch (Exception JavaDoc e) {
250                     throw new ScriptException("Could not parse script: " + script, e);
251                 }
252                 entry.lastModified = lastModified;
253                 scriptCache.put(script, entry);
254             }
255         }
256         Script scriptObject = InvokerHelper.createScript(entry.scriptClass, binding);
257         return scriptObject.run();
258     }
259 }
260
Popular Tags