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