View Javadoc

1   /*
2    * Copyright (c) 2007, Ounce Labs, Inc.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *     * Redistributions of source code must retain the above copyright
8    *       notice, this list of conditions and the following disclaimer.
9    *     * Redistributions in binary form must reproduce the above copyright
10   *       notice, this list of conditions and the following disclaimer in the
11   *       documentation and/or other materials provided with the distribution.
12   *     * Neither the name of the <organization> nor the
13   *       names of its contributors may be used to endorse or promote products
14   *       derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS PROVIDED BY OUNCE LABS, INC. ``AS IS'' AND ANY
17   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL OUNCE LABS, INC. BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  
28  package org.codehaus.mojo.ounce;
29  
30  import java.io.File;
31  import java.io.IOException;
32  import java.util.ArrayList;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Map;
36  
37  import org.apache.maven.plugin.MojoExecutionException;
38  import org.apache.maven.plugin.MojoFailureException;
39  import org.apache.maven.project.MavenProject;
40  import org.codehaus.mojo.ounce.core.OunceCore;
41  import org.codehaus.mojo.ounce.core.OunceCoreApplication;
42  import org.codehaus.mojo.ounce.core.OunceCoreException;
43  import org.codehaus.mojo.ounce.core.OunceProjectBean;
44  import org.codehaus.mojo.ounce.utils.ExternalApplication;
45  import org.codehaus.mojo.ounce.utils.ProjectFileInfo;
46  import org.codehaus.mojo.ounce.utils.Utils;
47  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
48  import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
49  import org.codehaus.plexus.util.StringUtils;
50  
51  /**
52   * This mojo generates an Ounce application file. It will automatically include all child modules as projects. This list
53   * make be modified using the includes and excludes patterns. Projects that are external to this build may be included
54   * directly using the externalProjects list. External Applications may also be included. All of their modules will be
55   * inherted as part of this application file. Those projects may also be filtered upon import.
56   * 
57   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
58   * @aggregator
59   * @phase package
60   * @goal application
61   */
62  public class ApplicationMojo
63      extends AbstractOunceMojo
64  {
65  
66      /**
67       * The projects in the current build.
68       * 
69       * @parameter expression="${reactorProjects}"
70       * @required
71       * @readonly
72       */
73      private List projects;
74  
75      /**
76       * An array of directories containing the pom file of any projects to include. If an include pattern is specified,
77       * projects not specifed by include patterns are excluded. <br/> Include only applies to inherited modules, not
78       * external projects. The current project is not filtered. <br/> The include pattern may contain the following
79       * wildcard characters:<br/> *: Zero or more characters<br/> **: Any folders<br/> ?: One and only one character<br/>
80       * 
81       * @parameter
82       */
83      protected String[] includes;
84  
85      /**
86       * An array of directories containing the pom file of any projects to exclude. Excludes can contain standard
87       * Ant-style wildcards. <br/> Excludes only apply to inherited modules, not external projects. The current project
88       * is not filtered.
89       * 
90       * @parameter
91       */
92      protected String[] excludes;
93  
94      /**
95       * List of external projects to include. These projects are included after any other projects have been included or
96       * excluded. <br/> The format is: name,path<br/> Where:<br/>
97       * <li>name is the artifact ID of the project to include.</li>
98       * <li>path is the pathname to the project.</li>
99       * 
100      * @parameter
101      */
102     protected List externalProjects;
103 
104     /**
105      * Allows you to include projects from multiple applications. The external application properties are not inherited,
106      * and the external application must already exist. <br/> externalApplications is a list of directories containing
107      * top-level pom files. <br/> The format for externalApplications is:
108      * pathname,[includes|includes],[excludes|excludes] <br/> Where:<br/>
109      * <li>pathname, includes, and excludes are comma delimited; if you have excludes, but no includes, use two commas.</li>
110      * <li>Multiple includes or excludes are separated by pipes (\x7c).</li>
111      * <li>Excludes can contain standard Ant style wildcards.</li>
112      * 
113      * @parameter
114      */
115     protected List externalApplications;
116     
117     /*
118      * (non-Javadoc)
119      * 
120      * @see org.apache.maven.plugin.Mojo#execute()
121      */
122     public void execute()
123         throws MojoExecutionException, MojoFailureException
124     {
125 
126         try
127         {
128             OunceCore core = getCore();
129 
130             List coreProjects = getIncludedModules();
131             List externs = getExternalProjects();
132 
133             if ( externs != null )
134             {
135                 if ( coreProjects != null )
136                 {
137                     coreProjects.addAll( externs );
138                 }
139                 else
140                 {
141                     coreProjects = externs;
142                 }
143             }
144 
145             externs = getIncludedExternalApplicationProjects( core );
146             if ( externs != null )
147             {
148                 coreProjects.addAll( externs );
149             }
150 
151             // perform variable substitution
152             Iterator it = coreProjects.iterator();
153             while ( it.hasNext() )
154             {
155                 OunceProjectBean projectBean = (OunceProjectBean) it.next();
156                 projectBean.setPath( Utils.convertToVariablePath( projectBean.getPath(), pathVariableMap ) );
157             }
158 
159             core.createApplication( getProjectRoot(), name, ".", coreProjects, options, getLog() );
160         }
161         catch ( ComponentLookupException e )
162         {
163             throw new MojoExecutionException( "Unable to lookup the core interface for hint: " + coreHint, e );
164         }
165         catch ( OunceCoreException e )
166         {
167             throw new MojoExecutionException( "Nested Ouncecore exception: " + e.getLocalizedMessage(), e );
168         }
169         catch ( IOException e )
170         {
171             throw new MojoExecutionException( "Nested IOexception: " + e.getLocalizedMessage(), e );
172         }
173 
174     }
175 
176     /**
177      * This method filters the projects.
178      * 
179      * @param theProjects
180      * @param includes
181      * @param excludes
182      * @return
183      * @throws IOException
184      */
185     private List getSelectedModules( List theProjects, String[] includes, String[] excludes )
186         throws IOException
187     {
188         IncludeExcludeFileSelector selector = new IncludeExcludeFileSelector();
189 
190         if ( excludes != null && excludes.length > 0 )
191         {
192             selector.setExcludes( excludes );
193         }
194 
195         if ( includes != null && includes.length > 0 )
196         {
197             selector.setIncludes( includes );
198         }
199 
200         List coreProjects = new ArrayList( theProjects.size() );
201 
202         Iterator iter = theProjects.iterator();
203         while ( iter.hasNext() )
204         {
205             MavenProject prj = (MavenProject) iter.next();
206 
207             if ( selector.isSelected( new ProjectFileInfo( prj.getBasedir() ) ) || prj == project )
208             {
209                 coreProjects.add( prj );
210             }
211         }
212         return coreProjects;
213     }
214 
215     /**
216      * Build a list of modules to be included as projects. These will be projects that are children of the current
217      * project.
218      * 
219      * @return List of OunceProjectBeans representing each module
220      * @throws IOException
221      */
222     protected List getIncludedModules()
223         throws IOException
224     {
225 
226         /*
227          * first we need to prefilter the reactor projects list. instead of including only the current project's
228          * children, it includes everything we need to build a prefilter based on the current project's path and only
229          * include projects with a matching path.
230          */
231         File baseDir = project.getBasedir();
232         String[] preFilterIncludes = new String[1];
233         preFilterIncludes[0] = "**/" + baseDir.getName() + "/**";
234         List preFilteredProjects = getSelectedModules( projects, preFilterIncludes, null );
235 
236         // now do the normal filtering
237         List includedProjects = getSelectedModules( preFilteredProjects, includes, excludes );
238 
239         // now make them beans
240         return convertToBeans( includedProjects );
241 
242     }
243 
244     /**
245      * Converts a list of Maven Projects to OunceProjectBeans
246      * 
247      * @param theProjects
248      * @return
249      */
250     private List convertToBeans( List theProjects )
251     {
252         List beanProjects = new ArrayList( theProjects.size() );
253 
254         Iterator iter = theProjects.iterator();
255         while ( iter.hasNext() )
256         {
257             MavenProject prj = (MavenProject) iter.next();
258 
259             if ( !skipPoms || !prj.getPackaging().equalsIgnoreCase( "pom" ) )
260             {
261                 String path = prj.getBasedir().getAbsolutePath();
262 
263                 path = Utils.convertToRelativePath( path, getProjectRoot(), "" );
264 
265                 beanProjects.add( new OunceProjectBean( path, prj.getArtifactId() ) );
266             }
267 
268             else
269             {
270                 this.getLog().debug( "Skipping Pom: " + prj.getArtifactId() );
271             }
272         }
273 
274         return beanProjects;
275     }
276 
277     /**
278      * Get the list of user defined external projects
279      * 
280      * @return List of external Projects
281      * @throws MojoExecutionException if the format is invalid
282      */
283     protected List getExternalProjects()
284         throws MojoExecutionException
285     {
286         List externals = null;
287 
288         if ( externalProjects != null && externalProjects.size() > 0 )
289         {
290 
291             // init the array
292             externals = new ArrayList( externalProjects.size() );
293 
294             // add each one
295             Iterator iter = externalProjects.iterator();
296             while ( iter.hasNext() )
297             {
298                 // break the project into name:path
299                 String extern = (String) iter.next();
300                 String[] prj = extern.split( "," );
301                 if ( prj.length == 2 )
302                 {
303                     externals.add( new OunceProjectBean( Utils.convertToUnixStylePath( prj[1] ), prj[0] ) );
304                 }
305                 else
306                 {
307                     // they didn't follow the format
308                     throw new MojoExecutionException( "Invalid External Project String: " + extern );
309                 }
310             }
311         }
312         return externals;
313     }
314 
315     /**
316      * Get the list of user defined external application files to process
317      * 
318      * @return List of external Applications
319      * @throws MojoExecutionException if the format is invalid
320      */
321     protected List getExternalApplications()
322         throws MojoExecutionException
323     {
324         List externals = null;
325 
326         if ( externalApplications != null && externalApplications.size() > 0 )
327         {
328 
329             // init the array
330             externals = new ArrayList( externalApplications.size() );
331 
332             // add each one
333             Iterator iter = externalApplications.iterator();
334             while ( iter.hasNext() )
335             {
336                 // break the project into
337                 // path,includes,excludes
338                 String extern = (String) iter.next();
339                 String[] prj = extern.split( "," );
340 
341                 prj[0] = Utils.convertToUnixStylePath( prj[0] );
342 
343                 if ( prj.length == 3 )
344                 {
345                     externals.add( new ExternalApplication( prj[0], prj[1], prj[2] ) );
346                 }
347                 else if ( prj.length == 2 )
348                 {
349                     externals.add( new ExternalApplication( prj[0], prj[1], null ) );
350                 }
351                 else if ( prj.length == 1 )
352                 {
353                     externals.add( new ExternalApplication( prj[0], null, null ) );
354                 }
355                 else
356                 {
357                     // they didn't follow the format
358                     throw new MojoExecutionException( "Invalid External Application String: " + extern );
359                 }
360             }
361         }
362         else
363         {
364             externals = new ArrayList();
365         }
366         return externals;
367     }
368 
369     /**
370      * This method processes the external Applications and filters them according to the include/exclude patterns
371      * 
372      * @return List of OunceCoreProject objects
373      * @throws MojoExecutionException
374      * @throws OunceCoreException
375      * @throws IOException
376      */
377     public List getIncludedExternalApplicationProjects( OunceCore core )
378         throws MojoExecutionException, OunceCoreException, IOException
379     {
380 
381         List externalApps = getExternalApplications();
382 
383         // init results
384         ArrayList results = new ArrayList( externalApps.size() );
385 
386         Iterator iter = externalApps.iterator();
387 
388         while ( iter.hasNext() )
389         {
390             ExternalApplication extern = (ExternalApplication) iter.next();
391 
392             // read the projects from the application ->
393             getLog().debug( "Reading External Application: " + extern.getPath() );
394             OunceCoreApplication app = core.readApplication( extern.getPath(), getLog() );
395 
396             results.addAll( filterExternalApplicationProjects( app, extern ) );
397         }
398 
399         return results;
400     }
401 
402     /**
403      * This method filters the projects retrieved from the external application
404      * 
405      * @param app
406      * @param extern
407      * @return
408      * @throws IOException
409      */
410     public List filterExternalApplicationProjects( OunceCoreApplication app, ExternalApplication extern )
411         throws IOException
412     {
413         List results = new ArrayList();
414         if ( app != null && app.getProjects() != null )
415         {
416             IncludeExcludeFileSelector fileSelector = new IncludeExcludeFileSelector();
417 
418             String excludeString = extern.getExcludes();
419             String includeString = extern.getIncludes();
420 
421             // init scanner with inc/exc
422             if ( StringUtils.isNotEmpty( excludeString ) )
423             {
424                 // split on |
425                 fileSelector.setExcludes( excludeString.split( "\\x7C" ) );
426             }
427 
428             if ( StringUtils.isNotEmpty( includeString ) )
429             {
430                 // split on |
431                 fileSelector.setIncludes( includeString.split( "\\x7C" ) );
432             }
433 
434             for ( Iterator pIter = app.getProjects().iterator(); pIter.hasNext(); )
435             {
436                 OunceProjectBean prj = (OunceProjectBean) pIter.next();
437                 getLog().debug( "Filtering External App Project: " + prj );
438                 if ( fileSelector.isSelected( new ProjectFileInfo( new File( prj.getPath() ) ) ) )
439                 {
440                     String path = Utils.convertToUnixStylePath( extern.getPath() + "/" + prj.getPath() );
441                     path = Utils.convertToVariablePath( path, pathVariableMap );
442                     prj.setPath( path );
443 
444                     getLog().debug( "Adding External App Project: " + prj );
445                     results.add( prj );
446                 }
447             }
448         }
449         return results;
450     }
451 
452     /**
453      * @return the projects
454      */
455     public List getProjects()
456     {
457         return this.projects;
458     }
459 
460     /**
461      * @param theProjects the projects to set
462      */
463     public void setProjects( List theProjects )
464     {
465         this.projects = theProjects;
466     }
467     
468     /**
469      * @return the includes
470      */
471     public String[] getIncludes()
472     {
473         return this.includes;
474     }
475 
476     /**
477      * @param theIncludes the includes to set
478      */
479     public void setIncludes( String[] theIncludes )
480     {
481         this.includes = theIncludes;
482     }
483 
484     /**
485      * @return the excludes
486      */
487     public String[] getExcludes()
488     {
489         return this.excludes;
490     }
491 
492     /**
493      * @param theExcludes the excludes to set
494      */
495     public void setExcludes( String[] theExcludes )
496     {
497         this.excludes = theExcludes;
498     }
499 
500     /**
501      * @param theExternalProjects the externalProjects to set
502      */
503     public void setExternalProjects( List theExternalProjects )
504     {
505         this.externalProjects = theExternalProjects;
506     }
507 
508     /**
509      * @param theExternalApplications the externalApplications to set
510      */
511     public void setExternalApplications( List theExternalApplications )
512     {
513         this.externalApplications = theExternalApplications;
514     }
515 
516     /**
517      * @param thePathProperties the pathVariableMap to set
518      */
519     public void setPathProperties( Map thePathProperties )
520     {
521         this.pathVariableMap = thePathProperties;
522     }
523 
524 }