View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.maven.archetype.ui;
21  
22  import org.apache.maven.archetype.ArchetypeGenerationRequest;
23  import org.apache.maven.archetype.common.ArchetypeArtifactManager;
24  import org.apache.maven.archetype.common.ArchetypeConfiguration;
25  import org.apache.maven.archetype.common.ArchetypeDefinition;
26  import org.apache.maven.archetype.common.ArchetypeRegistryManager;
27  import org.apache.maven.archetype.common.Constants;
28  import org.apache.maven.archetype.exception.ArchetypeGenerationConfigurationFailure;
29  import org.apache.maven.archetype.exception.ArchetypeNotConfigured;
30  import org.apache.maven.archetype.exception.ArchetypeNotDefined;
31  import org.apache.maven.archetype.exception.UnknownArchetype;
32  import org.apache.maven.archetype.old.OldArchetype;
33  import org.apache.maven.artifact.repository.ArtifactRepository;
34  
35  import org.codehaus.plexus.components.interactivity.PrompterException;
36  import org.codehaus.plexus.logging.AbstractLogEnabled;
37  
38  import java.io.IOException;
39  
40  import java.util.ArrayList;
41  import java.util.Collections;
42  import java.util.Comparator;
43  import java.util.Iterator;
44  import java.util.List;
45  import java.util.Properties;
46  import org.codehaus.plexus.util.StringUtils;
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 repositories = new ArrayList();
96  
97          Properties properties = new Properties( executionProperties );
98  
99          ArchetypeDefinition ad = new ArchetypeDefinition();
100 
101         ad.setGroupId( request.getArchetypeGroupId() );
102 
103         ad.setArtifactId( request.getArchetypeArtifactId() );
104 
105         ad.setVersion( request.getArchetypeVersion() );
106 
107         if ( !ad.isDefined() )
108         {
109             if ( !interactiveMode.booleanValue() )
110             {
111                 throw new ArchetypeNotDefined( "No archetype was chosen" );
112             }
113             else
114             {
115                 throw new ArchetypeNotDefined( "The archetype is not defined" );
116             }
117         }
118         if ( request.getArchetypeRepository() != null )
119         {
120             archetypeRepository =
121                 archetypeRegistryManager.createRepository( request.getArchetypeRepository(),
122                                                            ad.getArtifactId() + "-repo" );
123             repositories.add( archetypeRepository );
124         }
125         if ( request.getRemoteArtifactRepositories() != null )
126         {
127             repositories.addAll( request.getRemoteArtifactRepositories() );
128         }
129 
130         if ( !archetypeArtifactManager.exists( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
131                                                archetypeRepository, localRepository, repositories ) )
132         {
133             throw new UnknownArchetype( "The desired archetype does not exist (" + ad.getGroupId() + ":"
134                 + ad.getArtifactId() + ":" + ad.getVersion() + ")" );
135         }
136 
137         request.setArchetypeVersion( ad.getVersion() );
138 
139         ArchetypeConfiguration archetypeConfiguration;
140 
141         if ( archetypeArtifactManager.isFileSetArchetype( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
142                                                           archetypeRepository, localRepository, repositories ) )
143         {
144             org.apache.maven.archetype.metadata.ArchetypeDescriptor archetypeDescriptor =
145                 archetypeArtifactManager.getFileSetArchetypeDescriptor( ad.getGroupId(), ad.getArtifactId(),
146                                                                         ad.getVersion(), archetypeRepository,
147                                                                         localRepository, repositories );
148 
149             archetypeConfiguration = archetypeFactory.createArchetypeConfiguration( archetypeDescriptor, properties );
150         }
151         else if ( archetypeArtifactManager.isOldArchetype( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
152                                                            archetypeRepository, localRepository, repositories ) )
153         {
154             org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor archetypeDescriptor =
155                 archetypeArtifactManager.getOldArchetypeDescriptor( ad.getGroupId(), ad.getArtifactId(),
156                                                                     ad.getVersion(), archetypeRepository,
157                                                                     localRepository, repositories );
158 
159             archetypeConfiguration = archetypeFactory.createArchetypeConfiguration( archetypeDescriptor, properties );
160         }
161         else
162         {
163             throw new ArchetypeGenerationConfigurationFailure( "The defined artifact is not an archetype" );
164         }
165 
166         if ( interactiveMode.booleanValue() )
167         {
168             boolean confirmed = false;
169 
170             while ( !confirmed )
171             {
172                 List propertiesRequired = archetypeConfiguration.getRequiredProperties();
173                 getLogger().debug( "Required properties before content sort: " + propertiesRequired );
174                 Collections.sort( propertiesRequired, new RequiredPropertyComparator( archetypeConfiguration ) );
175                 getLogger().debug( "Required properties after content sort: " + propertiesRequired );
176 
177                 if ( !archetypeConfiguration.isConfigured() )
178                 {
179                     for ( Iterator requiredProperties = propertiesRequired.iterator(); requiredProperties.hasNext(); )
180                     {
181                         String requiredProperty = (String) requiredProperties.next();
182 
183                         if ( !archetypeConfiguration.isConfigured( requiredProperty ) )
184                         {
185                             if ( "package".equals( requiredProperty ) )
186                             {
187                                 // if the asked property is 'package', then
188                                 // use its default and if not defined,
189                                 // use the 'groupId' property value.
190                                 String packageDefault = archetypeConfiguration.getDefaultValue( requiredProperty );
191                                 packageDefault =
192                                     ( null == packageDefault || "".equals( packageDefault ) ) ? archetypeConfiguration.getProperty( "groupId" )
193                                                     : archetypeConfiguration.getDefaultValue( requiredProperty );
194 
195                                 archetypeConfiguration.setProperty(
196                                                                     requiredProperty,
197                                                                     archetypeGenerationQueryer.getPropertyValue(
198                                                                                                                  requiredProperty,
199                                                                                                                  getTransitiveDefaultValue(
200                                                                                                                                             packageDefault,
201                                                                                                                                             archetypeConfiguration ) ) );
202                             }
203                             else
204                             {
205                                 archetypeConfiguration.setProperty(
206                                                                     requiredProperty,
207                                                                     archetypeGenerationQueryer.getPropertyValue(
208                                                                                                                  requiredProperty,
209                                                                                                                  getTransitiveDefaultValue(
210                                                                                                                                             archetypeConfiguration.getDefaultValue( requiredProperty ),
211                                                                                                                                             archetypeConfiguration ) ) );
212                             }
213                         }
214                         else
215                         {
216                             getLogger().info(
217                                               "Using property: " + requiredProperty + " = "
218                                                   + archetypeConfiguration.getProperty( requiredProperty ) );
219                         }
220                     }
221                 }
222                 else
223                 {
224 
225                     for ( Iterator requiredProperties = propertiesRequired.iterator(); requiredProperties.hasNext(); )
226                     {
227                         String requiredProperty = (String) requiredProperties.next();
228 
229                         getLogger().info(
230                                           "Using property: " + requiredProperty + " = "
231                                               + archetypeConfiguration.getProperty( requiredProperty ) );
232                     }
233                 }
234 
235                 if ( !archetypeConfiguration.isConfigured() )
236                 {
237                     getLogger().warn( "Archetype is not fully configured" );
238                 }
239                 else if ( !archetypeGenerationQueryer.confirmConfiguration( archetypeConfiguration ) )
240                 {
241                     getLogger().debug( "Archetype generation configuration not confirmed" );
242                     archetypeConfiguration.reset();
243                     restoreCommandLineProperties( archetypeConfiguration, executionProperties );
244                 }
245                 else
246                 {
247                     getLogger().debug( "Archetype generation configuration confirmed" );
248 
249                     confirmed = true;
250                 }
251             }
252         }
253         else
254         {
255             if ( !archetypeConfiguration.isConfigured() )
256             {
257                 for ( Iterator requiredProperties = archetypeConfiguration.getRequiredProperties().iterator();
258                     requiredProperties.hasNext(); )
259                 {
260                     String requiredProperty = (String) requiredProperties.next();
261 
262                     if ( !archetypeConfiguration.isConfigured( requiredProperty )
263                         && ( archetypeConfiguration.getDefaultValue( requiredProperty ) != null ) )
264                     {
265                         archetypeConfiguration.setProperty( requiredProperty,
266                                                             archetypeConfiguration.getDefaultValue( requiredProperty ) );
267                     }
268                 }
269 
270                 // in batch mode, we assume the defaults, and if still not configured fail
271                 if ( !archetypeConfiguration.isConfigured() )
272                 {
273                     StringBuffer exceptionMessage = new StringBuffer();
274                     exceptionMessage.append( "Archetype " );
275                     exceptionMessage.append( request.getArchetypeGroupId() );
276                     exceptionMessage.append( ":" );
277                     exceptionMessage.append( request.getArchetypeArtifactId() );
278                     exceptionMessage.append( ":" );
279                     exceptionMessage.append( request.getArchetypeVersion() );
280                     exceptionMessage.append( " is not configured" );
281 
282                     List missingProperties = new ArrayList( 0 );
283                     for ( Iterator requiredProperties = archetypeConfiguration.getRequiredProperties().iterator();
284                         requiredProperties.hasNext(); )
285                     {
286                         String requiredProperty = (String) requiredProperties.next();
287 
288                         if ( !archetypeConfiguration.isConfigured( requiredProperty ) )
289                         {
290                             exceptionMessage.append( "\n\tProperty " );
291                             exceptionMessage.append( requiredProperty );
292                             missingProperties.add( requiredProperty );
293                             exceptionMessage.append( " is missing." );
294                             getLogger().warn(
295                                               "Property " + requiredProperty + " is missing. Add -D" + requiredProperty
296                                                   + "=someValue" );
297                         }
298                     }
299 
300                     throw new ArchetypeNotConfigured( exceptionMessage.toString(), missingProperties );
301                 }
302             }
303         }
304 
305         request.setGroupId( archetypeConfiguration.getProperty( Constants.GROUP_ID ) );
306 
307         request.setArtifactId( archetypeConfiguration.getProperty( Constants.ARTIFACT_ID ) );
308 
309         request.setVersion( archetypeConfiguration.getProperty( Constants.VERSION ) );
310 
311         request.setPackage( archetypeConfiguration.getProperty( Constants.PACKAGE ) );
312 
313         properties = archetypeConfiguration.getProperties();
314 
315         request.setProperties( properties );
316     }
317 
318     private String getTransitiveDefaultValue( String defaultValue, ArchetypeConfiguration archetypeConfiguration )
319     {
320         String result = defaultValue;
321         if ( null == result )
322         {
323             return null;
324         }
325         for ( Iterator requiredProperties = archetypeConfiguration.getRequiredProperties().iterator();
326             requiredProperties.hasNext(); )
327         {
328             String property = (String) requiredProperties.next();
329 
330             if ( result.indexOf( "${" + property + "}" ) >= 0 )
331             {
332                 result = StringUtils.replace( result, "${" + property + "}",
333                                               archetypeConfiguration.getProperty(property) );
334             }
335         }
336         return result;
337     }
338 
339     private void restoreCommandLineProperties( ArchetypeConfiguration archetypeConfiguration,
340         Properties executionProperties )
341     {
342         getLogger().debug( "Restoring command line properties" );
343 
344         for ( Iterator properties = archetypeConfiguration.getRequiredProperties().iterator(); properties.hasNext(); )
345         {
346             String property = (String) properties.next();
347 
348             if ( executionProperties.containsKey( property ) )
349             {
350                 archetypeConfiguration.setProperty( property, executionProperties.getProperty( property ) );
351                 getLogger().debug( "Restored " + property + "=" + archetypeConfiguration.getProperty( property ) );
352             }
353         }
354     }
355 
356     public static class RequiredPropertyComparator implements Comparator
357     {
358         private final ArchetypeConfiguration archetypeConfiguration;
359 
360         public RequiredPropertyComparator( ArchetypeConfiguration archetypeConfiguration )
361         {
362             this.archetypeConfiguration = archetypeConfiguration;
363         }
364 
365         public int compare( Object left, Object right )
366         {
367             if ( !( left instanceof String ) || !( right instanceof String ) )
368             {
369                 return 0;
370             }
371             else
372             {
373                 String leftDefault = archetypeConfiguration.getDefaultValue( (String) left );
374                 String rightDefault = archetypeConfiguration.getDefaultValue( (String) right );
375                 if ( null == leftDefault || null == rightDefault )
376                 {
377                     return comparePropertyName( (String) left, (String) right );
378                 }
379                 else if ( leftDefault.indexOf( "${" + right + "}" ) >= 0 )
380                 {//left contains right
381                     return 1;
382                 }
383                 else if ( rightDefault.indexOf( "${" + left + "}" ) >= 0 )
384                 {//right contains left
385                     return -1;
386                 }
387                 else
388                 {
389                     return comparePropertyName( (String) left, (String) right );
390                 }
391             }
392         }
393 
394         private int comparePropertyName( String left, String right )
395         {
396             if ( "groupId".equals( left ) )
397             {
398                 return -1;
399             }
400             if ( "groupId".equals( right ) )
401             {
402                 return 1;
403             }
404             if ( "artifactId".equals( left ) )
405             {
406                 return -1;
407             }
408             if ( "artifactId".equals( right ) )
409             {
410                 return 1;
411             }
412             if ( "version".equals( left ) )
413             {
414                 return -1;
415             }
416             if ( "version".equals( right ) )
417             {
418                 return 1;
419             }
420             if ( "package".equals( left ) )
421             {
422                 return -1;
423             }
424             if ( "package".equals( right ) )
425             {
426                 return 1;
427             }
428             return left.compareTo( right );
429         }
430     }
431 }