View Javadoc

1   package org.apache.maven.archetype.ui.generation;
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.maven.archetype.ArchetypeGenerationRequest;
23  import org.apache.maven.archetype.common.ArchetypeArtifactManager;
24  import org.apache.maven.archetype.common.ArchetypeRegistryManager;
25  import org.apache.maven.archetype.common.Constants;
26  import org.apache.maven.archetype.exception.ArchetypeGenerationConfigurationFailure;
27  import org.apache.maven.archetype.exception.ArchetypeNotConfigured;
28  import org.apache.maven.archetype.exception.ArchetypeNotDefined;
29  import org.apache.maven.archetype.exception.UnknownArchetype;
30  import org.apache.maven.archetype.old.OldArchetype;
31  import org.apache.maven.archetype.ui.ArchetypeConfiguration;
32  import org.apache.maven.archetype.ui.ArchetypeDefinition;
33  import org.apache.maven.archetype.ui.ArchetypeFactory;
34  import org.apache.maven.artifact.repository.ArtifactRepository;
35  
36  import org.codehaus.plexus.component.annotations.Component;
37  import org.codehaus.plexus.component.annotations.Requirement;
38  import org.codehaus.plexus.components.interactivity.PrompterException;
39  import org.codehaus.plexus.logging.AbstractLogEnabled;
40  import org.codehaus.plexus.util.StringUtils;
41  
42  import java.io.IOException;
43  
44  import java.util.ArrayList;
45  import java.util.Collections;
46  import java.util.Comparator;
47  import java.util.List;
48  import java.util.Properties;
49  
50  // TODO: this seems to have more responsibilities than just a configurator
51  @Component( role = ArchetypeGenerationConfigurator.class )
52  public class DefaultArchetypeGenerationConfigurator
53      extends AbstractLogEnabled
54      implements ArchetypeGenerationConfigurator
55  {
56      @Requirement
57      OldArchetype oldArchetype;
58  
59      @Requirement
60      private ArchetypeArtifactManager archetypeArtifactManager;
61  
62      @Requirement
63      private ArchetypeFactory archetypeFactory;
64  
65      @Requirement
66      private ArchetypeGenerationQueryer archetypeGenerationQueryer;
67  
68      @Requirement
69      private ArchetypeRegistryManager archetypeRegistryManager;
70  
71      public void setArchetypeArtifactManager( ArchetypeArtifactManager archetypeArtifactManager )
72      {
73          this.archetypeArtifactManager = archetypeArtifactManager;
74      }
75  
76      public void configureArchetype( ArchetypeGenerationRequest request, Boolean interactiveMode,
77                                      Properties executionProperties )
78          throws ArchetypeNotDefined, UnknownArchetype, ArchetypeNotConfigured, IOException, PrompterException,
79          ArchetypeGenerationConfigurationFailure
80      {
81          ArtifactRepository localRepository = request.getLocalRepository();
82  
83          ArtifactRepository archetypeRepository = null;
84  
85          List<ArtifactRepository> repositories = new ArrayList<ArtifactRepository>();
86  
87          Properties properties = new Properties( executionProperties );
88  
89          ArchetypeDefinition ad = new ArchetypeDefinition( request );
90  
91          if ( !ad.isDefined() )
92          {
93              if ( !interactiveMode.booleanValue() )
94              {
95                  throw new ArchetypeNotDefined( "No archetype was chosen" );
96              }
97              else
98              {
99                  throw new ArchetypeNotDefined( "The archetype is not defined" );
100             }
101         }
102         if ( request.getArchetypeRepository() != null )
103         {
104             archetypeRepository =
105                 archetypeRegistryManager.createRepository( request.getArchetypeRepository(),
106                                                            ad.getArtifactId() + "-repo" );
107             repositories.add( archetypeRepository );
108         }
109         if ( request.getRemoteArtifactRepositories() != null )
110         {
111             repositories.addAll( request.getRemoteArtifactRepositories() );
112         }
113 
114         if ( !archetypeArtifactManager.exists( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
115                                                archetypeRepository, localRepository, repositories ) )
116         {
117             throw new UnknownArchetype( "The desired archetype does not exist (" + ad.getGroupId() + ":"
118                 + ad.getArtifactId() + ":" + ad.getVersion() + ")" );
119         }
120 
121         request.setArchetypeVersion( ad.getVersion() );
122 
123         ArchetypeConfiguration archetypeConfiguration;
124 
125         if ( archetypeArtifactManager.isFileSetArchetype( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
126                                                           archetypeRepository, localRepository, repositories ) )
127         {
128             org.apache.maven.archetype.metadata.ArchetypeDescriptor archetypeDescriptor =
129                 archetypeArtifactManager.getFileSetArchetypeDescriptor( ad.getGroupId(), ad.getArtifactId(),
130                                                                         ad.getVersion(), archetypeRepository,
131                                                                         localRepository, repositories );
132 
133             archetypeConfiguration = archetypeFactory.createArchetypeConfiguration( archetypeDescriptor, properties );
134         }
135         else if ( archetypeArtifactManager.isOldArchetype( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
136                                                            archetypeRepository, localRepository, repositories ) )
137         {
138             org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor archetypeDescriptor =
139                 archetypeArtifactManager.getOldArchetypeDescriptor( ad.getGroupId(), ad.getArtifactId(),
140                                                                     ad.getVersion(), archetypeRepository,
141                                                                     localRepository, repositories );
142 
143             archetypeConfiguration = archetypeFactory.createArchetypeConfiguration( archetypeDescriptor, properties );
144         }
145         else
146         {
147             throw new ArchetypeGenerationConfigurationFailure( "The defined artifact is not an archetype" );
148         }
149 
150         if ( interactiveMode.booleanValue() )
151         {
152             boolean confirmed = false;
153 
154             while ( !confirmed )
155             {
156                 List<String> propertiesRequired = archetypeConfiguration.getRequiredProperties();
157                 getLogger().debug( "Required properties before content sort: " + propertiesRequired );
158                 Collections.sort( propertiesRequired, new RequiredPropertyComparator( archetypeConfiguration ) );
159                 getLogger().debug( "Required properties after content sort: " + propertiesRequired );
160 
161                 if ( !archetypeConfiguration.isConfigured() )
162                 {
163                     for ( String requiredProperty : propertiesRequired )
164                     {
165                         if ( !archetypeConfiguration.isConfigured( requiredProperty ) )
166                         {
167                             if ( "package".equals( requiredProperty ) )
168                             {
169                                 // if the asked property is 'package', then
170                                 // use its default and if not defined,
171                                 // use the 'groupId' property value.
172                                 String packageDefault = archetypeConfiguration.getDefaultValue( requiredProperty );
173                                 packageDefault =
174                                     ( null == packageDefault || "".equals( packageDefault ) ) ? archetypeConfiguration.getProperty( "groupId" )
175                                                     : archetypeConfiguration.getDefaultValue( requiredProperty );
176 
177                                 String value = getTransitiveDefaultValue( packageDefault, archetypeConfiguration );
178 
179                                 value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value );
180 
181                                 archetypeConfiguration.setProperty( requiredProperty, value );
182                             }
183                             else
184                             {
185                                 String value = archetypeConfiguration.getDefaultValue( requiredProperty );
186 
187                                 value = getTransitiveDefaultValue( value, archetypeConfiguration );
188 
189                                 value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value );
190 
191                                 archetypeConfiguration.setProperty( requiredProperty, value );
192                             }
193                         }
194                         else
195                         {
196                             getLogger().info(
197                                               "Using property: " + requiredProperty + " = "
198                                                   + archetypeConfiguration.getProperty( requiredProperty ) );
199                         }
200                     }
201                 }
202                 else
203                 {
204 
205                     for ( String requiredProperty : propertiesRequired )
206                     {
207                         getLogger().info(
208                                           "Using property: " + requiredProperty + " = "
209                                               + archetypeConfiguration.getProperty( requiredProperty ) );
210                     }
211                 }
212 
213                 if ( !archetypeConfiguration.isConfigured() )
214                 {
215                     getLogger().warn( "Archetype is not fully configured" );
216                 }
217                 else if ( !archetypeGenerationQueryer.confirmConfiguration( archetypeConfiguration ) )
218                 {
219                     getLogger().debug( "Archetype generation configuration not confirmed" );
220                     archetypeConfiguration.reset();
221                     restoreCommandLineProperties( archetypeConfiguration, executionProperties );
222                 }
223                 else
224                 {
225                     getLogger().debug( "Archetype generation configuration confirmed" );
226 
227                     confirmed = true;
228                 }
229             }
230         }
231         else
232         {
233             if ( !archetypeConfiguration.isConfigured() )
234             {
235                 for ( String requiredProperty : archetypeConfiguration.getRequiredProperties() )
236                 {
237                     if ( !archetypeConfiguration.isConfigured( requiredProperty )
238                         && ( archetypeConfiguration.getDefaultValue( requiredProperty ) != null ) )
239                     {
240                         archetypeConfiguration.setProperty( requiredProperty,
241                                                             archetypeConfiguration.getDefaultValue( requiredProperty ) );
242                     }
243                 }
244 
245                 // in batch mode, we assume the defaults, and if still not configured fail
246                 if ( !archetypeConfiguration.isConfigured() )
247                 {
248                     StringBuffer exceptionMessage = new StringBuffer();
249                     exceptionMessage.append( "Archetype " );
250                     exceptionMessage.append( request.getArchetypeGroupId() );
251                     exceptionMessage.append( ":" );
252                     exceptionMessage.append( request.getArchetypeArtifactId() );
253                     exceptionMessage.append( ":" );
254                     exceptionMessage.append( request.getArchetypeVersion() );
255                     exceptionMessage.append( " is not configured" );
256 
257                     List<String> missingProperties = new ArrayList<String>( 0 );
258                     for ( String requiredProperty : archetypeConfiguration.getRequiredProperties() )
259                     {
260                         if ( !archetypeConfiguration.isConfigured( requiredProperty ) )
261                         {
262                             exceptionMessage.append( "\n\tProperty " );
263                             exceptionMessage.append( requiredProperty );
264                             missingProperties.add( requiredProperty );
265                             exceptionMessage.append( " is missing." );
266                             getLogger().warn(
267                                               "Property " + requiredProperty + " is missing. Add -D" + requiredProperty
268                                                   + "=someValue" );
269                         }
270                     }
271 
272                     throw new ArchetypeNotConfigured( exceptionMessage.toString(), missingProperties );
273                 }
274             }
275         }
276 
277         request.setGroupId( archetypeConfiguration.getProperty( Constants.GROUP_ID ) );
278 
279         request.setArtifactId( archetypeConfiguration.getProperty( Constants.ARTIFACT_ID ) );
280 
281         request.setVersion( archetypeConfiguration.getProperty( Constants.VERSION ) );
282 
283         request.setPackage( archetypeConfiguration.getProperty( Constants.PACKAGE ) );
284 
285         properties = archetypeConfiguration.getProperties();
286 
287         request.setProperties( properties );
288     }
289 
290     private String getTransitiveDefaultValue( String defaultValue, ArchetypeConfiguration archetypeConfiguration )
291     {
292         String result = defaultValue;
293         if ( null == result )
294         {
295             return null;
296         }
297         for ( String property : archetypeConfiguration.getRequiredProperties() )
298         {
299             if ( result.indexOf( "${" + property + "}" ) >= 0 )
300             {
301                 result = StringUtils.replace( result, "${" + property + "}",
302                                               archetypeConfiguration.getProperty( property ) );
303             }
304         }
305         return result;
306     }
307 
308     private void restoreCommandLineProperties( ArchetypeConfiguration archetypeConfiguration,
309                                                Properties executionProperties )
310     {
311         getLogger().debug( "Restoring command line properties" );
312 
313         for ( String property : archetypeConfiguration.getRequiredProperties() )
314         {
315             if ( executionProperties.containsKey( property ) )
316             {
317                 archetypeConfiguration.setProperty( property, executionProperties.getProperty( property ) );
318                 getLogger().debug( "Restored " + property + "=" + archetypeConfiguration.getProperty( property ) );
319             }
320         }
321     }
322 
323     public static class RequiredPropertyComparator
324         implements Comparator<String>
325     {
326         private final ArchetypeConfiguration archetypeConfiguration;
327 
328         public RequiredPropertyComparator( ArchetypeConfiguration archetypeConfiguration )
329         {
330             this.archetypeConfiguration = archetypeConfiguration;
331         }
332 
333         public int compare( String left, String right )
334         {
335             String leftDefault = archetypeConfiguration.getDefaultValue( left );
336 
337             if ( ( leftDefault != null ) && leftDefault.indexOf( "${" + right + "}" ) >= 0 )
338             { //left contains right
339                 return 1;
340             }
341 
342             String rightDefault = archetypeConfiguration.getDefaultValue( right );
343 
344             if ( ( rightDefault != null ) && rightDefault.indexOf( "${" + left + "}" ) >= 0 )
345             { //right contains left
346                 return -1;
347             }
348 
349             return comparePropertyName( left, right );
350         }
351 
352         private int comparePropertyName( String left, String right )
353         {
354             if ( "groupId".equals( left ) )
355             {
356                 return -1;
357             }
358             if ( "groupId".equals( right ) )
359             {
360                 return 1;
361             }
362             if ( "artifactId".equals( left ) )
363             {
364                 return -1;
365             }
366             if ( "artifactId".equals( right ) )
367             {
368                 return 1;
369             }
370             if ( "version".equals( left ) )
371             {
372                 return -1;
373             }
374             if ( "version".equals( right ) )
375             {
376                 return 1;
377             }
378             if ( "package".equals( left ) )
379             {
380                 return -1;
381             }
382             if ( "package".equals( right ) )
383             {
384                 return 1;
385             }
386             return left.compareTo( right );
387         }
388     }
389 }