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.lang3.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      * If set to {@code true} will ask for values also for properties having defaults in the first place.
125      * Only has an effect if {@link #interactiveMode} is used.
126      */
127     @Parameter( property = "askForDefaultPropertyValues", defaultValue = "false", required = true )
128     private Boolean askForDefaultPropertyValues;
129 
130     /**
131      * Local Maven repository.
132      */
133     @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
134     private ArtifactRepository localRepository;
135 
136     /**
137      * List of remote repositories used by the resolver.
138      */
139     @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
140     private List<ArtifactRepository> remoteArtifactRepositories;
141 
142     /**
143      * User settings used to check the interactiveMode.
144      */
145     @Parameter( property = "interactiveMode", defaultValue = "${settings.interactiveMode}", required = true )
146     private Boolean interactiveMode;
147 
148     @Parameter( defaultValue = "${basedir}", property = "outputDirectory" )
149     private File outputDirectory;
150 
151     @Parameter( defaultValue = "${session}", readonly = true )
152     private MavenSession session;
153 
154     /**
155      * Goals to immediately run on the project created from the archetype.
156      */
157     @Parameter( property = "goals" )
158     private String goals;
159 
160     /**
161      * Applying some filter on displayed archetypes list: format is <code>artifactId</code> or <code>groupId:artifactId</code>.
162      * <ul>
163      * <li><code>org.apache:</code> -> displays all archetypes which contain org.apache in groupId</li>
164      * <li><code>:jee</code> or <code>jee</code> -> displays all archetypes which contain jee in artifactId</li>
165      * <li><code>org.apache:jee</code> -> displays all archetypes which contain org.apache in groupId AND jee in artifactId</li>
166      * </ul>
167      *
168      * @since 2.1
169      */
170     @Parameter( property = "filter" )
171     private String filter;
172 
173     @Override
174     public void execute()
175         throws MojoExecutionException, MojoFailureException
176     {
177         Properties executionProperties = session.getUserProperties();
178 
179         ArchetypeGenerationRequest request =
180             new ArchetypeGenerationRequest().setArchetypeGroupId( archetypeGroupId )
181             .setArchetypeArtifactId( archetypeArtifactId )
182             .setArchetypeVersion( archetypeVersion )
183             .setOutputDirectory( outputDirectory.getAbsolutePath() )
184             .setLocalRepository( localRepository )
185             .setRemoteArtifactRepositories( remoteArtifactRepositories )
186             .setFilter( filter )
187             .setAskForDefaultPropertyValues( askForDefaultPropertyValues )
188             .setProjectBuildingRequest( session.getProjectBuildingRequest() );
189 
190         try
191         {
192             if ( interactiveMode.booleanValue() )
193             {
194                 getLog().info( "Generating project in Interactive mode" );
195             }
196             else
197             {
198                 getLog().info( "Generating project in Batch mode" );
199             }
200 
201             selector.selectArchetype( request, interactiveMode, archetypeCatalog );
202 
203             if ( StringUtils.isBlank( request.getArchetypeArtifactId() ) )
204             {
205                 // no archetype found: stopping
206                 return;
207             }
208 
209             configurator.configureArchetype( request, interactiveMode, executionProperties );
210 
211             ArchetypeGenerationResult generationResult = manager.generateProjectFromArchetype( request );
212 
213             if ( generationResult.getCause() != null )
214             {
215                 throw new MojoFailureException( generationResult.getCause(), generationResult.getCause().getMessage(),
216                                                 generationResult.getCause().getMessage() );
217             }
218         }
219         catch ( MojoFailureException ex )
220         {
221             throw ex;
222         }
223         catch ( Exception ex )
224         {
225             throw (MojoFailureException) new MojoFailureException( ex.getMessage() ).initCause( ex );
226         }
227 
228         String artifactId = request.getArtifactId();
229 
230         String postArchetypeGenerationGoals = request.getArchetypeGoals();
231 
232         if ( StringUtils.isEmpty( postArchetypeGenerationGoals ) )
233         {
234             postArchetypeGenerationGoals = goals;
235         }
236 
237         if ( StringUtils.isNotEmpty( postArchetypeGenerationGoals ) )
238         {
239             invokePostArchetypeGenerationGoals( postArchetypeGenerationGoals, artifactId );
240         }
241     }
242 
243     private void invokePostArchetypeGenerationGoals( String goals, String artifactId )
244         throws MojoExecutionException, MojoFailureException
245     {
246         getLog().info( "Invoking post-archetype-generation goals: " + goals );
247 
248         File projectBasedir = new File( outputDirectory, artifactId );
249 
250         if ( projectBasedir.exists() )
251         {
252             InvocationRequest request = new DefaultInvocationRequest().setBaseDirectory( projectBasedir ).setGoals(
253                 Arrays.asList( StringUtils.split( goals, "," ) ) );
254 
255             try
256             {
257                 InvocationResult result = invoker.execute( request );
258                 
259                 if ( result.getExitCode() != 0 )
260                 {
261                     throw new MojoExecutionException( "Failed to invoke goals",
262                                                       result.getExecutionException() );
263                 }
264             }
265             catch ( MavenInvocationException e )
266             {
267                 throw new MojoExecutionException( "Cannot run additions goals.", e );
268             }
269         }
270         else
271         {
272             getLog().info( "Post-archetype-generation goals aborted: unavailable basedir " + projectBasedir );
273         }
274     }
275 }