View Javadoc
1   package org.apache.maven.archetype.mojos;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.maven.archetype.ArchetypeGenerationRequest;
24  import org.apache.maven.archetype.ArchetypeGenerationResult;
25  import org.apache.maven.archetype.ArchetypeManager;
26  import org.apache.maven.archetype.ui.generation.ArchetypeGenerationConfigurator;
27  import org.apache.maven.archetype.ui.generation.ArchetypeSelector;
28  import org.apache.maven.artifact.repository.ArtifactRepository;
29  import org.apache.maven.execution.MavenSession;
30  import org.apache.maven.plugin.AbstractMojo;
31  import org.apache.maven.plugin.ContextEnabled;
32  import org.apache.maven.plugin.MojoExecutionException;
33  import org.apache.maven.plugin.MojoFailureException;
34  import org.apache.maven.plugins.annotations.Component;
35  import org.apache.maven.plugins.annotations.Execute;
36  import org.apache.maven.plugins.annotations.LifecyclePhase;
37  import org.apache.maven.plugins.annotations.Mojo;
38  import org.apache.maven.plugins.annotations.Parameter;
39  import org.apache.maven.shared.invoker.DefaultInvocationRequest;
40  import org.apache.maven.shared.invoker.InvocationRequest;
41  import org.apache.maven.shared.invoker.InvocationResult;
42  import org.apache.maven.shared.invoker.Invoker;
43  import org.apache.maven.shared.invoker.MavenInvocationException;
44  
45  import java.io.File;
46  import java.util.Arrays;
47  import java.util.List;
48  import java.util.Properties;
49  
50  /**
51   * Generates a new project from an archetype, or updates the actual project if using a partial archetype.
52   * If the project is fully generated, it is generated in a directory corresponding to its artifactId.
53   * If the project is updated with a partial archetype, it is done in the current directory.
54   *
55   * @author rafale
56   */
57  @Mojo( name = "generate", requiresProject = false )
58  @Execute( phase = LifecyclePhase.GENERATE_SOURCES )
59  public class CreateProjectFromArchetypeMojo
60      extends AbstractMojo
61      implements ContextEnabled
62  {
63      @Component
64      private ArchetypeManager manager;
65  
66      @Component
67      private ArchetypeSelector selector;
68  
69      @Component
70      private ArchetypeGenerationConfigurator configurator;
71  
72      @Component
73      private Invoker invoker;
74  
75      /**
76       * The archetype's artifactId.
77       */
78      @Parameter( property = "archetypeArtifactId" )
79      private String archetypeArtifactId;
80  
81      /**
82       * The archetype's groupId.
83       */
84      @Parameter( property = "archetypeGroupId" )
85      private String archetypeGroupId;
86  
87      /**
88       * The archetype's version.
89       */
90      @Parameter( property = "archetypeVersion" )
91      private String archetypeVersion;
92  
93      /**
94       * The archetype catalogs to use to build a list and let the user choose from.
95       * It is a comma separated list of catalogs.
96       * Catalogs use the following schemes:
97       * <ul>
98       * <li>'<code>local</code>' which is the shortcut for '<code>file://~/.m2/archetype-catalog.xml</code>'</li>
99       * <li>'<code>remote</code>' which is the shortcut for Maven Central repository, ie '<code>http://repo.maven.apache.org/maven2</code>'</li>;
100      * <li>'<code>internal</code>' which is an internal catalog</li>
101      * </ul>
102      * <p/>
103      * If Maven Central repository catalog file is empty, <code>internal</code> catalog is used instead.
104      */
105     @Parameter( property = "archetypeCatalog", defaultValue = "remote,local" )
106     private String archetypeCatalog;
107 
108     /**
109      * Local Maven repository.
110      */
111     @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
112     private ArtifactRepository localRepository;
113 
114     /**
115      * List of remote repositories used by the resolver.
116      */
117     @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
118     private List<ArtifactRepository> remoteArtifactRepositories;
119 
120     /**
121      * User settings used to check the interactiveMode.
122      */
123     @Parameter( property = "interactiveMode", defaultValue = "${settings.interactiveMode}", required = true )
124     private Boolean interactiveMode;
125 
126     @Parameter( defaultValue = "${basedir}" )
127     private File basedir;
128 
129     @Parameter( defaultValue = "${session}", readonly = true )
130     private MavenSession session;
131 
132     /**
133      * Goals to immediately run on the project created from the archetype.
134      */
135     @Parameter( property = "goals" )
136     private String goals;
137 
138     /**
139      * Applying some filter on displayed archetypes list: format is <code>artifactId</code> or <code>groupId:artifactId</code>.
140      * <ul>
141      * <li><code>org.apache:</code> -> displays all archetypes which contain org.apache in groupId</li>
142      * <li><code>:jee</code> or <code>jee</code> -> displays all archetypes which contain jee in artifactId</li>
143      * <li><code>org.apache:jee</code> -> displays all archetypes which contain org.apache in groupId AND jee in artifactId</li>
144      * </ul>
145      *
146      * @since 2.1
147      */
148     @Parameter( property = "filter" )
149     private String filter;
150 
151     public void execute()
152         throws MojoExecutionException, MojoFailureException
153     {
154         Properties executionProperties = session.getUserProperties();
155 
156         ArchetypeGenerationRequest request =
157             new ArchetypeGenerationRequest().setArchetypeGroupId( archetypeGroupId )
158             .setArchetypeArtifactId( archetypeArtifactId )
159             .setArchetypeVersion( archetypeVersion )
160             .setOutputDirectory( basedir.getAbsolutePath() )
161             .setLocalRepository( localRepository )
162             .setRemoteArtifactRepositories( remoteArtifactRepositories )
163             .setFilter( filter )
164             .setProjectBuildingRequest( session.getProjectBuildingRequest() );
165 
166         try
167         {
168             if ( interactiveMode.booleanValue() )
169             {
170                 getLog().info( "Generating project in Interactive mode" );
171             }
172             else
173             {
174                 getLog().info( "Generating project in Batch mode" );
175             }
176 
177             selector.selectArchetype( request, interactiveMode, archetypeCatalog );
178 
179             if ( StringUtils.isBlank( request.getArchetypeArtifactId() ) )
180             {
181                 // no archetype found: stopping
182                 return;
183             }
184 
185             configurator.configureArchetype( request, interactiveMode, executionProperties );
186 
187             ArchetypeGenerationResult generationResult = manager.generateProjectFromArchetype( request );
188 
189             if ( generationResult.getCause() != null )
190             {
191                 throw new MojoFailureException( generationResult.getCause(), generationResult.getCause().getMessage(),
192                                                 generationResult.getCause().getMessage() );
193             }
194         }
195         catch ( MojoFailureException ex )
196         {
197             throw ex;
198         }
199         catch ( Exception ex )
200         {
201             throw (MojoFailureException) new MojoFailureException( ex.getMessage() ).initCause( ex );
202         }
203 
204         String artifactId = request.getArtifactId();
205 
206         String postArchetypeGenerationGoals = request.getArchetypeGoals();
207 
208         if ( StringUtils.isEmpty( postArchetypeGenerationGoals ) )
209         {
210             postArchetypeGenerationGoals = goals;
211         }
212 
213         if ( StringUtils.isNotEmpty( postArchetypeGenerationGoals ) )
214         {
215             invokePostArchetypeGenerationGoals( postArchetypeGenerationGoals, artifactId );
216         }
217     }
218 
219     private void invokePostArchetypeGenerationGoals( String goals, String artifactId )
220         throws MojoExecutionException, MojoFailureException
221     {
222         getLog().info( "Invoking post-archetype-generation goals: " + goals );
223 
224         File projectBasedir = new File( basedir, artifactId );
225 
226         if ( projectBasedir.exists() )
227         {
228             InvocationRequest request = new DefaultInvocationRequest().setBaseDirectory( projectBasedir ).setGoals(
229                 Arrays.asList( StringUtils.split( goals, "," ) ) );
230 
231             try
232             {
233                 InvocationResult result = invoker.execute( request );
234                 
235                 if ( result.getExitCode() != 0 )
236                 {
237                     throw new MojoExecutionException( "Failed to invoke goals",
238                                                       result.getExecutionException() );
239                 }
240             }
241             catch ( MavenInvocationException e )
242             {
243                 throw new MojoExecutionException( "Cannot run additions goals.", e );
244             }
245         }
246         else
247         {
248             getLog().info( "Post-archetype-generation goals aborted: unavailable basedir " + projectBasedir );
249         }
250     }
251 }