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.ant;
16  
17  import org.figure8.join.core.ParameterDefinition;
18  import org.figure8.join.core.InvalidParameterException;
19  import org.figure8.join.services.scripting.ScriptLauncher;
20  import org.figure8.join.services.scripting.ScriptException;
21  import org.figure8.join.util.LogUtil;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.tools.ant.Project;
25  import org.apache.tools.ant.ProjectHelper;
26  import org.apache.tools.ant.BuildLogger;
27  import org.apache.tools.ant.DefaultLogger;
28  import org.apache.tools.ant.BuildException;
29  
30  import java.io.File;
31  import java.io.PrintStream;
32  import java.io.OutputStream;
33  import java.util.List;
34  import java.util.Iterator;
35  import java.util.ArrayList;
36  import java.util.Properties;
37  /**
38   * Extension of {@link ScriptLauncher} dedicated to the Apache Ant build
39   * tool (see http://ant.apache.org). This implementation lets you wrap the
40   * execution of an Ant script within a ScriptLauncher.<br/>
41   * As a {@link org.figure8.join.core.Configurable} implementation, this
42   * launcher defines 2 more configurable parameters that are the build file
43   * target to execute and the log level to apply onto the logger build listener.
44   *
45   * @see org.figure8.join.core.Configurable
46   *
47   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
48   * @version $Revision: 1.2 $
49   */
50  public class AntScriptLauncher extends ScriptLauncher{
51  
52     // Static -------------------------------------------------------------------
53  
54     /** Get a commons logger. */
55     private static final Log log = LogUtil.getLog(AntScriptLauncher.class);
56  
57     /** Name of configurable parameter denoting the target to execute in Ant script. */
58     public static final String TARGET_PARAM = "target";
59     /** Name of configurable parameter denoting the log level of script execution. */
60     public static final String LOG_LEVEL_PARAM = "logLevel";
61  
62     /** List of {@link ParameterDefinition}s supported by this launcher */
63     protected static List parameters = new ArrayList();
64  
65     /** ParameterDefinition representation of parameter denoting the target to execute. */
66     protected static final ParameterDefinition targetParam = new ParameterDefinition(TARGET_PARAM,
67             "The target to execute in Ant script", "default", false);
68     /** ParameterDefinition representation of parameter denoting the log level of execution. */
69     protected static final ParameterDefinition logLevelParam = new ParameterDefinition(LOG_LEVEL_PARAM,
70             "The level of logging for script execution", "info", false);
71  
72  
73     // Attributes ---------------------------------------------------------------
74  
75     /** The target to execute in Ant script. */
76     private String target;
77     /** The level of log during execution. */
78     private String logLevel;
79  
80  
81     // Constructors -------------------------------------------------------------
82  
83     /** Create a new instance of AntScriptLauncher. */
84     public AntScriptLauncher(){
85     }
86  
87     /**
88      * Creates a new instance of AntScriptLauncher with script path
89      * @param scriptPath the path of script to later execute
90      * @throws InvalidParameterException if path cannot be accessed
91      */
92     public AntScriptLauncher(String scriptPath) throws InvalidParameterException{
93        super(scriptPath);
94     }
95  
96  
97     // Public -------------------------------------------------------------------
98  
99     /** @return The target to execute in Ant script */
100    public String getTarget(){
101       return target;
102    }
103    /** @param target The target to execute in Ant script */
104    public void setTarget(String target){
105       this.target = target;
106    }
107 
108    /** @return The level of log during execution */
109    public String getLogLevel(){
110       return logLevel;
111    }
112    /** @param logLevel The level of log during execution */
113    public void setLogLevel(String logLevel){
114       this.logLevel = logLevel;
115    }
116 
117 
118    // Implementation of ScriptLauncher -----------------------------------------
119 
120    /**
121     * Run the Ant build file identified by <code>scriptPath</code> inner
122     * field. Properties passed as param are injected into the Ant project
123     * as user properties. Script can directly use them using the ${property.name}
124     * form.
125     * @param properties The runtime properties to inject into execution environment
126     * @throws ScriptException if something wrong occurs during script parsing, evaluation, ...
127     */
128    public void runScript(Properties properties) throws ScriptException{
129 
130       // Build a new project using thread context class loader.
131       Project project = new Project();
132       project.setCoreLoader(Thread.currentThread().getContextClassLoader());
133 
134       File buildFile = getScript();
135       Throwable exception = null;
136       try{
137          // Configure and init project using build file.
138          ProjectHelper.configureProject(project, buildFile);
139          project.init();
140 
141          // Set user defined properties
142          Iterator keys = properties.keySet().iterator();
143          while (keys != null && keys.hasNext()){
144             String key = (String)keys.next();
145             String value = properties.getProperty(key);
146             if (log.isDebugEnabled())
147                log.debug("Adding property '" + key + "' (" + value + ") as project property");
148             project.setUserProperty(key, value);
149          }
150 
151          // Create a logger if output stream if available.
152          if (getLogOutputStream() != null)
153             addBuildListener(project, getLogOutputStream());
154 
155          // Make sure we have a target to execute.
156          if (target == null || target.trim().length() == 0)
157             target = project.getDefaultTarget();
158 
159          // Launch execution.
160          project.fireBuildStarted();
161          project.executeTarget(target);
162       }
163       catch (BuildException be){
164          exception = be;
165          // Log and propagate exception into a wrapped ScriptException.
166          log.error("BuildException during initialization or evaluation of script '" + getScriptPath() + "'");
167          log.error("Here's the detailed exception message: " + be.getMessage() + " @ " + be.getLocation());
168          throw new ScriptException("BuildException: " + be.getMessage() + " @ " + be.getLocation());
169       }
170       finally{
171          // Set the build as finished.
172          project.fireBuildFinished(exception);
173          // Output stream may still be open.
174          if (getLogOutputStream() != null){
175             try {getLogOutputStream().close();}
176             catch (Exception e){
177                log.warn("Exception while closing the log output stream: " + e.getMessage());
178             }
179          }
180       }
181    }
182 
183 
184    // Override of ScriptLauncher -----------------------------------------------
185 
186    /**
187     * Get this object parameters definitions as a list
188     * @return A list of {@code ParameterDefinition} objects
189     */
190    public List getParameterDefinitionsAsList(){
191       // Use super parameters as base.
192       if (parameters.isEmpty()){
193          parameters.addAll(super.getParameterDefinitionsAsList());
194          parameters.add(targetParam);
195          parameters.add(logLevelParam);
196       }
197       return parameters;
198    }
199 
200    /**
201     * Set the value of a parameter using its nama
202     * @param parameterName The name of parameter so set value for
203     * @param parameterValue The value of the paramater
204     * @throws org.figure8.join.core.InvalidParameterException if this parameter is not supported by this object
205     */
206    public void setParameter(String parameterName, String parameterValue) throws InvalidParameterException{
207       try{
208          // Delegate to base class first.
209          super.setParameter(parameterName, parameterValue);
210       }
211       catch (InvalidParameterException ipe){
212          // Then test the managed parameters.
213          if (TARGET_PARAM.equals(parameterName))
214             setTarget(parameterValue);
215          else if (LOG_LEVEL_PARAM.equals(parameterName))
216             setLogLevel(parameterValue);
217          else{
218             log.warn("The parameter '" + parameterName + "' is not supported by AntScriptLauncher");
219             throw new InvalidParameterException("The parameter '" + parameterName + "' is not supported by AntScriptLauncher");
220          }
221       }
222    }
223 
224 
225    // Private ------------------------------------------------------------------
226 
227    /**
228     * Add a build listener to the specified project. This build listener
229     * is the Ant default logger which output stream points to specified file.
230     * @param project The project to add listeners to. Must not be null.
231     * @param os The output stream that stores log messages.
232     */
233    private void addBuildListener(Project project, OutputStream os){
234       // Get a print stream.
235       PrintStream out = new PrintStream(os);
236       // Find appropriate log level (default is info).
237       int outputLevel = Project.MSG_INFO;
238       if ("debug".equalsIgnoreCase(logLevel))
239          outputLevel = Project.MSG_DEBUG;
240       else if ("info".equalsIgnoreCase(logLevel))
241          outputLevel = Project.MSG_INFO;
242       else if ("quiet".equalsIgnoreCase(logLevel))
243          outputLevel = Project.MSG_WARN;
244       else if ("verbose".equalsIgnoreCase(logLevel))
245          outputLevel = Project.MSG_VERBOSE;
246 
247       // Build a default logger.
248       BuildLogger logger = new DefaultLogger();
249       logger.setMessageOutputLevel(outputLevel);
250       logger.setOutputPrintStream(out);
251       logger.setErrorPrintStream(out);
252       logger.setEmacsMode(false);
253       // Add the default logger.
254       project.addBuildListener(logger);
255    }
256 }