View Javadoc

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