|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
GroovyScriptEngine.java | 0% | 0% | 0% | 0% |
|
1 |
/*
|
|
2 |
* $Id: GroovyScriptEngine.java,v 1.4 2004/04/19 07:29:43 cpoirier 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;
|
|
41 |
import java.io.File;
|
|
42 |
import java.io.IOException;
|
|
43 |
import java.io.InputStreamReader;
|
|
44 |
import java.net.MalformedURLException;
|
|
45 |
import java.net.URL;
|
|
46 |
import java.net.URLConnection;
|
|
47 |
import java.security.AccessController;
|
|
48 |
import java.security.PrivilegedAction;
|
|
49 |
import java.util.Collections;
|
|
50 |
import java.util.HashMap;
|
|
51 |
import java.util.Iterator;
|
|
52 |
import java.util.Map;
|
|
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 | 0 |
public static void main(String[] args) throws Exception { |
73 | 0 |
URL[] roots = new URL[args.length];
|
74 | 0 |
for (int i = 0; i < roots.length; i++) { |
75 | 0 |
roots[i] = new File(args[i]).toURL();
|
76 |
} |
|
77 | 0 |
GroovyScriptEngine gse = new GroovyScriptEngine(roots);
|
78 | 0 |
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); |
79 | 0 |
String line; |
80 | 0 |
while (true) { |
81 | 0 |
System.out.print("groovy> ");
|
82 | 0 |
if ((line = br.readLine()) == null || line.equals("quit")) |
83 | 0 |
break;
|
84 | 0 |
try {
|
85 | 0 |
System.out.println(gse.run(line, new Binding()));
|
86 |
} catch (Exception e) {
|
|
87 | 0 |
e.printStackTrace(); |
88 |
} |
|
89 |
} |
|
90 |
} |
|
91 |
|
|
92 |
private URL[] roots;
|
|
93 |
private Map scriptCache = Collections.synchronizedMap(new HashMap()); |
|
94 |
private ResourceConnector rc;
|
|
95 |
|
|
96 |
private static class ScriptCacheEntry { |
|
97 |
private Class scriptClass;
|
|
98 |
private long lastModified; |
|
99 |
private Map dependencies = new HashMap(); |
|
100 |
} |
|
101 |
|
|
102 | 0 |
public URLConnection getResourceConnection(String resourceName) throws ResourceException { |
103 |
// Get the URLConnection
|
|
104 | 0 |
URLConnection groovyScriptConn = null;
|
105 |
|
|
106 | 0 |
ResourceException se = null;
|
107 | 0 |
for (int i = 0; i < roots.length; i++) { |
108 | 0 |
URL scriptURL = null;
|
109 | 0 |
try {
|
110 | 0 |
scriptURL = new URL(roots[i], resourceName);
|
111 | 0 |
groovyScriptConn = scriptURL.openConnection(); |
112 |
} catch (MalformedURLException e) {
|
|
113 | 0 |
String message = "Malformed URL: " + roots[i] + ", " + resourceName; |
114 | 0 |
if (se == null) { |
115 | 0 |
se = new ResourceException(message);
|
116 |
} else {
|
|
117 | 0 |
se = new ResourceException(message, se);
|
118 |
} |
|
119 |
} catch (IOException e1) {
|
|
120 | 0 |
String message = "Cannot open URL: " + scriptURL;
|
121 | 0 |
if (se == null) { |
122 | 0 |
se = new ResourceException(message);
|
123 |
} else {
|
|
124 | 0 |
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 | 0 |
if (groovyScriptConn == null) { |
133 | 0 |
throw se;
|
134 |
} |
|
135 |
|
|
136 | 0 |
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 | 0 |
public GroovyScriptEngine(URL[] roots) {
|
145 | 0 |
this.roots = roots;
|
146 | 0 |
this.rc = this; |
147 |
} |
|
148 |
|
|
149 | 0 |
public GroovyScriptEngine(String[] args) throws IOException { |
150 | 0 |
URL[] roots = new URL[args.length];
|
151 | 0 |
for (int i = 0; i < roots.length; i++) { |
152 | 0 |
roots[i] = new File(args[i]).toURL();
|
153 |
} |
|
154 | 0 |
this.rc = this; |
155 |
} |
|
156 |
|
|
157 | 0 |
public GroovyScriptEngine(String arg) throws IOException { |
158 | 0 |
this.roots = new URL[1]; |
159 | 0 |
roots[0] = new File(arg).toURL();
|
160 | 0 |
this.rc = this; |
161 |
} |
|
162 |
|
|
163 | 0 |
public GroovyScriptEngine(ResourceConnector rc) {
|
164 | 0 |
this.rc = rc;
|
165 |
} |
|
166 |
|
|
167 | 0 |
public String run(String script, String argument) throws ResourceException, ScriptException { |
168 | 0 |
Binding binding = new Binding();
|
169 | 0 |
binding.setVariable("arg", argument);
|
170 | 0 |
Object result = run(script, binding); |
171 | 0 |
return result == null ? "" : result.toString(); |
172 |
} |
|
173 |
|
|
174 | 0 |
public Object run(String script, Binding binding) throws ResourceException, ScriptException { |
175 |
|
|
176 | 0 |
ScriptCacheEntry entry; |
177 |
|
|
178 | 0 |
script = script.intern(); |
179 | 0 |
synchronized (script) {
|
180 |
|
|
181 | 0 |
URLConnection groovyScriptConn = rc.getResourceConnection(script); |
182 |
|
|
183 |
// URL last modified
|
|
184 | 0 |
long lastModified = groovyScriptConn.getLastModified();
|
185 |
// Check the cache for the script
|
|
186 | 0 |
entry = (ScriptCacheEntry) scriptCache.get(script); |
187 |
// If the entry isn't null check all the dependencies
|
|
188 | 0 |
boolean dependencyOutOfDate = false; |
189 | 0 |
if (entry != null) { |
190 | 0 |
for (Iterator i = entry.dependencies.keySet().iterator(); i.hasNext();) {
|
191 | 0 |
URLConnection urlc = null;
|
192 | 0 |
URL url = (URL) i.next(); |
193 | 0 |
try {
|
194 | 0 |
urlc = url.openConnection(); |
195 | 0 |
urlc.setDoInput(false);
|
196 | 0 |
urlc.setDoOutput(false);
|
197 | 0 |
long dependentLastModified = urlc.getLastModified();
|
198 | 0 |
if (dependentLastModified > ((Long) entry.dependencies.get(url)).longValue()) {
|
199 | 0 |
dependencyOutOfDate = true;
|
200 | 0 |
break;
|
201 |
} |
|
202 |
} catch (IOException ioe) {
|
|
203 | 0 |
dependencyOutOfDate = true;
|
204 | 0 |
break;
|
205 |
} |
|
206 |
} |
|
207 |
} |
|
208 |
|
|
209 | 0 |
if (entry == null || entry.lastModified < lastModified || dependencyOutOfDate) { |
210 |
// Make a new entry
|
|
211 | 0 |
entry = new ScriptCacheEntry();
|
212 |
|
|
213 |
// Closure variable
|
|
214 | 0 |
final ScriptCacheEntry finalEntry = entry; |
215 |
|
|
216 |
// Compile the script into an object
|
|
217 | 0 |
GroovyClassLoader groovyLoader = |
218 |
(GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
|
|
219 | 0 |
public Object run() {
|
220 | 0 |
return new GroovyClassLoader(getClass().getClassLoader()) { |
221 | 0 |
protected Class findClass(String className) throws ClassNotFoundException { |
222 | 0 |
String filename = className.replace('.', File.separatorChar) + ".groovy";
|
223 | 0 |
URLConnection dependentScriptConn = null;
|
224 | 0 |
try {
|
225 | 0 |
dependentScriptConn = rc.getResourceConnection(filename); |
226 | 0 |
finalEntry.dependencies.put( |
227 |
dependentScriptConn.getURL(), |
|
228 |
new Long(dependentScriptConn.getLastModified()));
|
|
229 |
} catch (ResourceException e1) {
|
|
230 | 0 |
throw new ClassNotFoundException("Could not read " + className + ": " + e1); |
231 |
} |
|
232 | 0 |
try {
|
233 | 0 |
return parseClass(dependentScriptConn.getInputStream(), filename);
|
234 |
} catch (CompilationFailedException e2) {
|
|
235 | 0 |
throw new ClassNotFoundException("Syntax error in " + className + ": " + e2); |
236 |
} catch (IOException e2) {
|
|
237 | 0 |
throw new ClassNotFoundException("Problem reading " + className + ": " + e2); |
238 |
} |
|
239 |
} |
|
240 |
}; |
|
241 |
} |
|
242 |
}); |
|
243 |
|
|
244 | 0 |
try {
|
245 | 0 |
entry.scriptClass = groovyLoader.parseClass(groovyScriptConn.getInputStream(), script); |
246 |
} catch (Exception e) {
|
|
247 | 0 |
throw new ScriptException("Could not parse script: " + script, e); |
248 |
} |
|
249 | 0 |
entry.lastModified = lastModified; |
250 | 0 |
scriptCache.put(script, entry); |
251 |
} |
|
252 |
} |
|
253 | 0 |
Script scriptObject = InvokerHelper.createScript(entry.scriptClass, binding); |
254 | 0 |
return scriptObject.run();
|
255 |
} |
|
256 |
} |
|
257 |
|
|