View Javadoc

1   /*
2    * Copyright (c) 2006 Israfil Consulting Services Corporation
3    * Copyright (c) 2006 Christian Edward Gruber
4    * All Rights Reserved
5    * 
6    * This software is licensed under the Berkeley Standard Distribution license,
7    * (BSD license), as defined below:
8    * 
9    * Redistribution and use in source and binary forms, with or without 
10   * modification, are permitted provided that the following conditions are met:
11   *
12   * 1. Redistributions of source code must retain the above copyright notice, this 
13   *    list of conditions and the following disclaimer.
14   * 2. Redistributions in binary form must reproduce the above copyright notice, 
15   *    this list of conditions and the following disclaimer in the documentation 
16   *    and/or other materials provided with the distribution.
17   * 3. Neither the name of Israfil Consulting Services nor the names of its contributors 
18   *    may be used to endorse or promote products derived from this software without 
19   *    specific prior written permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
23   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
24   * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
25   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
27   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
30   * OF SUCH DAMAGE.
31   * 
32   * $Id: AbstractFlexMojo.java 610 2008-01-15 16:49:22Z christianedwardgruber $
33   */
34  package net.israfil.mojo.flex2;
35  
36  import java.io.File;
37  import java.io.IOException;
38  import java.io.InputStream;
39  import java.util.ArrayList;
40  import java.util.Arrays;
41  import java.util.Iterator;
42  import java.util.List;
43  
44  import org.apache.maven.artifact.Artifact;
45  import org.apache.maven.plugin.AbstractMojo;
46  import org.apache.maven.plugin.MojoExecutionException;
47  import org.apache.maven.plugin.MojoFailureException;
48  import org.apache.maven.project.MavenProject;
49  import org.apache.maven.project.MavenProjectHelper;
50  import org.codehaus.plexus.util.cli.CommandLineException;
51  import org.codehaus.plexus.util.cli.CommandLineUtils;
52  import org.codehaus.plexus.util.cli.Commandline;
53  import org.codehaus.plexus.util.cli.StreamConsumer;
54  
55  /***
56   * Base class for flex2/actionscript3 plugin
57   *
58   * @author <a href="cgruber@israfil.net">Christian Edward Gruber</a>
59   * @author <a href="tspurway@gmail.com">Tim Spurway</a>
60   * @version $Id: AbstractFlexMojo.java 610 2008-01-15 16:49:22Z christianedwardgruber $
61   */
62  public abstract class AbstractFlexMojo extends AbstractMojo {
63  
64  	/***
65  	 * The directory in which Flex (command-line or builder) is installed.
66  	 * 
67  	 * @parameter expression="${flex.home}"
68  	 * @required 
69  	 * 
70  	 */
71  	protected File flexHome;
72  
73  	/***
74  	 * The location of the flex configuration file.  
75  	 * 
76  	 * @parameter expression="${flex.config}"
77  	 */
78  	protected File flexConfig;
79      
80      /***
81       * Location of the flex sources.
82       *
83       * @parameter expression="${flex.compiler.source}" default="src/main/flex"
84       */
85      protected File source;
86  	
87  	/***
88  	 * The directory into which to place the resulting artifact.  note that this is a read-only 
89  	 * parameter, satisfied from the build directory.  Attempts to configure this should use the 
90  	 * standard &lt;build&gt;&lt;directory/&gt;&lt;/build&gt; approach.
91  	 * 
92  	 * @parameter expression="${project.build.directory}"
93  	 * @required
94  	 * @readonly
95  	 */
96  	protected File outputDirectory;
97  
98      /***
99  	 * Name of the generated compiled binary file.
100 	 * 
101 	 * @parameter expression="${project.build.finalName}"
102 	 * @required
103 	 */
104 	protected String finalName;
105    
106 
107     /***
108      * The maven project.
109      *
110      * @parameter expression="${project}"
111      * @required
112      * @readonly
113      */
114     protected MavenProject project;
115     
116     /***
117      * @component
118      */
119     protected MavenProjectHelper projectHelper;
120 
121     /***
122      * @parameter expression="${plugin.artifacts}"
123      * @required
124      * @readonly
125      */
126     protected List pluginArtifacts;
127     
128     /***
129      * These are additional JVM options used when invoking the Flex compiler
130      *
131      * @parameter expression="${flex.java.options}"
132      */
133     protected String[] javaOpts;
134 
135     /***
136      * @parameter expression="${flex.extraParameters}" 
137      */
138     protected Parameter[] extraParameters;
139     
140 	/***
141 	 * Classifier to add to the artifact generated. If given, the artifact will
142 	 * be an attachment instead.
143 	 * 
144 	 * @parameter
145 	 */
146 	protected String classifier;
147 
148     protected abstract File getOutputFile();
149 
150     protected abstract String getCompilerClass();    
151 
152     protected abstract String getFileExtension();
153     
154     protected File getFile( File basedir, String finalName, String classifier ) {
155         if ( classifier != null && !classifier.equals("") ) {
156         	if ( classifier.trim().length() > 0 && !classifier.startsWith( "-" )){
157         		classifier = "-" + classifier;
158         	}
159             return new File( basedir, finalName + classifier + ".jar" );
160         } else {
161         	return new File( basedir, finalName + "." + getFileExtension() );
162         }
163     }
164 
165     /***
166      * Override and implement this method to take the existing java parameters
167      * and add any final information requried to provide source files to the
168      * compiler.  
169      * @param parameterList
170      */
171     protected List prepareParameters() throws MojoFailureException, MojoExecutionException {
172     	List parameters = new ArrayList();
173     	
174 		try {
175 			parameters.add("+flexlib=" + new File(flexHome,"frameworks").getCanonicalPath());			
176 		} catch (IOException e) {
177 			throw new MojoExecutionException("Config file does not exist.", e);
178 		}
179     	
180 		if (flexConfig != null) {
181 			parameters.add("-load-config");
182 			try {
183 				parameters.add(flexConfig.getCanonicalFile().getAbsolutePath());
184 			} catch (IOException e) {
185 				throw new MojoExecutionException("Config file does not exist.", e);
186 			}
187 		}
188 		
189 		parameters.add( "-source-path" );
190 		
191 		try {
192 			parameters.add( source.getCanonicalPath());
193 		} catch (IOException e) {
194 			throw new MojoExecutionException("Source path doesn't exist.", e);
195 		}
196     	
197     	
198     	return parameters;
199     }
200 
201     protected void finalizeParameters(List parameters) throws MojoExecutionException, MojoFailureException {
202     	getLog().info("Adding Extra Parameters: " + Arrays.asList(extraParameters));
203 		Iterator extraParmsIter = Arrays.asList(extraParameters).iterator();
204 		while (extraParmsIter.hasNext()) {
205 			Parameter p = (Parameter)extraParmsIter.next();
206 			getLog().debug("Adding parameter " + p.getName());
207 			parameters.add("-" + p.getName());
208 			if (p.getValues() != null) {
209 				Iterator values = Arrays.asList(p.getValues()).iterator();
210 				while (values.hasNext()) {
211 					String value = (String)values.next();
212 					getLog().debug("Adding parameter value" + value);
213 					parameters.add(value);					
214 				}
215 			}
216 		}
217     }
218 
219     
220     protected abstract String getExecutableJar();
221     
222 	protected String getCommandClassPath()  throws MojoExecutionException, MojoFailureException {
223 		StringBuffer compilerClasspath = new StringBuffer();
224 		try {
225     		addClasspathEntry(compilerClasspath,new File(new File(flexHome,"lib"),getExecutableJar()).getCanonicalPath());
226 			
227     		// get support jar.
228     		for (Iterator i = pluginArtifacts.iterator(); i.hasNext() ;) {
229 				Artifact artifact = (Artifact)i.next();
230 				getLog().debug("Trying artifact to add to classpath: " + artifact);
231 				if (artifact.getGroupId().equals("net.israfil.mojo") && artifact.getArtifactId().equals("maven-flex2-plugin-support")) {
232 					addClasspathEntry(compilerClasspath, artifact.getFile().getCanonicalFile().getAbsolutePath());
233 					break;
234 				}
235 			}
236 		} catch (IOException e) { 
237 			throw new MojoExecutionException("Could not generate a canonical path for library.",e); 
238 		}	
239 
240 		return compilerClasspath.toString();
241     }
242     
243 	public void execute() throws MojoExecutionException, MojoFailureException {
244 		
245 		if (!flexHome.exists())
246 			throw new MojoExecutionException(flexHome + " does not exist.  flex.home property must be set.");
247 
248 
249 		this.getLog().debug("Creating output directory: " + outputDirectory);
250 		outputDirectory.mkdirs();
251 		
252 		
253 		// HACK: why is this not being set in the defaults???
254 		if (source == null) source = new File(project.getBasedir(),"src/main/flex");
255 		if ( !source.exists() ) 				
256 			throw new MojoExecutionException("Source directory " + source + " does not exist.");
257 		
258 		//
259 		// Setup the Command-line of java execution.
260 		//
261 		List commandLineArgs = new ArrayList();
262         
263 		//Add java opts, checking for two opts which are set in the 
264 		//basic flex shell scripts, and setting them if they're not 
265 		//overridden.
266 		//TODO: Test this.
267 		boolean maxMemIsSet = false;
268 		boolean sunIoCachesIsSet = false;
269         for( int i = 0; i < javaOpts.length; i++ ) {
270             commandLineArgs.add( javaOpts[i] );
271             if (javaOpts[i].startsWith("-Xmx")) maxMemIsSet = true;
272             else if (javaOpts[i].startsWith("-Dsun.io.useCanonCaches")) sunIoCachesIsSet = true;
273         }
274         if (!maxMemIsSet) commandLineArgs.add("-Xmx384m");
275         if (!sunIoCachesIsSet) commandLineArgs.add("-Dsun.io.useCanonCaches=false");
276         
277 		commandLineArgs.add("-classpath");
278 		commandLineArgs.add(getCommandClassPath());
279 		
280 		//
281 		// Setup the Java parameters.
282 		//
283 		
284 		List parameters = prepareParameters();
285     	finalizeParameters(parameters); // stuff
286 
287     	
288     	int result = -1;
289 
290 		try {
291 			source = source.getCanonicalFile(); // try to reduce size of line.
292 		} catch (IOException e) {}
293 
294         try {
295             result = executeJavaCommand("java", source.getAbsolutePath(), commandLineArgs, getCompilerClass(), parameters);
296             if ( result != 0 ) 
297                 throw new MojoExecutionException( "Result of " + getCompilerClass() + " execution is: '" + result + "'." );
298         } catch ( CommandLineException e ) {
299             throw new MojoExecutionException( "Command execution failed.", e );
300         }
301         
302         postProcess();
303 		
304 	}
305 	
306 	/***
307 	 * Executed near the end of execute().
308 	 */
309 	protected void postProcess() {
310 		// Point Maven2 at the outbound file.
311         File outFile = getOutputFile();
312 		if (classifier != null) {
313 			projectHelper.attachArtifact(project, classifier, outFile);
314 		} else {
315 			project.getArtifact().setFile(outFile);
316 		}
317 	};
318 	
319 	protected void addClasspathEntry(StringBuffer compilerClasspath, String path) {
320 		getLog().debug("Adding " + path + " to path.");
321 		if (compilerClasspath.length() != 0) {
322 			compilerClasspath.append(System.getProperty("path.separator"));
323 		} 
324 		compilerClasspath.append(path);
325 	}
326 	
327 	protected int executeJavaCommand(String cmd, String cwd, List commandLineArgs, String className, List programArgs) throws CommandLineException {
328 		
329     	// Attempt to invoke the compiler
330 		// create the array for the method sig consisting of one
331 		// string array representing command-line params.
332 		getLog().debug("Invoking " + className + " with parameters: " + programArgs);
333 		
334         Commandline cl = new Commandline();
335         cl.setExecutable( cmd );
336         Iterator clargsIterator = commandLineArgs.iterator();
337         while ( clargsIterator.hasNext() ) 
338         	cl.createArgument().setValue( (String)clargsIterator.next() );
339 
340         cl.createArgument().setValue( StreamedParameterExecutableWrapper.class.getCanonicalName() );
341         
342         cl.createArgument().setValue( className );
343         
344         InputStream argIs = StringStreamUtil.prepareInputStreamFromStrings(programArgs);
345         
346         cl.setWorkingDirectory( cwd );
347         
348         StreamConsumer consumer = new StreamConsumer() {
349             public void consumeLine( String line ) { getLog().info( line ); }
350         };
351         
352         getLog().debug("Command line: " + cl);	
353         
354         return CommandLineUtils.executeCommandLine( cl, argIs, consumer, consumer );
355         
356 	}
357 
358 }