1 package org.apache.maven.archetype.ui.generation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.archetype.ArchetypeGenerationRequest;
23 import org.apache.maven.archetype.common.ArchetypeArtifactManager;
24 import org.apache.maven.archetype.common.Constants;
25 import org.apache.maven.archetype.exception.ArchetypeGenerationConfigurationFailure;
26 import org.apache.maven.archetype.exception.ArchetypeNotConfigured;
27 import org.apache.maven.archetype.exception.ArchetypeNotDefined;
28 import org.apache.maven.archetype.exception.UnknownArchetype;
29 import org.apache.maven.archetype.old.OldArchetype;
30 import org.apache.maven.archetype.ui.ArchetypeConfiguration;
31 import org.apache.maven.archetype.ui.ArchetypeDefinition;
32 import org.apache.maven.archetype.ui.ArchetypeFactory;
33 import org.apache.maven.artifact.repository.ArtifactRepository;
34 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
35 import org.apache.maven.artifact.repository.MavenArtifactRepository;
36 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
37 import org.apache.velocity.VelocityContext;
38 import org.apache.velocity.app.Velocity;
39 import org.apache.velocity.context.Context;
40 import org.codehaus.plexus.component.annotations.Component;
41 import org.codehaus.plexus.component.annotations.Requirement;
42 import org.codehaus.plexus.components.interactivity.PrompterException;
43 import org.codehaus.plexus.logging.AbstractLogEnabled;
44 import org.codehaus.plexus.util.IOUtil;
45 import org.codehaus.plexus.util.StringUtils;
46
47 import java.io.IOException;
48 import java.io.StringWriter;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.Comparator;
52 import java.util.List;
53 import java.util.Properties;
54
55
56 @Component( role = ArchetypeGenerationConfigurator.class, hint = "default" )
57 public class DefaultArchetypeGenerationConfigurator
58 extends AbstractLogEnabled
59 implements ArchetypeGenerationConfigurator
60 {
61 @Requirement
62 OldArchetype oldArchetype;
63
64 @Requirement
65 private ArchetypeArtifactManager archetypeArtifactManager;
66
67 @Requirement
68 private ArchetypeFactory archetypeFactory;
69
70 @Requirement
71 private ArchetypeGenerationQueryer archetypeGenerationQueryer;
72
73
74
75
76 @Requirement
77 private ArtifactRepositoryLayout defaultArtifactRepositoryLayout;
78
79 public void setArchetypeArtifactManager( ArchetypeArtifactManager archetypeArtifactManager )
80 {
81 this.archetypeArtifactManager = archetypeArtifactManager;
82 }
83
84 public void configureArchetype( ArchetypeGenerationRequest request, Boolean interactiveMode,
85 Properties executionProperties )
86 throws ArchetypeNotDefined, UnknownArchetype, ArchetypeNotConfigured, IOException, PrompterException,
87 ArchetypeGenerationConfigurationFailure
88 {
89 ArtifactRepository localRepository = request.getLocalRepository();
90
91 ArtifactRepository archetypeRepository = null;
92
93 List<ArtifactRepository> repositories = new ArrayList<ArtifactRepository>();
94
95 Properties properties = new Properties( executionProperties );
96
97 ArchetypeDefinition ad = new ArchetypeDefinition( request );
98
99 if ( !ad.isDefined() )
100 {
101 if ( !interactiveMode.booleanValue() )
102 {
103 throw new ArchetypeNotDefined( "No archetype was chosen" );
104 }
105 else
106 {
107 throw new ArchetypeNotDefined( "The archetype is not defined" );
108 }
109 }
110 if ( request.getArchetypeRepository() != null )
111 {
112 archetypeRepository = createRepository( request.getArchetypeRepository(),
113 ad.getArtifactId() + "-repo" );
114 repositories.add( archetypeRepository );
115 }
116 if ( request.getRemoteArtifactRepositories() != null )
117 {
118 repositories.addAll( request.getRemoteArtifactRepositories() );
119 }
120
121 if ( !archetypeArtifactManager.exists( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
122 archetypeRepository, localRepository, repositories,
123 request.getProjectBuildingRequest() ) )
124 {
125 throw new UnknownArchetype( "The desired archetype does not exist (" + ad.getGroupId() + ":"
126 + ad.getArtifactId() + ":" + ad.getVersion() + ")" );
127 }
128
129 request.setArchetypeVersion( ad.getVersion() );
130
131 ArchetypeConfiguration archetypeConfiguration;
132
133 if ( archetypeArtifactManager.isFileSetArchetype( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
134 archetypeRepository, localRepository, repositories,
135 request.getProjectBuildingRequest() ) )
136 {
137 org.apache.maven.archetype.metadata.ArchetypeDescriptor archetypeDescriptor =
138 archetypeArtifactManager.getFileSetArchetypeDescriptor( ad.getGroupId(), ad.getArtifactId(),
139 ad.getVersion(), archetypeRepository,
140 localRepository, repositories,
141 request.getProjectBuildingRequest() );
142
143 archetypeConfiguration = archetypeFactory.createArchetypeConfiguration( archetypeDescriptor, properties );
144 }
145 else if ( archetypeArtifactManager.isOldArchetype( ad.getGroupId(), ad.getArtifactId(), ad.getVersion(),
146 archetypeRepository, localRepository, repositories,
147 request.getProjectBuildingRequest() ) )
148 {
149 org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor archetypeDescriptor =
150 archetypeArtifactManager.getOldArchetypeDescriptor( ad.getGroupId(), ad.getArtifactId(),
151 ad.getVersion(), archetypeRepository,
152 localRepository, repositories,
153 request.getProjectBuildingRequest() );
154
155 archetypeConfiguration = archetypeFactory.createArchetypeConfiguration( archetypeDescriptor, properties );
156 }
157 else
158 {
159 throw new ArchetypeGenerationConfigurationFailure( "The defined artifact is not an archetype" );
160 }
161
162 Context context = new VelocityContext();
163 if ( interactiveMode.booleanValue() )
164 {
165 boolean confirmed = false;
166 context.put( Constants.GROUP_ID, ad.getGroupId() );
167 context.put( Constants.ARTIFACT_ID, ad.getArtifactId() );
168 context.put( Constants.VERSION, ad.getVersion() );
169 while ( !confirmed )
170 {
171 List<String> propertiesRequired = archetypeConfiguration.getRequiredProperties();
172 getLogger().debug( "Required properties before content sort: " + propertiesRequired );
173 Collections.sort( propertiesRequired, new RequiredPropertyComparator( archetypeConfiguration ) );
174 getLogger().debug( "Required properties after content sort: " + propertiesRequired );
175
176 if ( !archetypeConfiguration.isConfigured() )
177 {
178 for ( String requiredProperty : propertiesRequired )
179 {
180 if ( !archetypeConfiguration.isConfigured( requiredProperty ) )
181 {
182 if ( "package".equals( requiredProperty ) )
183 {
184
185
186
187 String packageDefault = archetypeConfiguration.getDefaultValue( requiredProperty );
188 packageDefault = ( null == packageDefault || "".equals( packageDefault ) )
189 ? archetypeConfiguration.getProperty( "groupId" )
190 : archetypeConfiguration.getDefaultValue( requiredProperty );
191
192 String value =
193 getTransitiveDefaultValue( packageDefault, archetypeConfiguration, requiredProperty,
194 context );
195
196 value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value, null );
197
198 archetypeConfiguration.setProperty( requiredProperty, value );
199
200 context.put( Constants.PACKAGE, value );
201 }
202 else
203 {
204 String value = archetypeConfiguration.getDefaultValue( requiredProperty );
205
206 value = getTransitiveDefaultValue( value, archetypeConfiguration, requiredProperty,
207 context );
208
209 value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value,
210 archetypeConfiguration.getPropertyValidationRegex( requiredProperty ) );
211
212 archetypeConfiguration.setProperty( requiredProperty, value );
213
214 context.put( requiredProperty, value );
215 }
216 }
217 else
218 {
219 getLogger().info(
220 "Using property: " + requiredProperty + " = " + archetypeConfiguration.getProperty(
221 requiredProperty ) );
222 archetypeConfiguration.setProperty( requiredProperty, archetypeConfiguration.getProperty(
223 requiredProperty ) );
224 }
225 }
226 }
227 else
228 {
229
230 for ( String requiredProperty : propertiesRequired )
231 {
232 getLogger().info(
233 "Using property: " + requiredProperty + " = " + archetypeConfiguration.getProperty(
234 requiredProperty ) );
235 }
236 }
237
238 if ( !archetypeConfiguration.isConfigured() )
239 {
240 getLogger().warn( "Archetype is not fully configured" );
241 }
242 else if ( !archetypeGenerationQueryer.confirmConfiguration( archetypeConfiguration ) )
243 {
244 getLogger().debug( "Archetype generation configuration not confirmed" );
245 archetypeConfiguration.reset();
246 restoreCommandLineProperties( archetypeConfiguration, executionProperties );
247 }
248 else
249 {
250 getLogger().debug( "Archetype generation configuration confirmed" );
251
252 confirmed = true;
253 }
254 }
255 }
256 else
257 {
258 if ( !archetypeConfiguration.isConfigured() )
259 {
260 for ( String requiredProperty : archetypeConfiguration.getRequiredProperties() )
261 {
262 if ( !archetypeConfiguration.isConfigured( requiredProperty ) && (
263 archetypeConfiguration.getDefaultValue( requiredProperty ) != null ) )
264 {
265 String value = archetypeConfiguration.getDefaultValue( requiredProperty );
266 value = getTransitiveDefaultValue( value, archetypeConfiguration, requiredProperty, context );
267 archetypeConfiguration.setProperty( requiredProperty, value );
268 context.put( requiredProperty, value );
269 }
270 }
271
272
273 if ( !archetypeConfiguration.isConfigured() )
274 {
275 StringBuffer exceptionMessage = new StringBuffer();
276 exceptionMessage.append( "Archetype " );
277 exceptionMessage.append( request.getArchetypeGroupId() );
278 exceptionMessage.append( ":" );
279 exceptionMessage.append( request.getArchetypeArtifactId() );
280 exceptionMessage.append( ":" );
281 exceptionMessage.append( request.getArchetypeVersion() );
282 exceptionMessage.append( " is not configured" );
283
284 List<String> missingProperties = new ArrayList<String>( 0 );
285 for ( String requiredProperty : archetypeConfiguration.getRequiredProperties() )
286 {
287 if ( !archetypeConfiguration.isConfigured( requiredProperty ) )
288 {
289 exceptionMessage.append( "\n\tProperty " );
290 exceptionMessage.append( requiredProperty );
291 missingProperties.add( requiredProperty );
292 exceptionMessage.append( " is missing." );
293 getLogger().warn( "Property " + requiredProperty + " is missing. Add -D" + requiredProperty
294 + "=someValue" );
295 }
296 }
297
298 throw new ArchetypeNotConfigured( exceptionMessage.toString(), missingProperties );
299 }
300 }
301 }
302
303 request.setGroupId( archetypeConfiguration.getProperty( Constants.GROUP_ID ) );
304
305 request.setArtifactId( archetypeConfiguration.getProperty( Constants.ARTIFACT_ID ) );
306
307 request.setVersion( archetypeConfiguration.getProperty( Constants.VERSION ) );
308
309 request.setPackage( archetypeConfiguration.getProperty( Constants.PACKAGE ) );
310
311 properties = archetypeConfiguration.getProperties();
312
313 request.setProperties( properties );
314 }
315
316 private String getTransitiveDefaultValue( String defaultValue, ArchetypeConfiguration archetypeConfiguration,
317 String requiredProperty, Context context )
318 {
319 String result = defaultValue;
320 if ( null == result )
321 {
322 return null;
323 }
324 for ( String property : archetypeConfiguration.getRequiredProperties() )
325 {
326 if ( result.indexOf( "${" + property + "}" ) >= 0 )
327 {
328
329 result = StringUtils.replace( result, "${" + property + "}",
330 archetypeConfiguration.getProperty( property ) );
331 }
332 }
333 if ( result.contains( "${" ) )
334 {
335 result = evaluateProperty( context, requiredProperty, defaultValue );
336 }
337 return result;
338 }
339
340
341 private String evaluateProperty( Context context, String property, String value )
342 {
343 StringWriter stringWriter = new StringWriter();
344 try
345 {
346 Velocity.evaluate( context, stringWriter, property, value );
347 return stringWriter.toString();
348 }
349 catch ( Exception ex )
350 {
351 return value;
352 }
353 finally
354 {
355 IOUtil.close( stringWriter );
356 }
357 }
358
359
360 private void restoreCommandLineProperties( ArchetypeConfiguration archetypeConfiguration,
361 Properties executionProperties )
362 {
363 getLogger().debug( "Restoring command line properties" );
364
365 for ( String property : archetypeConfiguration.getRequiredProperties() )
366 {
367 if ( executionProperties.containsKey( property ) )
368 {
369 archetypeConfiguration.setProperty( property, executionProperties.getProperty( property ) );
370 getLogger().debug( "Restored " + property + "=" + archetypeConfiguration.getProperty( property ) );
371 }
372 }
373 }
374
375 public static class RequiredPropertyComparator
376 implements Comparator<String>
377 {
378 private final ArchetypeConfiguration archetypeConfiguration;
379
380 public RequiredPropertyComparator( ArchetypeConfiguration archetypeConfiguration )
381 {
382 this.archetypeConfiguration = archetypeConfiguration;
383 }
384
385 public int compare( String left, String right )
386 {
387 String leftDefault = archetypeConfiguration.getDefaultValue( left );
388
389 if ( ( leftDefault != null ) && leftDefault.indexOf( "${" + right + "}" ) >= 0 )
390 {
391 return 1;
392 }
393
394 String rightDefault = archetypeConfiguration.getDefaultValue( right );
395
396 if ( ( rightDefault != null ) && rightDefault.indexOf( "${" + left + "}" ) >= 0 )
397 {
398 return -1;
399 }
400
401 return comparePropertyName( left, right );
402 }
403
404 private int comparePropertyName( String left, String right )
405 {
406 if ( "groupId".equals( left ) )
407 {
408 return -1;
409 }
410 if ( "groupId".equals( right ) )
411 {
412 return 1;
413 }
414 if ( "artifactId".equals( left ) )
415 {
416 return -1;
417 }
418 if ( "artifactId".equals( right ) )
419 {
420 return 1;
421 }
422 if ( "version".equals( left ) )
423 {
424 return -1;
425 }
426 if ( "version".equals( right ) )
427 {
428 return 1;
429 }
430 if ( "package".equals( left ) )
431 {
432 return -1;
433 }
434 if ( "package".equals( right ) )
435 {
436 return 1;
437 }
438 return left.compareTo( right );
439 }
440 }
441
442 private ArtifactRepository createRepository( String url, String repositoryId )
443 {
444
445
446
447
448
449
450
451 String updatePolicyFlag = ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS;
452
453 String checksumPolicyFlag = ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN;
454
455 ArtifactRepositoryPolicy snapshotsPolicy =
456 new ArtifactRepositoryPolicy( true, updatePolicyFlag, checksumPolicyFlag );
457
458 ArtifactRepositoryPolicy releasesPolicy =
459 new ArtifactRepositoryPolicy( true, updatePolicyFlag, checksumPolicyFlag );
460
461 return new MavenArtifactRepository( repositoryId, url, defaultArtifactRepositoryLayout, snapshotsPolicy,
462 releasesPolicy );
463 }
464
465 }