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 to the local repository</li>
99       * <li>'<code>remote</code>' which is the shortcut for Maven Central repository or its mirror</li>
100      * <li>'<code>internal</code>' which is an internal catalog</li>
101      * </ul>
102      * <p/>
103      * If you want the catalogs to come from a different repository, please add the following to your 
104      * {@code settings.xml}
105      * <pre>
106      *   &lt;repository&gt;
107      *     &lt;id&gt;archetype&lt;/id&gt;
108      *     &lt;url&gt;https://repository.domain.com/path/to/repo/&lt;/url&gt;
109      *   &lt;/repository&gt;
110      *   
111      *   &lt;!-- in case of a repository with authentication --&gt;
112      *   &lt;server&gt;
113      *     &lt;id&gt;archetype&lt;/id&gt;
114      *     &lt;username&gt;user.name&lt;/username&gt;
115      *     &lt;password&gt;s3cr3t&lt;/password&gt;
116      *   &lt;/server&gt;
117      * </pre>
118      * If Maven Central repository catalog file is empty, <code>internal</code> catalog is used instead.
119      */
120     @Parameter( property = "archetypeCatalog", defaultValue = "remote,local" )
121     private String archetypeCatalog;
122 
123     /**
124      * Local Maven repository.
125      */
126     @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
127     private ArtifactRepository localRepository;
128 
129     /**
130      * List of remote repositories used by the resolver.
131      */
132     @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
133     private List<ArtifactRepository> remoteArtifactRepositories;
134 
135     /**
136      * User settings used to check the interactiveMode.
137      */
138     @Parameter( property = "interactiveMode", defaultValue = "${settings.interactiveMode}", required = true )
139     private Boolean interactiveMode;
140 
141     @Parameter( defaultValue = "${basedir}", property = "outputDirectory" )
142     private File outputDirectory;
143 
144     @Parameter( defaultValue = "${session}", readonly = true )
145     private MavenSession session;
146 
147     /**
148      * Goals to immediately run on the project created from the archetype.
149      */
150     @Parameter( property = "goals" )
151     private String goals;
152 
153     /**
154      * Applying some filter on displayed archetypes list: format is <code>artifactId</code> or <code>groupId:artifactId</code>.
155      * <ul>
156      * <li><code>org.apache:</code> -> displays all archetypes which contain org.apache in groupId</li>
157      * <li><code>:jee</code> or <code>jee</code> -> displays all archetypes which contain jee in artifactId</li>
158      * <li><code>org.apache:jee</code> -> displays all archetypes which contain org.apache in groupId AND jee in artifactId</li>
159      * </ul>
160      *
161      * @since 2.1
162      */
163     @Parameter( property = "filter" )
164     private String filter;
165 
166     @Override
167     public void execute()
168         throws MojoExecutionException, MojoFailureException
169     {
170         Properties executionProperties = session.getUserProperties();
171 
172         ArchetypeGenerationRequest request =
173             new ArchetypeGenerationRequest().setArchetypeGroupId( archetypeGroupId )
174             .setArchetypeArtifactId( archetypeArtifactId )
175             .setArchetypeVersion( archetypeVersion )
176             .setOutputDirectory( outputDirectory.getAbsolutePath() )
177             .setLocalRepository( localRepository )
178             .setRemoteArtifactRepositories( remoteArtifactRepositories )
179             .setFilter( filter )
180             .setProjectBuildingRequest( session.getProjectBuildingRequest() );
181 
182         try
183         {
184             if ( interactiveMode.booleanValue() )
185             {
186                 getLog().info( "Generating project in Interactive mode" );
187             }
188             else
189             {
190                 getLog().info( "Generating project in Batch mode" );
191             }
192 
193             selector.selectArchetype( request, interactiveMode, archetypeCatalog );
194 
195             if ( StringUtils.isBlank( request.getArchetypeArtifactId() ) )
196             {
197                 // no archetype found: stopping
198                 return;
199             }
200 
201             configurator.configureArchetype( request, interactiveMode, executionProperties );
202 
203             ArchetypeGenerationResult generationResult = manager.generateProjectFromArchetype( request );
204 
205             if ( generationResult.getCause() != null )
206             {
207                 throw new MojoFailureException( generationResult.getCause(), generationResult.getCause().getMessage(),
208                                                 generationResult.getCause().getMessage() );
209             }
210         }
211         catch ( MojoFailureException ex )
212         {
213             throw ex;
214         }
215         catch ( Exception ex )
216         {
217             throw (MojoFailureException) new MojoFailureException( ex.getMessage() ).initCause( ex );
218         }
219 
220         String artifactId = request.getArtifactId();
221 
222         String postArchetypeGenerationGoals = request.getArchetypeGoals();
223 
224         if ( StringUtils.isEmpty( postArchetypeGenerationGoals ) )
225         {
226             postArchetypeGenerationGoals = goals;
227         }
228 
229         if ( StringUtils.isNotEmpty( postArchetypeGenerationGoals ) )
230         {
231             invokePostArchetypeGenerationGoals( postArchetypeGenerationGoals, artifactId );
232         }
233     }
234 
235     private void invokePostArchetypeGenerationGoals( String goals, String artifactId )
236         throws MojoExecutionException, MojoFailureException
237     {
238         getLog().info( "Invoking post-archetype-generation goals: " + goals );
239 
240         File projectBasedir = new File( outputDirectory, artifactId );
241 
242         if ( projectBasedir.exists() )
243         {
244             InvocationRequest request = new DefaultInvocationRequest().setBaseDirectory( projectBasedir ).setGoals(
245                 Arrays.asList( StringUtils.split( goals, "," ) ) );
246 
247             try
248             {
249                 InvocationResult result = invoker.execute( request );
250                 
251                 if ( result.getExitCode() != 0 )
252                 {
253                     throw new MojoExecutionException( "Failed to invoke goals",
254                                                       result.getExecutionException() );
255                 }
256             }
257             catch ( MavenInvocationException e )
258             {
259                 throw new MojoExecutionException( "Cannot run additions goals.", e );
260             }
261         }
262         else
263         {
264             getLog().info( "Post-archetype-generation goals aborted: unavailable basedir " + projectBasedir );
265         }
266     }
267 }