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