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.StringUtils;
45
46 import java.io.IOException;
47 import java.io.StringWriter;
48 import java.util.ArrayList;
49 import java.util.Collections;
50 import java.util.Comparator;
51 import java.util.List;
52 import java.util.Properties;
53
54
55 @Component( role = ArchetypeGenerationConfigurator.class, hint = "default" )
56 public class DefaultArchetypeGenerationConfigurator
57 extends AbstractLogEnabled
58 implements ArchetypeGenerationConfigurator
59 {
60 @Requirement
61 OldArchetype oldArchetype;
62
63 @Requirement
64 private ArchetypeArtifactManager archetypeArtifactManager;
65
66 @Requirement
67 private ArchetypeFactory archetypeFactory;
68
69 @Requirement
70 private ArchetypeGenerationQueryer archetypeGenerationQueryer;
71
72
73
74
75 @Requirement
76 private ArtifactRepositoryLayout defaultArtifactRepositoryLayout;
77
78 public void setArchetypeArtifactManager( ArchetypeArtifactManager archetypeArtifactManager )
79 {
80 this.archetypeArtifactManager = archetypeArtifactManager;
81 }
82
83 @Override
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<>();
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 StringBuilder exceptionMessage = new StringBuilder();
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<>( 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
344 try ( StringWriter stringWriter = new StringWriter() )
345 {
346 Velocity.evaluate( context, stringWriter, property, value );
347 return stringWriter.toString();
348 }
349 catch ( Exception ex )
350 {
351 return value;
352 }
353 }
354
355
356 private void restoreCommandLineProperties( ArchetypeConfiguration archetypeConfiguration,
357 Properties executionProperties )
358 {
359 getLogger().debug( "Restoring command line properties" );
360
361 for ( String property : archetypeConfiguration.getRequiredProperties() )
362 {
363 if ( executionProperties.containsKey( property ) )
364 {
365 archetypeConfiguration.setProperty( property, executionProperties.getProperty( property ) );
366 getLogger().debug( "Restored " + property + "=" + archetypeConfiguration.getProperty( property ) );
367 }
368 }
369 }
370
371 public static class RequiredPropertyComparator
372 implements Comparator<String>
373 {
374 private final ArchetypeConfiguration archetypeConfiguration;
375
376 public RequiredPropertyComparator( ArchetypeConfiguration archetypeConfiguration )
377 {
378 this.archetypeConfiguration = archetypeConfiguration;
379 }
380
381 @Override
382 public int compare( String left, String right )
383 {
384 String leftDefault = archetypeConfiguration.getDefaultValue( left );
385
386 if ( ( leftDefault != null ) && leftDefault.indexOf( "${" + right + "}" ) >= 0 )
387 {
388 return 1;
389 }
390
391 String rightDefault = archetypeConfiguration.getDefaultValue( right );
392
393 if ( ( rightDefault != null ) && rightDefault.indexOf( "${" + left + "}" ) >= 0 )
394 {
395 return -1;
396 }
397
398 return comparePropertyName( left, right );
399 }
400
401 private int comparePropertyName( String left, String right )
402 {
403 if ( "groupId".equals( left ) )
404 {
405 return -1;
406 }
407 if ( "groupId".equals( right ) )
408 {
409 return 1;
410 }
411 if ( "artifactId".equals( left ) )
412 {
413 return -1;
414 }
415 if ( "artifactId".equals( right ) )
416 {
417 return 1;
418 }
419 if ( "version".equals( left ) )
420 {
421 return -1;
422 }
423 if ( "version".equals( right ) )
424 {
425 return 1;
426 }
427 if ( "package".equals( left ) )
428 {
429 return -1;
430 }
431 if ( "package".equals( right ) )
432 {
433 return 1;
434 }
435 return left.compareTo( right );
436 }
437 }
438
439 private ArtifactRepository createRepository( String url, String repositoryId )
440 {
441
442
443
444
445
446
447
448 String updatePolicyFlag = ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS;
449
450 String checksumPolicyFlag = ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN;
451
452 ArtifactRepositoryPolicy snapshotsPolicy =
453 new ArtifactRepositoryPolicy( true, updatePolicyFlag, checksumPolicyFlag );
454
455 ArtifactRepositoryPolicy releasesPolicy =
456 new ArtifactRepositoryPolicy( true, updatePolicyFlag, checksumPolicyFlag );
457
458 return new MavenArtifactRepository( repositoryId, url, defaultArtifactRepositoryLayout, snapshotsPolicy,
459 releasesPolicy );
460 }
461
462 }