View Javadoc

1   /*
2    $Id: Groovy.java,v 1.6 2005/07/18 22:11:48 glaforge Exp $
3   
4    Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  
47  package org.codehaus.groovy.ant;
48  
49  import groovy.lang.GroovyShell;
50  import groovy.lang.Script;
51  import groovy.util.AntBuilder;
52  
53  import java.io.BufferedOutputStream;
54  import java.io.BufferedReader;
55  import java.io.File;
56  import java.io.FileOutputStream;
57  import java.io.FileReader;
58  import java.io.IOException;
59  import java.io.PrintStream;
60  import java.io.Reader;
61  import java.lang.reflect.Field;
62  import java.util.Hashtable;
63  import java.util.Vector;
64  
65  import org.apache.tools.ant.BuildException;
66  import org.apache.tools.ant.DirectoryScanner;
67  import org.apache.tools.ant.Project;
68  import org.apache.tools.ant.Task;
69  import org.apache.tools.ant.types.FileSet;
70  import org.apache.tools.ant.types.Path;
71  import org.apache.tools.ant.types.Reference;
72  import org.codehaus.groovy.control.CompilationFailedException;
73  import org.codehaus.groovy.runtime.InvokerHelper;
74  
75  /***
76   * Executes a series of Groovy statements.
77   *
78   * <p>Statements can
79   * either be read in from a text file using the <i>src</i> attribute or from
80   * between the enclosing groovy tags.</p>
81   *
82   *
83   * Based heavily on SQLExec.java which is part of apache-ant
84   * http://cvs.apache.org/viewcvs.cgi/ant/src/main/org/apache/tools/ant/taskdefs/SQLExec.java?rev=MAIN
85   *
86   * Copyright  2000-2005 The Apache Software Foundation
87   *
88   *  Licensed under the Apache License, Version 2.0 (the "License");
89   *  you may not use this file except in compliance with the License.
90   *  You may obtain a copy of the License at
91   *
92   *      http://www.apache.org/licenses/LICENSE-2.0
93   *
94   *  Unless required by applicable law or agreed to in writing, software
95   *  distributed under the License is distributed on an "AS IS" BASIS,
96   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
97   *  See the License for the specific language governing permissions and
98   *  limitations under the License.
99   *
100  *
101  */
102 public class Groovy extends Task {
103     /***
104      * files to load
105      */
106     private Vector filesets = new Vector();
107 
108     /***
109      * input file
110      */
111     private File srcFile = null;
112 
113     /***
114      * input command
115      */
116     private String command = "";
117 
118     /***
119      * Print results.
120      */
121     private boolean print = false;
122 
123     /***
124      * Results Output file.
125      */
126     private File output = null;
127 
128     /***
129      * Append to an existing file or overwrite it?
130      */
131     private boolean append = false;
132 
133     /***
134      * Used for caching loaders / driver. This is to avoid
135      * getting an OutOfMemoryError when calling this task
136      * multiple times in a row.
137      */
138     private static Hashtable loaderMap = new Hashtable(3);
139 
140     private Path classpath;
141 
142     /***
143      * User name.
144      */
145     private String userId = null;
146 
147     /***
148      * Groovy Version needed for this collection of statements.
149      **/
150     private String version = null;
151 
152 
153     /***
154      * Set the name of the file to be run.
155      * Required unless statements are enclosed in the build file
156      */
157     public void setSrc(File srcFile) {
158         this.srcFile = srcFile;
159     }
160 
161     /***
162      * Set an inline command to execute.
163      * NB: Properties are not expanded in this text.
164      */
165     public void addText(String txt) {
166         log("addText('"+txt+"')", Project.MSG_VERBOSE);
167         this.command += txt;
168     }
169 
170     /***
171      * Adds a set of files (nested fileset attribute).
172      */
173     public void addFileset(FileSet set) {
174         filesets.addElement(set);
175     }
176 
177     /***
178      * Print results from the statements;
179      * optional, default false
180      */
181     public void setPrint(boolean print) {
182         this.print = print;
183     }
184 
185     /***
186      * Set the output file;
187      * optional, defaults to the Ant log.
188      */
189     public void setOutput(File output) {
190         this.output = output;
191     }
192 
193     /***
194      * whether output should be appended to or overwrite
195      * an existing file.  Defaults to false.
196      *
197      * @since Ant 1.5
198      */
199     public void setAppend(boolean append) {
200         this.append = append;
201     }
202 
203 
204     /***
205      * Sets the classpath for loading.
206      * @param classpath The classpath to set
207      */
208     public void setClasspath(Path classpath) {
209         this.classpath = classpath;
210     }
211 
212     /***
213      * Add a path to the classpath for loading.
214      */
215     public Path createClasspath() {
216         if (this.classpath == null) {
217             this.classpath = new Path(getProject());
218         }
219         return this.classpath.createPath();
220     }
221 
222     /***
223      * Set the classpath for loading
224      * using the classpath reference.
225      */
226     public void setClasspathRef(Reference r) {
227         createClasspath().setRefid(r);
228     }
229 
230     /***
231      * Sets the version string, execute task only if
232      * groovy version match; optional.
233      * @param version The version to set
234      */
235     public void setVersion(String version) {
236         this.version = version;
237     }
238 
239 
240     protected static Hashtable getLoaderMap() {
241         return loaderMap;
242     }
243 
244 
245 
246 
247     /***
248      * Gets the classpath.
249      * @return Returns a Path
250      */
251     public Path getClasspath() {
252         return classpath;
253     }
254 
255     /***
256      * Gets the userId.
257      * @return Returns a String
258      */
259     public String getUserId() {
260         return userId;
261     }
262 
263     /***
264      * Set the user name for the connection; required.
265      * @param userId The userId to set
266      */
267     public void setUserid(String userId) {
268         this.userId = userId;
269     }
270 
271     /***
272      * Gets the version.
273      * @return Returns a String
274      */
275     public String getVersion() {
276         return version;
277     }
278 
279     /***
280      * Load the file and then execute it
281      */
282     public void execute() throws BuildException {
283         log("execute()", Project.MSG_VERBOSE);
284 
285         command = command.trim();
286 
287         try {
288             if (srcFile == null && command.length() == 0
289                 && filesets.isEmpty()) {
290                 throw new BuildException("Source file does not exist!", getLocation());
291             }
292 
293             if (srcFile != null && !srcFile.exists()) {
294                 throw new BuildException("Source file does not exist!", getLocation());
295             }
296 
297             // deal with the filesets
298             for (int i = 0; i < filesets.size(); i++) {
299                 FileSet fs = (FileSet) filesets.elementAt(i);
300                 DirectoryScanner ds = fs.getDirectoryScanner(getProject());
301                 File srcDir = fs.getDir(getProject());
302 
303                 String[] srcFiles = ds.getIncludedFiles();
304             }
305 
306             try {
307                 PrintStream out = System.out;
308                 try {
309                     if (output != null) {
310                         log("Opening PrintStream to output file " + output,
311                             Project.MSG_VERBOSE);
312                         out = new PrintStream(
313                                   new BufferedOutputStream(
314                                       new FileOutputStream(output
315                                                            .getAbsolutePath(),
316                                                            append)));
317                     }
318 
319                     // if there are no groovy statements between the enclosing Groovy tags
320                     // then read groovy statements in from a text file using the src attribute
321                     if (command == null || command.trim().length() == 0) {
322                         command = getText(new BufferedReader(new FileReader(srcFile)));
323                     }
324 
325                     
326                     if (command != null) {
327                         execGroovy(command,out);
328                     } else {
329                         throw new BuildException("Source file does not exist!", getLocation());
330                     }
331 
332                 } finally {
333                     if (out != null && out != System.out) {
334                         out.close();
335                     }
336                 }
337             } catch (IOException e) {
338                 throw new BuildException(e, getLocation());
339             }
340 
341             log("statements executed successfully");
342         } finally{}
343     }
344 
345 
346     private static String getText(BufferedReader reader) throws IOException {
347         StringBuffer answer = new StringBuffer();
348         // reading the content of the file within a char buffer allow to keep the correct line endings
349         char[] charBuffer = new char[4096];
350         int nbCharRead = 0;
351         while ((nbCharRead = reader.read(charBuffer)) != -1) {
352             // appends buffer
353             answer.append(charBuffer, 0, nbCharRead);
354         }
355         reader.close();
356         return answer.toString();
357     }
358 
359 
360     /***
361      * read in lines and execute them
362      */
363     protected void runStatements(Reader reader, PrintStream out)
364         throws IOException {
365         log("runStatements()", Project.MSG_VERBOSE);
366 
367         StringBuffer txt = new StringBuffer();
368         String line = "";
369 
370         BufferedReader in = new BufferedReader(reader);
371 
372         while ((line = in.readLine()) != null) {
373             line = getProject().replaceProperties(line);
374 
375             if (line.indexOf("--") >= 0) {
376                 txt.append("\n");
377             }
378         }
379         // Catch any statements not followed by ;
380         if (!txt.equals("")) {
381             execGroovy(txt.toString(), out);
382         }
383     }
384 
385 
386     /***
387      * Exec the statement.
388      */
389     protected void execGroovy(String txt, PrintStream out) {
390         log("execGroovy()", Project.MSG_VERBOSE);
391 
392         // Check and ignore empty statements
393         if ("".equals(txt.trim())) {
394             return;
395         }
396 
397             log("Groovy: " + txt, Project.MSG_VERBOSE);
398 
399             //log(getClasspath().toString(),Project.MSG_VERBOSE);
400             GroovyShell groovy = new GroovyShell(GroovyShell.class.getClassLoader());
401 
402             try {
403                 Script script = groovy.parse(txt);
404                 Project project = getProject();
405                 script.setProperty("ant", new AntBuilder(project));
406                 script.setProperty("project", project);
407                 script.setProperty("properties", new AntProjectPropertiesDelegate(project));
408                 script.setProperty("target", getOwningTarget());
409                 script.setProperty("task", this);
410 
411                 // treat the case Ant is run through Maven, and
412                 if ("org.apache.commons.grant.GrantProject".equals(project.getClass().getName())) {
413                     try {
414                         Object propsHandler = project.getClass().getMethod("getPropsHandler", new Class[0]).invoke(project, new Object[0]);
415                         Field contextField = propsHandler.getClass().getDeclaredField("context");
416                         contextField.setAccessible(true);
417                         Object context = contextField.get(propsHandler);
418                         Object mavenPom = InvokerHelper.invokeMethod(context, "getProject", new Object[0]);
419                         script.setProperty("pom", mavenPom);
420                     } catch (Exception e) {
421                         throw new BuildException("Impossible to retrieve Maven's Ant project: " + e.getMessage(), getLocation());
422                     }
423                 }
424 
425                 script.run();
426             } catch (CompilationFailedException e) {
427                 throw new BuildException("Script Failed: "+ e.getMessage(), getLocation());
428             }
429 
430             if (print) {
431                 StringBuffer line = new StringBuffer();
432                 line.append( " foo bar");
433                 out.println(line);
434             }
435 
436 
437     }
438 
439     /***
440      * print any results in the statement.
441      */
442     protected void printResults(PrintStream out) {
443             log("printResults()", Project.MSG_VERBOSE);
444             StringBuffer line = new StringBuffer();
445             out.println(line);
446             line = new StringBuffer();
447         out.println();
448     }
449 }