View Javadoc

1   /**
2    * Copyright 2005-2006 the original author or authors.
3    *
4    * Licensed under the Gnu General Pubic License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    *
8    *      http://www.opensource.org/licenses/gpl-license.php
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13   * See the Gnu General Public License for more details.
14   */
15  package org.figure8.join.services.scripting.groovy;
16  
17  import org.figure8.join.core.InvalidParameterException;
18  import org.figure8.join.services.scripting.ScriptLauncher;
19  import org.figure8.join.services.scripting.ScriptException;
20  import org.figure8.join.util.LogUtil;
21  
22  import groovy.lang.Script;
23  import groovy.lang.Binding;
24  import groovy.lang.GroovyShell;
25  import org.apache.commons.logging.Log;
26  import org.codehaus.groovy.control.CompilationFailedException;
27  
28  import java.io.IOException;
29  import java.io.PrintWriter;
30  import java.util.Properties;
31  import java.util.Enumeration;
32  /**
33   * Extension of {@link ScriptLauncher} dedicated to the Groovy script
34   * language (see http://groovy.codehaus.org). This implementation lets
35   * you wrap the execution of a Groovy script within a ScriptLauncher.
36   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
37   * @version $Revision: 1.2 $
38   */
39  public class GroovyScriptLauncher extends ScriptLauncher{
40  
41     // Static -------------------------------------------------------------------
42  
43     /** Get a commons logger. */
44     private static final Log log = LogUtil.getLog(GroovyScriptLauncher.class);
45  
46  
47     // Attributes ---------------------------------------------------------------
48  
49     /** A handler on parsed script file (for optimization) */
50     private Script groovyScript = null;
51     /** Copy of base class value (for optimization on parsing) */
52     private String scriptPath = super.getScriptPath();
53  
54  
55     // Constructors -------------------------------------------------------------
56  
57     /** Creates a new instance of GroovyScriptLauncher. */
58     public GroovyScriptLauncher(){
59     }
60  
61     /**
62      * Creates a new instance of GroovyScriptLauncher with script path.
63      * @param scriptPath the path of script to later execute
64      * @throws InvalidParameterException if path cannot be accessed
65      */
66     public GroovyScriptLauncher(String scriptPath) throws InvalidParameterException{
67        super(scriptPath);
68     }
69  
70  
71     // Implementation of ScriptLauncher -----------------------------------------
72  
73     /**
74      * Run the Groovy script file identified by <code>scriptPath</code> inner
75      * field. Properties passed as param are injected into the Groovy script
76      * as binding properties. Script can directly use them using the ${property_name}
77      * form. <b>Warning: </b> "." in properties keys passing in are modified
78      * into "_" before injected. This is necessary because "." as special meaning
79      * in Groovy (nested field) that we don't want to have here.
80      * @param properties
81      */
82     public void runScript(Properties properties) throws ScriptException{
83        // Prepare a writer for logging.
84        PrintWriter writer = null;
85        try{
86           // Parse script file only if necessary.
87           if (scriptHasChanged()){
88              // Create new shell & script.
89              Thread th = Thread.currentThread();
90              GroovyShell shell = new GroovyShell(th.getContextClassLoader());
91              log.info("Parsing Groovy script '" + getScript().getPath() + "'");
92              groovyScript = shell.parse(getScript());
93           }
94  
95           // Create and fill Binding.
96           Binding binding = new Binding();
97           Enumeration keys = properties.keys();
98           while (keys != null && keys.hasMoreElements()){
99              String key = (String)keys.nextElement();
100             String value = properties.getProperty(key);
101             // Dot represents a nested field in groovy,
102             // replace dot by underscore into property names.
103             if (log.isDebugEnabled())
104                log.debug("Adding property '" + key.replace('.', '_') + "' (" + value + ") as binding property");
105             binding.setProperty(key.replace('.', '_'), value);
106          }
107 
108          // Use a logger if output stream is available.
109          if (getLogOutputStream() != null){
110             writer = new PrintWriter(getLogOutputStream());
111             binding.setVariable("out", writer);
112          }
113 
114          // Launch execution.
115          groovyScript.setBinding(binding);
116          groovyScript.run();
117       }
118       catch (CompilationFailedException cfe){
119          // Log and wrap into a ScriptException.
120          log.error("The compilation of '" + scriptPath + "' Groovy script failed !");
121          log.error("Here's the detailed message: " + cfe.getMessage());
122          throw new ScriptException("Compilation of Groovy script failed", cfe);
123       }
124       catch (IOException ioe){
125          // Log and wrap into a ScriptException.
126          log.error("IOException while accessing Groovy script '" + scriptPath + "'");
127          throw new ScriptException("IOException while accessing Groovy script", ioe);
128       }
129       finally{
130          // Close writer on log file.
131          if (writer != null)
132             writer.close();
133       }
134    }
135 
136 
137    // Private ------------------------------------------------------------------
138 
139    /** @return True if script has changed since last parsing */
140    private boolean scriptHasChanged(){
141       // Has path to script file changed ?
142       if (groovyScript== null || !getScriptPath().equals(scriptPath)){
143          log.info("Script has changed, getting " + getScriptPath());
144          scriptPath = getScriptPath();
145          return true;
146       }
147       return false;
148    }
149 }