1 package org.apache.maven.archetype.generator;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import groovy.lang.Binding;
23 import groovy.lang.GroovyShell;
24 import org.apache.maven.archetype.ArchetypeGenerationRequest;
25 import org.apache.maven.archetype.common.ArchetypeArtifactManager;
26 import org.apache.maven.archetype.common.ArchetypeFilesResolver;
27 import org.apache.maven.archetype.common.Constants;
28 import org.apache.maven.archetype.common.PomManager;
29 import org.apache.maven.archetype.exception.ArchetypeGenerationFailure;
30 import org.apache.maven.archetype.exception.ArchetypeNotConfigured;
31 import org.apache.maven.archetype.exception.InvalidPackaging;
32 import org.apache.maven.archetype.exception.OutputFileExists;
33 import org.apache.maven.archetype.exception.PomFileExists;
34 import org.apache.maven.archetype.exception.ProjectDirectoryExists;
35 import org.apache.maven.archetype.exception.UnknownArchetype;
36 import org.apache.maven.archetype.metadata.AbstractArchetypeDescriptor;
37 import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
38 import org.apache.maven.archetype.metadata.FileSet;
39 import org.apache.maven.archetype.metadata.ModuleDescriptor;
40 import org.apache.maven.archetype.metadata.RequiredProperty;
41 import org.apache.velocity.VelocityContext;
42 import org.apache.velocity.app.Velocity;
43 import org.apache.velocity.context.Context;
44 import org.codehaus.plexus.component.annotations.Component;
45 import org.codehaus.plexus.component.annotations.Requirement;
46 import org.codehaus.plexus.logging.AbstractLogEnabled;
47 import org.codehaus.plexus.util.FileUtils;
48 import org.codehaus.plexus.util.IOUtil;
49 import org.codehaus.plexus.util.StringUtils;
50 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
51 import org.codehaus.plexus.velocity.VelocityComponent;
52 import org.dom4j.DocumentException;
53
54 import java.io.File;
55 import java.io.FileNotFoundException;
56 import java.io.FileOutputStream;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.io.OutputStream;
60 import java.io.OutputStreamWriter;
61 import java.io.StringWriter;
62 import java.io.Writer;
63 import java.util.ArrayList;
64 import java.util.Iterator;
65 import java.util.List;
66 import java.util.Map;
67 import java.util.Properties;
68 import java.util.regex.Pattern;
69 import java.util.zip.ZipEntry;
70 import java.util.zip.ZipFile;
71
72 @Component( role = FilesetArchetypeGenerator.class )
73 public class DefaultFilesetArchetypeGenerator
74 extends AbstractLogEnabled
75 implements FilesetArchetypeGenerator
76 {
77 @Requirement
78 private ArchetypeArtifactManager archetypeArtifactManager;
79
80 @Requirement
81 private ArchetypeFilesResolver archetypeFilesResolver;
82
83 @Requirement
84 private PomManager pomManager;
85
86 @Requirement
87 private VelocityComponent velocity;
88
89
90
91
92 private static final String DELIMITER = "__";
93
94
95
96
97
98 private static final Pattern TOKEN_PATTERN = Pattern.compile( ".*" + DELIMITER + ".*" + DELIMITER + ".*" );
99
100 public void generateArchetype( ArchetypeGenerationRequest request, File archetypeFile )
101 throws UnknownArchetype, ArchetypeNotConfigured, ProjectDirectoryExists, PomFileExists, OutputFileExists,
102 ArchetypeGenerationFailure
103 {
104 ClassLoader old = Thread.currentThread().getContextClassLoader();
105
106 try
107 {
108 ArchetypeDescriptor archetypeDescriptor =
109 archetypeArtifactManager.getFileSetArchetypeDescriptor( archetypeFile );
110
111 if ( !isArchetypeConfigured( archetypeDescriptor, request ) )
112 {
113 if ( request.isInteractiveMode() )
114 {
115 throw new ArchetypeNotConfigured( "No archetype was chosen.", null );
116 }
117
118 StringBuffer exceptionMessage = new StringBuffer(
119 "Archetype " + request.getArchetypeGroupId() + ":" + request.getArchetypeArtifactId() + ":"
120 + request.getArchetypeVersion() + " is not configured" );
121
122 List<String> missingProperties = new ArrayList<String>( 0 );
123 for ( RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties() )
124 {
125 if ( StringUtils.isEmpty( request.getProperties().getProperty( requiredProperty.getKey() ) ) )
126 {
127 exceptionMessage.append( "\n\tProperty " + requiredProperty.getKey() + " is missing." );
128
129 missingProperties.add( requiredProperty.getKey() );
130 }
131 }
132
133 throw new ArchetypeNotConfigured( exceptionMessage.toString(), missingProperties );
134 }
135
136 Context context = prepareVelocityContext( request );
137
138 String packageName = request.getPackage();
139 String artifactId = request.getArtifactId();
140 File outputDirectoryFile = new File( request.getOutputDirectory(), artifactId );
141 File basedirPom = new File( request.getOutputDirectory(), Constants.ARCHETYPE_POM );
142 File pom = new File( outputDirectoryFile, Constants.ARCHETYPE_POM );
143
144 List<String> archetypeResources = archetypeArtifactManager.getFilesetArchetypeResources( archetypeFile );
145
146 ZipFile archetypeZipFile = archetypeArtifactManager.getArchetypeZipFile( archetypeFile );
147
148 ClassLoader archetypeJarLoader = archetypeArtifactManager.getArchetypeJarLoader( archetypeFile );
149
150 Thread.currentThread().setContextClassLoader( archetypeJarLoader );
151
152 if ( archetypeDescriptor.isPartial() )
153 {
154 getLogger().debug( "Processing partial archetype " + archetypeDescriptor.getName() );
155 if ( outputDirectoryFile.exists() )
156 {
157 if ( !pom.exists() )
158 {
159 throw new PomFileExists( "This is a partial archetype and the pom.xml file doesn't exist." );
160 }
161
162 processPomWithMerge( context, pom, "" );
163
164 processArchetypeTemplatesWithWarning( archetypeDescriptor, archetypeResources, archetypeZipFile, "",
165 context, packageName, outputDirectoryFile );
166 }
167 else
168 {
169 if ( basedirPom.exists() )
170 {
171 processPomWithMerge( context, basedirPom, "" );
172
173 processArchetypeTemplatesWithWarning( archetypeDescriptor, archetypeResources, archetypeZipFile,
174 "", context, packageName,
175 new File( request.getOutputDirectory() ) );
176 }
177 else
178 {
179 processPom( context, pom, "" );
180
181 processArchetypeTemplates( archetypeDescriptor, archetypeResources, archetypeZipFile, "",
182 context, packageName, outputDirectoryFile );
183 }
184 }
185
186 if ( archetypeDescriptor.getModules().size() > 0 )
187 {
188 getLogger().info( "Modules ignored in partial mode" );
189 }
190 }
191 else
192 {
193 getLogger().debug( "Processing complete archetype " + archetypeDescriptor.getName() );
194 if ( outputDirectoryFile.exists() && pom.exists() )
195 {
196 throw new ProjectDirectoryExists(
197 "A Maven 2 project already exists in the directory " + outputDirectoryFile.getPath() );
198 }
199
200 if ( outputDirectoryFile.exists() )
201 {
202 getLogger().warn( "The directory " + outputDirectoryFile.getPath() + " already exists." );
203 }
204
205 context.put( "rootArtifactId", artifactId );
206
207 processFilesetModule( artifactId, artifactId, archetypeResources, pom, archetypeZipFile, "", basedirPom,
208 outputDirectoryFile, packageName, archetypeDescriptor, context );
209 }
210
211 String postGenerationScript = archetypeArtifactManager.getPostGenerationScript( archetypeFile );
212 if ( postGenerationScript != null )
213 {
214 getLogger().info( "Executing " + Constants.ARCHETYPE_POST_GENERATION_SCRIPT
215 + " post-generation script" );
216
217 Binding binding = new Binding();
218
219 final Properties archetypeGeneratorProperties = new Properties();
220 archetypeGeneratorProperties.putAll( System.getProperties() );
221
222 if ( request.getProperties() != null )
223 {
224 archetypeGeneratorProperties.putAll( request.getProperties() );
225 }
226
227 for ( Map.Entry<Object, Object> entry : archetypeGeneratorProperties.entrySet() )
228 {
229 binding.setVariable( entry.getKey().toString(), entry.getValue() );
230 }
231
232 binding.setVariable( "request", request );
233
234 GroovyShell shell = new GroovyShell( binding );
235 shell.evaluate( postGenerationScript );
236 }
237
238
239
240
241 if ( getLogger().isInfoEnabled() )
242 {
243 getLogger().info( "Project created from Archetype in dir: " + outputDirectoryFile.getAbsolutePath() );
244 }
245 }
246 catch ( FileNotFoundException ex )
247 {
248 throw new ArchetypeGenerationFailure( ex );
249 }
250 catch ( IOException ex )
251 {
252 throw new ArchetypeGenerationFailure( ex );
253 }
254 catch ( XmlPullParserException ex )
255 {
256 throw new ArchetypeGenerationFailure( ex );
257 }
258 catch ( DocumentException ex )
259 {
260 throw new ArchetypeGenerationFailure( ex );
261 }
262 catch ( ArchetypeGenerationFailure ex )
263 {
264 throw new ArchetypeGenerationFailure( ex );
265 }
266 catch ( InvalidPackaging ex )
267 {
268 throw new ArchetypeGenerationFailure( ex );
269 }
270 finally
271 {
272 Thread.currentThread().setContextClassLoader( old );
273 }
274 }
275
276 public String getPackageAsDirectory( String packageName )
277 {
278 return StringUtils.replace( packageName, ".", "/" );
279 }
280
281 private boolean copyFile( final File outFile, final String template, final boolean failIfExists,
282 final ZipFile archetypeZipFile )
283 throws FileNotFoundException, OutputFileExists, IOException
284 {
285 getLogger().debug( "Copying file " + template );
286
287 if ( failIfExists && outFile.exists() )
288 {
289 throw new OutputFileExists( "Don't rewrite file " + outFile.getName() );
290 }
291 else if ( outFile.exists() )
292 {
293 getLogger().warn( "CP Don't override file " + outFile );
294
295 return false;
296 }
297
298 ZipEntry input = archetypeZipFile.getEntry( Constants.ARCHETYPE_RESOURCES + "/" + template );
299
300 if ( input.isDirectory() )
301 {
302 outFile.mkdirs();
303 }
304 else
305 {
306 InputStream inputStream = null;
307 OutputStream out = null;
308 try
309 {
310 inputStream = archetypeZipFile.getInputStream( input );
311
312 outFile.getParentFile().mkdirs();
313
314 out = new FileOutputStream( outFile );
315
316 IOUtil.copy( inputStream, out );
317 }
318 finally
319 {
320 IOUtil.close( inputStream );
321 IOUtil.close( out );
322 }
323 }
324
325 return true;
326 }
327
328 private int copyFiles( String directory, List<String> fileSetResources, boolean packaged, String packageName,
329 File outputDirectoryFile, ZipFile archetypeZipFile, String moduleOffset,
330 boolean failIfExists, Context context )
331 throws OutputFileExists, FileNotFoundException, IOException
332 {
333 int count = 0;
334
335 for ( String template : fileSetResources )
336 {
337 File outputFile =
338 getOutputFile( template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context );
339
340 if ( copyFile( outputFile, template, failIfExists, archetypeZipFile ) )
341 {
342 count++;
343 }
344 }
345
346 return count;
347 }
348
349 private String getEncoding( String archetypeEncoding )
350 {
351 return StringUtils.isEmpty( archetypeEncoding ) ? "UTF-8" : archetypeEncoding;
352 }
353
354 private String getOffsetSeparator( String moduleOffset )
355 {
356 return StringUtils.isEmpty( moduleOffset ) ? "/" : ( "/" + moduleOffset + "/" );
357 }
358
359 private File getOutputFile( String template, String directory, File outputDirectoryFile, boolean packaged,
360 String packageName, String moduleOffset, Context context )
361 {
362 String templateName = StringUtils.replaceOnce( template, directory, "" );
363
364 String outputFileName =
365 directory + "/" + ( packaged ? getPackageAsDirectory( packageName ) : "" ) + "/" + templateName.substring(
366 moduleOffset.length() );
367
368 if ( TOKEN_PATTERN.matcher( outputFileName ).matches() )
369 {
370 outputFileName = replaceFilenameTokens( outputFileName, context );
371 }
372
373 return new File( outputDirectoryFile, outputFileName );
374 }
375
376
377
378
379
380
381
382
383
384
385 private String replaceFilenameTokens( final String filePath, final Context context )
386 {
387 String interpolatedResult = filePath;
388
389 int start = 0;
390
391 while ( true )
392 {
393 start = interpolatedResult.indexOf( DELIMITER, start );
394
395 if ( start == -1 )
396 {
397 break;
398 }
399
400 int end = interpolatedResult.indexOf( DELIMITER, start + DELIMITER.length() );
401
402 if ( end == -1 )
403 {
404 break;
405 }
406
407 String propertyToken = interpolatedResult.substring( start + DELIMITER.length(), end );
408
409 String contextPropertyValue = (String) context.get( propertyToken );
410
411 if ( contextPropertyValue != null && contextPropertyValue.trim().length() > 0 )
412 {
413 String search = DELIMITER + propertyToken + DELIMITER;
414
415 if ( getLogger().isDebugEnabled() )
416 {
417 getLogger().debug(
418 "Replacing '" + search + "' in file path '" + interpolatedResult + "' with value '"
419 + contextPropertyValue + "'." );
420 }
421
422 interpolatedResult = StringUtils.replace( interpolatedResult, search, contextPropertyValue );
423
424 end = end + contextPropertyValue.length() - search.length();
425 }
426 else
427 {
428
429 getLogger().warn(
430 "Property '" + propertyToken + "' was not specified, so the token in '" + interpolatedResult
431 + "' is not being replaced." );
432 }
433
434 start = end + DELIMITER.length() + 1;
435 }
436
437 if ( getLogger().isDebugEnabled() )
438 {
439 getLogger().debug( "Final interpolated file path: '" + interpolatedResult + "'" );
440 }
441
442 return interpolatedResult;
443 }
444
445 private String getPackageInPathFormat( String aPackage )
446 {
447 return StringUtils.replace( aPackage, ".", "/" );
448 }
449
450 private boolean isArchetypeConfigured( ArchetypeDescriptor archetypeDescriptor, ArchetypeGenerationRequest request )
451 {
452 for ( RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties() )
453 {
454 if ( StringUtils.isEmpty( request.getProperties().getProperty( requiredProperty.getKey() ) ) )
455 {
456 return false;
457 }
458 }
459
460 return true;
461 }
462
463 private void setParentArtifactId( Context context, String artifactId )
464 {
465 context.put( Constants.PARENT_ARTIFACT_ID, artifactId );
466 }
467
468 private Context prepareVelocityContext( ArchetypeGenerationRequest request )
469 {
470 Context context = new VelocityContext();
471 context.put( Constants.GROUP_ID, request.getGroupId() );
472 context.put( Constants.ARTIFACT_ID, request.getArtifactId() );
473 context.put( Constants.VERSION, request.getVersion() );
474 context.put( Constants.PACKAGE, request.getPackage() );
475 final String packageInPathFormat = getPackageInPathFormat( request.getPackage() );
476 context.put( Constants.PACKAGE_IN_PATH_FORMAT, packageInPathFormat );
477
478 if ( getLogger().isInfoEnabled() )
479 {
480 getLogger().info( "----------------------------------------------------------------------------" );
481
482 getLogger().info(
483 "Using following parameters for creating project from Archetype: " + request.getArchetypeArtifactId()
484 + ":" + request.getArchetypeVersion() );
485
486 getLogger().info( "----------------------------------------------------------------------------" );
487 getLogger().info( "Parameter: " + Constants.GROUP_ID + ", Value: " + request.getGroupId() );
488 getLogger().info( "Parameter: " + Constants.ARTIFACT_ID + ", Value: " + request.getArtifactId() );
489 getLogger().info( "Parameter: " + Constants.VERSION + ", Value: " + request.getVersion() );
490 getLogger().info( "Parameter: " + Constants.PACKAGE + ", Value: " + request.getPackage() );
491 getLogger().info( "Parameter: " + Constants.PACKAGE_IN_PATH_FORMAT + ", Value: " + packageInPathFormat );
492 }
493
494 for ( Iterator<?> iterator = request.getProperties().keySet().iterator(); iterator.hasNext(); )
495 {
496 String key = (String) iterator.next();
497
498 String value = request.getProperties().getProperty( key );
499
500 if ( maybeVelocityExpression( value ) )
501 {
502 value = evaluateExpression( context, key, value );
503 }
504
505 context.put( key, value );
506
507 if ( getLogger().isInfoEnabled() )
508 {
509 getLogger().info( "Parameter: " + key + ", Value: " + value );
510 }
511 }
512 return context;
513 }
514
515 private boolean maybeVelocityExpression( String value )
516 {
517 return value != null && value.contains( "${" );
518 }
519
520 private String evaluateExpression( Context context, String key, String value )
521 {
522 StringWriter stringWriter = new StringWriter();
523 try
524 {
525 Velocity.evaluate( context, stringWriter, key, value );
526 return stringWriter.toString();
527 }
528 catch ( Exception ex )
529 {
530 return value;
531 }
532 finally
533 {
534 IOUtil.close( stringWriter );
535 }
536
537 }
538
539 private void processArchetypeTemplates( AbstractArchetypeDescriptor archetypeDescriptor,
540 List<String> archetypeResources, ZipFile archetypeZipFile,
541 String moduleOffset, Context context, String packageName,
542 File outputDirectoryFile )
543 throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
544 {
545 processTemplates( packageName, outputDirectoryFile, context, archetypeDescriptor, archetypeResources,
546 archetypeZipFile, moduleOffset, false );
547 }
548
549 private void processArchetypeTemplatesWithWarning( ArchetypeDescriptor archetypeDescriptor,
550 List<String> archetypeResources, ZipFile archetypeZipFile,
551 String moduleOffset, Context context, String packageName,
552 File outputDirectoryFile )
553 throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
554 {
555 processTemplates( packageName, outputDirectoryFile, context, archetypeDescriptor, archetypeResources,
556 archetypeZipFile, moduleOffset, true );
557 }
558
559 private int processFileSet( String directory, List<String> fileSetResources, boolean packaged, String packageName,
560 Context context, File outputDirectoryFile, String moduleOffset,
561 String archetypeEncoding, boolean failIfExists )
562 throws OutputFileExists, ArchetypeGenerationFailure
563 {
564 int count = 0;
565
566 for ( String template : fileSetResources )
567 {
568 File outputFile =
569 getOutputFile( template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context );
570
571 if ( processTemplate( outputFile, context, Constants.ARCHETYPE_RESOURCES + "/" + template,
572 archetypeEncoding, failIfExists ) )
573 {
574 count++;
575 }
576 }
577
578 return count;
579 }
580
581 private void processFilesetModule( final String rootArtifactId, final String artifactId,
582 final List<String> archetypeResources, File pom, final ZipFile archetypeZipFile,
583 String moduleOffset, File basedirPom, File outputDirectoryFile,
584 final String packageName, final AbstractArchetypeDescriptor archetypeDescriptor,
585 final Context context )
586 throws DocumentException, XmlPullParserException, ArchetypeGenerationFailure, InvalidPackaging, IOException,
587 OutputFileExists
588 {
589 outputDirectoryFile.mkdirs();
590 getLogger().debug( "Processing module " + artifactId );
591 getLogger().debug( "Processing module rootArtifactId " + rootArtifactId );
592 getLogger().debug( "Processing module pom " + pom );
593 getLogger().debug( "Processing module moduleOffset " + moduleOffset );
594 getLogger().debug( "Processing module outputDirectoryFile " + outputDirectoryFile );
595
596 processFilesetProject( archetypeDescriptor,
597 StringUtils.replace( artifactId, "${rootArtifactId}", rootArtifactId ),
598 archetypeResources, pom, archetypeZipFile, moduleOffset, context, packageName,
599 outputDirectoryFile, basedirPom );
600
601 String parentArtifactId = (String) context.get( Constants.PARENT_ARTIFACT_ID );
602
603 Iterator<ModuleDescriptor> subprojects = archetypeDescriptor.getModules().iterator();
604
605 if ( subprojects.hasNext() )
606 {
607 getLogger().debug( artifactId + " has modules (" + archetypeDescriptor.getModules() + ")" );
608
609 setParentArtifactId( context, StringUtils.replace( artifactId, "${rootArtifactId}", rootArtifactId ) );
610 }
611
612 while ( subprojects.hasNext() )
613 {
614 ModuleDescriptor project = subprojects.next();
615
616 String modulePath = StringUtils.replace( project.getDir(), "__rootArtifactId__", rootArtifactId );
617 modulePath = replaceFilenameTokens( modulePath, context );
618
619 File moduleOutputDirectoryFile = new File( outputDirectoryFile, modulePath );
620
621 context.put( Constants.ARTIFACT_ID,
622 StringUtils.replace( project.getId(), "${rootArtifactId}", rootArtifactId ) );
623
624 String moduleArtifactId = StringUtils.replace( project.getDir(), "__rootArtifactId__", rootArtifactId );
625 moduleArtifactId = replaceFilenameTokens( moduleArtifactId, context );
626
627 processFilesetModule( rootArtifactId, moduleArtifactId,
628 archetypeResources, new File( moduleOutputDirectoryFile, Constants.ARCHETYPE_POM ),
629 archetypeZipFile,
630 ( StringUtils.isEmpty( moduleOffset ) ? "" : ( moduleOffset + "/" ) )
631 + StringUtils.replace( project.getDir(), "${rootArtifactId}", rootArtifactId ),
632 pom, moduleOutputDirectoryFile, packageName, project, context );
633 }
634
635 restoreParentArtifactId( context, parentArtifactId );
636
637 getLogger().debug( "Processed " + artifactId );
638 }
639
640 private void processFilesetProject( final AbstractArchetypeDescriptor archetypeDescriptor, final String moduleId,
641 final List<String> archetypeResources, final File pom,
642 final ZipFile archetypeZipFile, String moduleOffset, final Context context,
643 final String packageName, final File outputDirectoryFile,
644 final File basedirPom )
645 throws DocumentException, XmlPullParserException, ArchetypeGenerationFailure, InvalidPackaging, IOException,
646 FileNotFoundException, OutputFileExists
647 {
648 getLogger().debug( "Processing fileset project moduleId " + moduleId );
649 getLogger().debug( "Processing fileset project pom " + pom );
650 getLogger().debug( "Processing fileset project moduleOffset " + moduleOffset );
651 getLogger().debug( "Processing fileset project outputDirectoryFile " + outputDirectoryFile );
652 getLogger().debug( "Processing fileset project basedirPom " + basedirPom );
653
654 if ( basedirPom.exists() )
655 {
656 processPomWithParent( context, pom, moduleOffset, basedirPom, moduleId );
657 }
658 else
659 {
660 processPom( context, pom, moduleOffset );
661 }
662
663 processArchetypeTemplates( archetypeDescriptor, archetypeResources, archetypeZipFile, moduleOffset, context,
664 packageName, outputDirectoryFile );
665 }
666
667 private void processPom( Context context, File pom, String moduleOffset )
668 throws OutputFileExists, ArchetypeGenerationFailure
669 {
670 getLogger().debug( "Processing pom " + pom );
671
672 processTemplate( pom, context,
673 Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset ) + Constants.ARCHETYPE_POM,
674 getEncoding( null ), true );
675 }
676
677 private void processPomWithMerge( Context context, File pom, String moduleOffset )
678 throws OutputFileExists, IOException, XmlPullParserException, ArchetypeGenerationFailure
679 {
680 getLogger().debug( "Processing pom " + pom + " with merge" );
681
682 File temporaryPom = getTemporaryFile( pom );
683
684 processTemplate( temporaryPom, context,
685 Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset ) + Constants.ARCHETYPE_POM,
686 getEncoding( null ), true );
687
688 pomManager.mergePoms( pom, temporaryPom );
689
690
691
692 try
693 {
694 FileUtils.forceDelete( temporaryPom );
695 }
696 catch ( IOException e )
697 {
698 temporaryPom.deleteOnExit();
699 }
700 }
701
702 private void processPomWithParent( Context context, File pom, String moduleOffset, File basedirPom,
703 String moduleId )
704 throws OutputFileExists, XmlPullParserException, DocumentException, IOException, InvalidPackaging,
705 ArchetypeGenerationFailure
706 {
707 getLogger().debug( "Processing pom " + pom + " with parent " + basedirPom );
708
709 processTemplate( pom, context,
710 Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset ) + Constants.ARCHETYPE_POM,
711 getEncoding( null ), true );
712
713 getLogger().debug( "Adding module " + moduleId );
714
715 pomManager.addModule( basedirPom, moduleId );
716
717 pomManager.addParent( pom, basedirPom );
718 }
719
720 @SuppressWarnings( "deprecation" )
721 private boolean processTemplate( File outFile, Context context, String templateFileName, String encoding,
722 boolean failIfExists )
723 throws OutputFileExists, ArchetypeGenerationFailure
724 {
725 templateFileName = templateFileName.replace( File.separatorChar, '/' );
726
727 String localTemplateFileName = templateFileName.replace( '/', File.separatorChar );
728 if ( !templateFileName.equals( localTemplateFileName ) && !velocity.getEngine().templateExists(
729 templateFileName ) && velocity.getEngine().templateExists( localTemplateFileName ) )
730 {
731 templateFileName = localTemplateFileName;
732 }
733
734 getLogger().debug( "Processing template " + templateFileName );
735
736 if ( outFile.exists() )
737 {
738 if ( failIfExists )
739 {
740 throw new OutputFileExists( "Don't override file " + outFile.getAbsolutePath() );
741 }
742
743 getLogger().warn( "Don't override file " + outFile );
744
745 return false;
746 }
747
748 if ( templateFileName.endsWith( "/" ) )
749 {
750 getLogger().debug( "Creating directory " + outFile );
751
752 outFile.mkdirs();
753
754 return true;
755 }
756
757 if ( !outFile.getParentFile().exists() )
758 {
759 outFile.getParentFile().mkdirs();
760 }
761
762 getLogger().debug( "Merging into " + outFile );
763
764 Writer writer = null;
765
766 try
767 {
768 StringWriter stringWriter = new StringWriter();
769
770 velocity.getEngine().mergeTemplate( templateFileName, encoding, context, stringWriter );
771
772 writer = new OutputStreamWriter( new FileOutputStream( outFile ), encoding );
773
774 writer.write( StringUtils.unifyLineSeparators( stringWriter.toString() ) );
775
776 writer.flush();
777 }
778 catch ( Exception e )
779 {
780 throw new ArchetypeGenerationFailure( "Error merging velocity templates: " + e.getMessage(), e );
781 }
782 finally
783 {
784 IOUtil.close( writer );
785 }
786
787 return true;
788 }
789
790 private void processTemplates( String packageName, File outputDirectoryFile, Context context,
791 AbstractArchetypeDescriptor archetypeDescriptor, List<String> archetypeResources,
792 ZipFile archetypeZipFile, String moduleOffset, boolean failIfExists )
793 throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
794 {
795 Iterator<FileSet> iterator = archetypeDescriptor.getFileSets().iterator();
796 if ( iterator.hasNext() )
797 {
798 getLogger().debug( "Processing filesets" + "\n " + archetypeResources );
799 }
800
801 int count = 0;
802 while ( iterator.hasNext() )
803 {
804 FileSet fileSet = iterator.next();
805 count++;
806
807 List<String> fileSetResources =
808 archetypeFilesResolver.filterFiles( moduleOffset, fileSet, archetypeResources );
809
810
811
812 getOutputFile( moduleOffset, fileSet.getDirectory(), outputDirectoryFile, fileSet.isPackaged(), packageName,
813 moduleOffset, context ).mkdirs();
814
815 if ( fileSet.isFiltered() )
816 {
817 getLogger().debug( " Processing fileset " + fileSet + " -> " + fileSetResources.size() + ":\n "
818 + fileSetResources );
819
820 int processed =
821 processFileSet( fileSet.getDirectory(), fileSetResources, fileSet.isPackaged(), packageName,
822 context, outputDirectoryFile, moduleOffset, getEncoding( fileSet.getEncoding() ),
823 failIfExists );
824
825 getLogger().debug( " Processed " + processed + " files." );
826 }
827 else
828 {
829 getLogger().debug( " Copying fileset " + fileSet + " -> " + fileSetResources.size() + ":\n "
830 + fileSetResources );
831
832 int copied = copyFiles( fileSet.getDirectory(), fileSetResources, fileSet.isPackaged(), packageName,
833 outputDirectoryFile, archetypeZipFile, moduleOffset, failIfExists, context );
834
835 getLogger().debug( " Copied " + copied + " files." );
836 }
837 }
838
839 getLogger().debug( "Processed " + count + " filesets" );
840 }
841
842 private void restoreParentArtifactId( Context context, String parentArtifactId )
843 {
844 if ( StringUtils.isEmpty( parentArtifactId ) )
845 {
846 context.remove( Constants.PARENT_ARTIFACT_ID );
847 }
848 else
849 {
850 context.put( Constants.PARENT_ARTIFACT_ID, parentArtifactId );
851 }
852 }
853
854 private File getTemporaryFile( File file )
855 {
856 File tmp = FileUtils.createTempFile( file.getName(), Constants.TMP, file.getParentFile() );
857
858 tmp.deleteOnExit();
859
860 return tmp;
861 }
862 }