View Javadoc
1   package org.apache.maven.archetype.creator;
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.ArchetypeCreationRequest;
23  import org.apache.maven.archetype.ArchetypeCreationResult;
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.common.util.FileCharsetDetector;
28  import org.apache.maven.archetype.common.util.ListScanner;
29  import org.apache.maven.archetype.common.util.PathUtils;
30  import org.apache.maven.archetype.exception.TemplateCreationException;
31  import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
32  import org.apache.maven.archetype.metadata.FileSet;
33  import org.apache.maven.archetype.metadata.ModuleDescriptor;
34  import org.apache.maven.archetype.metadata.RequiredProperty;
35  import org.apache.maven.archetype.metadata.io.xpp3.ArchetypeDescriptorXpp3Writer;
36  import org.apache.maven.artifact.Artifact;
37  import org.apache.maven.artifact.repository.ArtifactRepository;
38  import org.apache.maven.model.Build;
39  import org.apache.maven.model.Dependency;
40  import org.apache.maven.model.Extension;
41  import org.apache.maven.model.Model;
42  import org.apache.maven.model.Plugin;
43  import org.apache.maven.model.PluginManagement;
44  import org.apache.maven.model.Profile;
45  import org.apache.maven.project.MavenProject;
46  import org.apache.maven.project.MavenProjectBuilder;
47  import org.apache.maven.project.ProjectBuildingException;
48  import org.apache.maven.shared.invoker.DefaultInvocationRequest;
49  import org.apache.maven.shared.invoker.DefaultInvoker;
50  import org.apache.maven.shared.invoker.InvocationRequest;
51  import org.apache.maven.shared.invoker.Invoker;
52  import org.codehaus.plexus.component.annotations.Component;
53  import org.codehaus.plexus.component.annotations.Requirement;
54  import org.codehaus.plexus.logging.AbstractLogEnabled;
55  import org.codehaus.plexus.util.DirectoryScanner;
56  import org.codehaus.plexus.util.FileUtils;
57  import org.codehaus.plexus.util.IOUtil;
58  import org.codehaus.plexus.util.ReaderFactory;
59  import org.codehaus.plexus.util.StringUtils;
60  import org.codehaus.plexus.util.WriterFactory;
61  import org.codehaus.plexus.util.xml.Xpp3Dom;
62  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
63  
64  import java.io.File;
65  import java.io.FileInputStream;
66  import java.io.FileNotFoundException;
67  import java.io.FileOutputStream;
68  import java.io.IOException;
69  import java.io.InputStream;
70  import java.io.OutputStream;
71  import java.io.Reader;
72  import java.io.Writer;
73  import java.util.ArrayList;
74  import java.util.Arrays;
75  import java.util.Collections;
76  import java.util.HashMap;
77  import java.util.HashSet;
78  import java.util.Iterator;
79  import java.util.List;
80  import java.util.Map;
81  import java.util.Properties;
82  import java.util.Set;
83  
84  /**
85   * Create a 2.x Archetype project from a project. Since 2.0-alpha-5, an integration-test named "basic" is created along
86   * the archetype itself to provide immediate test when building the archetype.
87   */
88  @Component( role = ArchetypeCreator.class, hint = "fileset" )
89  public class FilesetArchetypeCreator
90      extends AbstractLogEnabled
91      implements ArchetypeCreator
92  {
93      private static final String DEFAULT_OUTPUT_DIRECTORY =
94          "target" + File.separator + "generated-sources" + File.separator + "archetype";
95  
96      @Requirement
97      private ArchetypeFilesResolver archetypeFilesResolver;
98  
99      @Requirement
100     private PomManager pomManager;
101 
102     @Requirement
103     private MavenProjectBuilder projectBuilder;
104 
105     public void createArchetype( ArchetypeCreationRequest request, ArchetypeCreationResult result )
106     {
107         MavenProject project = request.getProject();
108         List<String> languages = request.getLanguages();
109         List<String> filtereds = request.getFiltereds();
110         String defaultEncoding = request.getDefaultEncoding();
111         boolean preserveCData = request.isPreserveCData();
112         boolean keepParent = request.isKeepParent();
113         boolean partialArchetype = request.isPartialArchetype();
114         ArtifactRepository localRepository = request.getLocalRepository();
115         File outputDirectory = request.getOutputDirectory();
116         File basedir = project.getBasedir();
117 
118         Properties properties = new Properties();
119         Properties configurationProperties = new Properties();
120         if ( request.getProperties() != null )
121         {
122             properties.putAll( request.getProperties() );
123             configurationProperties.putAll( request.getProperties() );
124         }
125 
126         extractPropertiesFromProject( project, properties, configurationProperties, request.getPackageName() );
127 
128         if ( outputDirectory == null )
129         {
130             getLogger().debug( "No output directory defined, using default: " + DEFAULT_OUTPUT_DIRECTORY );
131             outputDirectory = FileUtils.resolveFile( basedir, DEFAULT_OUTPUT_DIRECTORY );
132         }
133         outputDirectory.mkdirs();
134 
135         getLogger().debug( "Creating archetype in " + outputDirectory );
136 
137         try
138         {
139             File archetypePomFile =
140                 createArchetypeProjectPom( project, localRepository, configurationProperties, outputDirectory );
141 
142             File archetypeResourcesDirectory = new File( outputDirectory, getTemplateOutputDirectory() );
143 
144             File archetypeFilesDirectory = new File( archetypeResourcesDirectory, Constants.ARCHETYPE_RESOURCES );
145             getLogger().debug( "Archetype's files output directory " + archetypeFilesDirectory );
146 
147             File archetypeDescriptorFile = new File( archetypeResourcesDirectory, Constants.ARCHETYPE_DESCRIPTOR );
148             archetypeDescriptorFile.getParentFile().mkdirs();
149 
150             getLogger().debug( "Starting archetype's descriptor " + project.getArtifactId() );
151             ArchetypeDescriptor archetypeDescriptor = new ArchetypeDescriptor();
152 
153             archetypeDescriptor.setName( project.getArtifactId() );
154             archetypeDescriptor.setPartial( partialArchetype );
155 
156             addRequiredProperties( archetypeDescriptor, properties );
157 
158             // TODO ensure reverseProperties contains NO dotted properties
159             Properties reverseProperties = getReversedProperties( archetypeDescriptor, properties );
160             // reverseProperties.remove( Constants.GROUP_ID );
161 
162             // TODO ensure pomReversedProperties contains NO dotted properties
163             Properties pomReversedProperties = getReversedProperties( archetypeDescriptor, properties );
164             // pomReversedProperties.remove( Constants.PACKAGE );
165 
166             String packageName = configurationProperties.getProperty( Constants.PACKAGE );
167 
168             Model pom = pomManager.readPom( FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ) );
169 
170             List<String> fileNames = resolveFileNames( pom, basedir );
171             if ( getLogger().isDebugEnabled() )
172             {
173                 getLogger().debug( "Scanned for files " + fileNames.size() );
174 
175                 for ( String name : fileNames )
176                 {
177                     getLogger().debug( "- " + name );
178                 }
179             }
180 
181             List<FileSet> filesets = resolveFileSets( packageName, fileNames, languages, filtereds, defaultEncoding );
182             getLogger().debug( "Resolved filesets for " + archetypeDescriptor.getName() );
183 
184             archetypeDescriptor.setFileSets( filesets );
185 
186             createArchetypeFiles( reverseProperties, filesets, packageName, basedir, archetypeFilesDirectory,
187                                   defaultEncoding );
188             getLogger().debug( "Created files for " + archetypeDescriptor.getName() );
189 
190             setParentArtifactId( reverseProperties, configurationProperties.getProperty( Constants.ARTIFACT_ID ) );
191 
192             for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
193             {
194                 String moduleId = (String) modules.next();
195                 String rootArtifactId = configurationProperties.getProperty( Constants.ARTIFACT_ID );
196                 String moduleIdDirectory = moduleId;
197 
198                 if ( moduleId.indexOf( rootArtifactId ) >= 0 )
199                 {
200                     moduleIdDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
201                 }
202 
203                 getLogger().debug( "Creating module " + moduleId );
204 
205                 ModuleDescriptor moduleDescriptor =
206                     createModule( reverseProperties, rootArtifactId, moduleId, packageName,
207                                   FileUtils.resolveFile( basedir, moduleId ),
208                                   new File( archetypeFilesDirectory, moduleIdDirectory ), languages, filtereds,
209                                   defaultEncoding, preserveCData, keepParent );
210 
211                 archetypeDescriptor.addModule( moduleDescriptor );
212 
213                 getLogger().debug(
214                     "Added module " + moduleDescriptor.getName() + " in " + archetypeDescriptor.getName() );
215             }
216 
217             restoreParentArtifactId( reverseProperties, null );
218             restoreArtifactId( reverseProperties, configurationProperties.getProperty( Constants.ARTIFACT_ID ) );
219 
220             createPoms( pom, configurationProperties.getProperty( Constants.ARTIFACT_ID ),
221                         configurationProperties.getProperty( Constants.ARTIFACT_ID ), archetypeFilesDirectory, basedir,
222                         pomReversedProperties, preserveCData, keepParent );
223             getLogger().debug( "Created Archetype " + archetypeDescriptor.getName() + " template pom(s)" );
224 
225             Writer out = null;
226             try
227             {
228                 out = WriterFactory.newXmlWriter( archetypeDescriptorFile );
229 
230                 ArchetypeDescriptorXpp3Writer writer = new ArchetypeDescriptorXpp3Writer();
231 
232                 writer.write( out, archetypeDescriptor );
233 
234                 getLogger().debug( "Archetype " + archetypeDescriptor.getName() + " descriptor written" );
235             }
236             finally
237             {
238                 IOUtil.close( out );
239             }
240 
241             createArchetypeBasicIt( archetypeDescriptor, outputDirectory );
242 
243             InvocationRequest internalRequest = new DefaultInvocationRequest();
244             internalRequest.setPomFile( archetypePomFile );
245             internalRequest.setGoals( Collections.singletonList( request.getPostPhase() ) );
246 
247             Invoker invoker = new DefaultInvoker();
248             invoker.execute( internalRequest );
249         }
250         catch ( Exception e )
251         {
252             result.setCause( e );
253         }
254     }
255 
256     /**
257      * Create an archetype IT, ie goals.txt and archetype.properties in src/test/resources/projects/basic.
258      *
259      * @param archetypeDescriptor
260      * @param generatedSourcesDirectory
261      * @throws IOException
262      * @since 2.0-alpha-5
263      */
264     private void createArchetypeBasicIt( ArchetypeDescriptor archetypeDescriptor, File generatedSourcesDirectory )
265         throws IOException
266     {
267         String basic =
268             Constants.SRC + File.separator + Constants.TEST + File.separator + Constants.RESOURCES + File.separator
269                 + "projects" + File.separator + "basic";
270         File basicItDirectory = new File( generatedSourcesDirectory, basic );
271         basicItDirectory.mkdirs();
272 
273         InputStream in = null;
274         OutputStream out = null;
275 
276         try
277         {
278             in = FilesetArchetypeCreator.class.getResourceAsStream( "archetype.properties" );
279 
280             Properties archetypeProperties = new Properties();
281             archetypeProperties.load( in );
282 
283             for ( RequiredProperty req : archetypeDescriptor.getRequiredProperties() )
284             {
285                 archetypeProperties.put( req.getKey(), req.getDefaultValue() );
286             }
287 
288             out = new FileOutputStream( new File( basicItDirectory, "archetype.properties" ) );
289             archetypeProperties.store( out, null );
290         }
291         finally
292         {
293             IOUtil.close( in );
294             IOUtil.close( out );
295         }
296         copyResource( "goal.txt", new File( basicItDirectory, "goal.txt" ) );
297 
298         getLogger().debug( "Added basic integration test" );
299     }
300 
301     private void extractPropertiesFromProject( MavenProject project, Properties properties,
302                                                Properties configurationProperties, String packageName )
303     {
304         if ( !properties.containsKey( Constants.GROUP_ID ) )
305         {
306             properties.setProperty( Constants.GROUP_ID, project.getGroupId() );
307         }
308         configurationProperties.setProperty( Constants.GROUP_ID, properties.getProperty( Constants.GROUP_ID ) );
309 
310         if ( !properties.containsKey( Constants.ARTIFACT_ID ) )
311         {
312             properties.setProperty( Constants.ARTIFACT_ID, project.getArtifactId() );
313         }
314         configurationProperties.setProperty( Constants.ARTIFACT_ID, properties.getProperty( Constants.ARTIFACT_ID ) );
315 
316         if ( !properties.containsKey( Constants.VERSION ) )
317         {
318             properties.setProperty( Constants.VERSION, project.getVersion() );
319         }
320         configurationProperties.setProperty( Constants.VERSION, properties.getProperty( Constants.VERSION ) );
321 
322         if ( packageName != null )
323         {
324             properties.setProperty( Constants.PACKAGE, packageName );
325         }
326         else if ( !properties.containsKey( Constants.PACKAGE ) )
327         {
328             properties.setProperty( Constants.PACKAGE, project.getGroupId() );
329         }
330         configurationProperties.setProperty( Constants.PACKAGE, properties.getProperty( Constants.PACKAGE ) );
331     }
332 
333     /**
334      * Create the archetype project pom.xml file, that will be used to build the archetype.
335      */
336     private File createArchetypeProjectPom( MavenProject project, ArtifactRepository localRepository,
337                                             Properties configurationProperties, File projectDir )
338         throws TemplateCreationException, IOException
339     {
340         Model model = new Model();
341         model.setModelVersion( "4.0.0" );
342         // these values should be retrieved from the request with sensible defaults
343         model.setGroupId( configurationProperties.getProperty( Constants.ARCHETYPE_GROUP_ID, project.getGroupId() ) );
344         model.setArtifactId(
345             configurationProperties.getProperty( Constants.ARCHETYPE_ARTIFACT_ID, project.getArtifactId() ) );
346         model.setVersion( configurationProperties.getProperty( Constants.ARCHETYPE_VERSION, project.getVersion() ) );
347         model.setPackaging( "maven-archetype" );
348         model.setName(
349             configurationProperties.getProperty( Constants.ARCHETYPE_ARTIFACT_ID, project.getArtifactId() ) );
350         model.setUrl( configurationProperties.getProperty( Constants.ARCHETYPE_URL, project.getUrl() ) );
351         model.setDescription(
352             configurationProperties.getProperty( Constants.ARCHETYPE_DESCRIPTION, project.getDescription() ) );
353         model.setLicenses( project.getLicenses() );
354         model.setDevelopers( project.getDevelopers() );
355         model.setScm( project.getScm() );
356         Build build = new Build();
357         model.setBuild( build );
358 
359         // In many cases where we are behind a firewall making Archetypes for work mates we want
360         // to simply be able to deploy the archetypes once we have created them. In order to do
361         // this we want to utilize information from the project we are creating the archetype from.
362         // This will be a fully working project that has been testing and inherits from a POM
363         // that contains deployment information, along with any extensions required for deployment.
364         // We don't want to create archetypes that cannot be deployed after we create them. People
365         // might want to edit the archetype POM but they should not have too.
366 
367         if ( project.getParent() != null )
368         {
369             Artifact pa = project.getParentArtifact();
370 
371             try
372             {
373                 MavenProject p =
374                     projectBuilder.buildFromRepository( pa, project.getRemoteArtifactRepositories(), localRepository );
375 
376                 if ( p.getDistributionManagement() != null )
377                 {
378                     model.setDistributionManagement( p.getDistributionManagement() );
379                 }
380 
381                 if ( p.getBuildExtensions() != null )
382                 {
383                     for ( Iterator<Extension> i = p.getBuildExtensions().iterator(); i.hasNext(); )
384                     {
385                         Extension be = i.next();
386 
387                         model.getBuild().addExtension( be );
388                     }
389                 }
390             }
391             catch ( ProjectBuildingException e )
392             {
393                 throw new TemplateCreationException(
394                     "Error reading parent POM of project: " + pa.getGroupId() + ":" + pa.getArtifactId() + ":"
395                         + pa.getVersion() );
396             }
397         }
398 
399         Extension extension = new Extension();
400         extension.setGroupId( "org.apache.maven.archetype" );
401         extension.setArtifactId( "archetype-packaging" );
402         extension.setVersion( getArchetypeVersion() );
403         model.getBuild().addExtension( extension );
404 
405         Plugin plugin = new Plugin();
406         plugin.setGroupId( "org.apache.maven.plugins" );
407         plugin.setArtifactId( "maven-archetype-plugin" );
408         plugin.setVersion( getArchetypeVersion() );
409 
410         PluginManagement pluginManagement = new PluginManagement();
411         pluginManagement.addPlugin( plugin );
412         model.getBuild().setPluginManagement( pluginManagement );
413 
414         getLogger().debug( "Creating archetype's pom" );
415 
416         File archetypePomFile = new File( projectDir, Constants.ARCHETYPE_POM );
417 
418         archetypePomFile.getParentFile().mkdirs();
419 
420         copyResource( "pom-prototype.xml", archetypePomFile );
421 
422         pomManager.writePom( model, archetypePomFile, archetypePomFile );
423 
424         return archetypePomFile;
425     }
426 
427     private void copyResource( String name, File destination )
428         throws IOException
429     {
430         InputStream in = null;
431         OutputStream out = null;
432 
433         try
434         {
435             in = FilesetArchetypeCreator.class.getResourceAsStream( name );
436             out = new FileOutputStream( destination );
437 
438             IOUtil.copy( in, out );
439         }
440         finally
441         {
442             IOUtil.close( in );
443             IOUtil.close( out );
444         }
445     }
446 
447     private void addRequiredProperties( ArchetypeDescriptor archetypeDescriptor, Properties properties )
448     {
449         Properties requiredProperties = new Properties();
450         requiredProperties.putAll( properties );
451         requiredProperties.remove( Constants.ARCHETYPE_GROUP_ID );
452         requiredProperties.remove( Constants.ARCHETYPE_ARTIFACT_ID );
453         requiredProperties.remove( Constants.ARCHETYPE_VERSION );
454         requiredProperties.remove( Constants.GROUP_ID );
455         requiredProperties.remove( Constants.ARTIFACT_ID );
456         requiredProperties.remove( Constants.VERSION );
457         requiredProperties.remove( Constants.PACKAGE );
458 
459         for ( Iterator<?> propertiesIterator = requiredProperties.keySet().iterator(); propertiesIterator.hasNext(); )
460         {
461             String propertyKey = (String) propertiesIterator.next();
462 
463             RequiredProperty requiredProperty = new RequiredProperty();
464             requiredProperty.setKey( propertyKey );
465             requiredProperty.setDefaultValue( requiredProperties.getProperty( propertyKey ) );
466 
467             archetypeDescriptor.addRequiredProperty( requiredProperty );
468 
469             getLogger().debug(
470                 "Adding requiredProperty " + propertyKey + "=" + requiredProperties.getProperty( propertyKey )
471                     + " to archetype's descriptor" );
472         }
473     }
474 
475     private void createModulePoms( Properties pomReversedProperties, String rootArtifactId, String packageName,
476                                    File basedir, File archetypeFilesDirectory, boolean preserveCData,
477                                    boolean keepParent )
478         throws FileNotFoundException, IOException, XmlPullParserException
479     {
480         Model pom = pomManager.readPom( FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ) );
481 
482         String parentArtifactId = pomReversedProperties.getProperty( Constants.PARENT_ARTIFACT_ID );
483         String artifactId = pom.getArtifactId();
484         setParentArtifactId( pomReversedProperties, pomReversedProperties.getProperty( Constants.ARTIFACT_ID ) );
485         setArtifactId( pomReversedProperties, pom.getArtifactId() );
486 
487         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
488         {
489             String subModuleId = modules.next();
490 
491             String subModuleIdDirectory = subModuleId;
492 
493             if ( subModuleId.indexOf( rootArtifactId ) >= 0 )
494             {
495                 subModuleIdDirectory = StringUtils.replace( subModuleId, rootArtifactId, "__rootArtifactId__" );
496             }
497 
498             createModulePoms( pomReversedProperties, rootArtifactId, packageName,
499                               FileUtils.resolveFile( basedir, subModuleId ),
500                               FileUtils.resolveFile( archetypeFilesDirectory, subModuleIdDirectory ), preserveCData,
501                               keepParent );
502         }
503 
504         createModulePom( pom, rootArtifactId, archetypeFilesDirectory, pomReversedProperties,
505                          FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ), preserveCData, keepParent );
506 
507         restoreParentArtifactId( pomReversedProperties, parentArtifactId );
508         restoreArtifactId( pomReversedProperties, artifactId );
509     }
510 
511     private void createPoms( Model pom, String rootArtifactId, String artifactId, File archetypeFilesDirectory,
512                              File basedir, Properties pomReversedProperties, boolean preserveCData, boolean keepParent )
513         throws IOException, FileNotFoundException, XmlPullParserException
514     {
515         setArtifactId( pomReversedProperties, pom.getArtifactId() );
516 
517         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
518         {
519             String moduleId = modules.next();
520 
521             String moduleIdDirectory = moduleId;
522 
523             if ( moduleId.indexOf( rootArtifactId ) >= 0 )
524             {
525                 moduleIdDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
526             }
527 
528             createModulePoms( pomReversedProperties, rootArtifactId, moduleId,
529                               FileUtils.resolveFile( basedir, moduleId ),
530                               new File( archetypeFilesDirectory, moduleIdDirectory ), preserveCData, keepParent );
531         }
532 
533         restoreParentArtifactId( pomReversedProperties, null );
534         restoreArtifactId( pomReversedProperties, artifactId );
535 
536         createArchetypePom( pom, archetypeFilesDirectory, pomReversedProperties,
537                             FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ), preserveCData, keepParent );
538     }
539 
540     private String getPackageInPathFormat( String aPackage )
541     {
542         return StringUtils.replace( aPackage, ".", "/" );
543     }
544 
545     private void rewriteReferences( Model pom, String rootArtifactId, String groupId )
546     {
547         // rewrite Dependencies
548         if ( pom.getDependencies() != null && !pom.getDependencies().isEmpty() )
549         {
550             for ( Iterator<Dependency> dependencies = pom.getDependencies().iterator(); dependencies.hasNext(); )
551             {
552                 rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
553             }
554         }
555 
556         // rewrite DependencyManagement
557         if ( pom.getDependencyManagement() != null && pom.getDependencyManagement().getDependencies() != null
558             && !pom.getDependencyManagement().getDependencies().isEmpty() )
559         {
560             for ( Iterator<Dependency> dependencies = pom.getDependencyManagement().getDependencies().iterator();
561                   dependencies.hasNext(); )
562             {
563                 rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
564             }
565         }
566 
567         // rewrite Plugins
568         if ( pom.getBuild() != null && pom.getBuild().getPlugins() != null && !pom.getBuild().getPlugins().isEmpty() )
569         {
570             for ( Iterator<Plugin> plugins = pom.getBuild().getPlugins().iterator(); plugins.hasNext(); )
571             {
572                 rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
573             }
574         }
575 
576         // rewrite PluginManagement
577         if ( pom.getBuild() != null && pom.getBuild().getPluginManagement() != null
578             && pom.getBuild().getPluginManagement().getPlugins() != null
579             && !pom.getBuild().getPluginManagement().getPlugins().isEmpty() )
580         {
581             for ( Iterator<Plugin> plugins = pom.getBuild().getPluginManagement().getPlugins().iterator();
582                   plugins.hasNext(); )
583             {
584                 rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
585             }
586         }
587 
588         // rewrite Profiles
589         if ( pom.getProfiles() != null )
590         {
591             for ( Iterator<Profile> profiles = pom.getProfiles().iterator(); profiles.hasNext(); )
592             {
593                 Profile profile = profiles.next();
594 
595                 // rewrite Dependencies
596                 if ( profile.getDependencies() != null && !profile.getDependencies().isEmpty() )
597                 {
598                     for ( Iterator<Dependency> dependencies = profile.getDependencies().iterator();
599                           dependencies.hasNext(); )
600                     {
601                         rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
602                     }
603                 }
604 
605                 // rewrite DependencyManagement
606                 if ( profile.getDependencyManagement() != null
607                     && profile.getDependencyManagement().getDependencies() != null
608                     && !profile.getDependencyManagement().getDependencies().isEmpty() )
609                 {
610                     for ( Iterator<Dependency> dependencies =
611                               profile.getDependencyManagement().getDependencies().iterator(); dependencies.hasNext(); )
612                     {
613                         rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
614                     }
615                 }
616 
617                 // rewrite Plugins
618                 if ( profile.getBuild() != null && profile.getBuild().getPlugins() != null
619                     && !profile.getBuild().getPlugins().isEmpty() )
620                 {
621                     for ( Iterator<Plugin> plugins = profile.getBuild().getPlugins().iterator(); plugins.hasNext(); )
622                     {
623                         rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
624                     }
625                 }
626 
627                 // rewrite PluginManagement
628                 if ( profile.getBuild() != null && profile.getBuild().getPluginManagement() != null
629                     && profile.getBuild().getPluginManagement().getPlugins() != null
630                     && !profile.getBuild().getPluginManagement().getPlugins().isEmpty() )
631                 {
632                     for ( Iterator<Plugin> plugins = profile.getBuild().getPluginManagement().getPlugins().iterator();
633                           plugins.hasNext(); )
634                     {
635                         rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
636                     }
637                 }
638             }
639         }
640     }
641 
642     private void rewriteDependencyReferences( Dependency dependency, String rootArtifactId, String groupId )
643     {
644         if ( dependency.getArtifactId() != null && dependency.getArtifactId().indexOf( rootArtifactId ) >= 0 )
645         {
646             if ( dependency.getGroupId() != null )
647             {
648                 dependency.setGroupId( StringUtils.replace( dependency.getGroupId(), groupId, "${" + Constants.GROUP_ID
649                     + "}" ) );
650             }
651 
652             dependency.setArtifactId( StringUtils.replace( dependency.getArtifactId(), rootArtifactId,
653                                                            "${rootArtifactId}" ) );
654 
655             if ( dependency.getVersion() != null )
656             {
657                 dependency.setVersion( "${" + Constants.VERSION + "}" );
658             }
659         }
660     }
661 
662     private void rewritePluginReferences( Plugin plugin, String rootArtifactId, String groupId )
663     {
664         if ( plugin.getArtifactId() != null && plugin.getArtifactId().indexOf( rootArtifactId ) >= 0 )
665         {
666             if ( plugin.getGroupId() != null )
667             {
668                 String g = StringUtils.replace( plugin.getGroupId(), groupId, "${" + Constants.GROUP_ID + "}" );
669                 plugin.setGroupId( g );
670             }
671 
672             plugin.setArtifactId( StringUtils.replace( plugin.getArtifactId(), rootArtifactId, "${rootArtifactId}" ) );
673 
674             if ( plugin.getVersion() != null )
675             {
676                 plugin.setVersion( "${" + Constants.VERSION + "}" );
677             }
678         }
679 
680         if ( plugin.getArtifactId() != null && "maven-ear-plugin".equals( plugin.getArtifactId() ) )
681         {
682             rewriteEARPluginReferences( plugin, rootArtifactId, groupId );
683         }
684     }
685 
686     private void rewriteEARPluginReferences( Plugin plugin, String rootArtifactId, String groupId )
687     {
688         Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
689         Xpp3Dom[] modules = configuration.getChild( "modules" ).getChildren();
690         for ( int i = 0; i < modules.length; i++ )
691         {
692             Xpp3Dom module = modules[i];
693             Xpp3Dom moduleGroupId = module.getChild( "groupId" );
694             Xpp3Dom moduleArtifactId = module.getChild( "artifactId" );
695             Xpp3Dom moduleBundleFileName = module.getChild( "bundleFileName" );
696             Xpp3Dom moduleModuleId = module.getChild( "moduleId" );
697             Xpp3Dom moduleContextRoot = module.getChild( "contextRoot" );
698 
699             if ( moduleGroupId != null )
700             {
701                 moduleGroupId.setValue( StringUtils.replace( moduleGroupId.getValue(), groupId, "${"
702                     + Constants.GROUP_ID + "}" ) );
703             }
704 
705             if ( moduleArtifactId != null )
706             {
707                 moduleArtifactId.setValue( StringUtils.replace( moduleArtifactId.getValue(), rootArtifactId,
708                                                                 "${rootArtifactId}" ) );
709             }
710 
711             if ( moduleBundleFileName != null )
712             {
713                 moduleBundleFileName.setValue( StringUtils.replace( moduleBundleFileName.getValue(), rootArtifactId,
714                                                                     "${rootArtifactId}" ) );
715             }
716 
717             if ( moduleModuleId != null )
718             {
719                 moduleModuleId.setValue( StringUtils.replace( moduleModuleId.getValue(), rootArtifactId,
720                                                               "${rootArtifactId}" ) );
721             }
722 
723             if ( moduleContextRoot != null )
724             {
725                 moduleContextRoot.setValue( StringUtils.replace( moduleContextRoot.getValue(), rootArtifactId,
726                                                                  "${rootArtifactId}" ) );
727             }
728         }
729     }
730 
731     private void setArtifactId( Properties properties, String artifactId )
732     {
733         properties.setProperty( Constants.ARTIFACT_ID, artifactId );
734     }
735 
736     private List<String> concatenateToList( List<String> toConcatenate, String with )
737     {
738         List<String> result = new ArrayList<String>( toConcatenate.size() );
739 
740         for ( String concatenate : toConcatenate )
741         {
742             result.add( ( ( with.length() > 0 ) ? ( with + "/" + concatenate ) : concatenate ) );
743         }
744 
745         return result;
746     }
747 
748     private void copyFiles( File basedir, File archetypeFilesDirectory, String directory, List<String> fileSetResources,
749                             boolean packaged, String packageName )
750         throws IOException
751     {
752         String packageAsDirectory = StringUtils.replace( packageName, ".", File.separator );
753 
754         getLogger().debug( "Package as Directory: Package:" + packageName + "->" + packageAsDirectory );
755 
756         for ( String inputFileName : fileSetResources )
757         {
758             String outputFileName = packaged
759                 ? StringUtils.replace( inputFileName, packageAsDirectory + File.separator, "" )
760                 : inputFileName;
761             getLogger().debug( "InputFileName:" + inputFileName );
762             getLogger().debug( "OutputFileName:" + outputFileName );
763 
764             File outputFile = new File( archetypeFilesDirectory, outputFileName );
765 
766             File inputFile = new File( basedir, inputFileName );
767 
768             outputFile.getParentFile().mkdirs();
769 
770             FileUtils.copyFile( inputFile, outputFile );
771         }
772     }
773 
774     private void createArchetypeFiles( Properties reverseProperties, List<FileSet> fileSets, String packageName,
775                                        File basedir, File archetypeFilesDirectory, String defaultEncoding )
776         throws IOException
777     {
778         getLogger().debug( "Creating Archetype/Module files from " + basedir + " to " + archetypeFilesDirectory );
779 
780         for ( FileSet fileSet : fileSets )
781         {
782             DirectoryScanner scanner = new DirectoryScanner();
783             scanner.setBasedir( basedir );
784             scanner.setIncludes( (String[]) concatenateToList( fileSet.getIncludes(), fileSet.getDirectory() ).toArray(
785                 new String[fileSet.getIncludes().size()] ) );
786             scanner.setExcludes( (String[]) fileSet.getExcludes().toArray( new String[fileSet.getExcludes().size()] ) );
787             scanner.addDefaultExcludes();
788             getLogger().debug( "Using fileset " + fileSet );
789             scanner.scan();
790 
791             List<String> fileSetResources = Arrays.asList( scanner.getIncludedFiles() );
792             getLogger().debug( "Scanned " + fileSetResources.size() + " resources" );
793 
794             if ( fileSet.isFiltered() )
795             {
796                 processFileSet( basedir, archetypeFilesDirectory, fileSet.getDirectory(), fileSetResources,
797                                 fileSet.isPackaged(), packageName, reverseProperties, defaultEncoding );
798                 getLogger().debug( "Processed " + fileSet.getDirectory() + " files" );
799             }
800             else
801             {
802                 copyFiles( basedir, archetypeFilesDirectory, fileSet.getDirectory(), fileSetResources,
803                            fileSet.isPackaged(), packageName );
804                 getLogger().debug( "Copied " + fileSet.getDirectory() + " files" );
805             }
806         }
807     }
808 
809     private void createArchetypePom( Model pom, File archetypeFilesDirectory, Properties pomReversedProperties,
810                                      File initialPomFile, boolean preserveCData, boolean keepParent )
811         throws IOException
812     {
813         File outputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM );
814 
815         if ( preserveCData )
816         {
817             getLogger().debug( "Preserving CDATA parts of pom" );
818             File inputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM + ".tmp" );
819 
820             FileUtils.copyFile( initialPomFile, inputFile );
821 
822             Reader in = null;
823             Writer out = null;
824             try
825             {
826                 in = ReaderFactory.newXmlReader( inputFile );
827 
828                 String initialcontent = IOUtil.toString( in );
829 
830                 String content = getReversedContent( initialcontent, pomReversedProperties );
831 
832                 outputFile.getParentFile().mkdirs();
833 
834                 out = WriterFactory.newXmlWriter( outputFile );
835 
836                 IOUtil.copy( content, out );
837             }
838             finally
839             {
840                 IOUtil.close( in );
841                 IOUtil.close( out );
842             }
843 
844             inputFile.delete();
845         }
846         else
847         {
848             if ( !keepParent )
849             {
850                 pom.setParent( null );
851             }
852 
853             pom.setModules( null );
854             pom.setGroupId( "${" + Constants.GROUP_ID + "}" );
855             pom.setArtifactId( "${" + Constants.ARTIFACT_ID + "}" );
856             pom.setVersion( "${" + Constants.VERSION + "}" );
857 
858             rewriteReferences( pom, pomReversedProperties.getProperty( Constants.ARTIFACT_ID ),
859                                pomReversedProperties.getProperty( Constants.GROUP_ID ) );
860 
861             pomManager.writePom( pom, outputFile, initialPomFile );
862         }
863 
864         Reader in = null;
865         try
866         {
867             in = ReaderFactory.newXmlReader( initialPomFile );
868             String initialcontent = IOUtil.toString( in );
869 
870             Iterator<?> properties = pomReversedProperties.keySet().iterator();
871             while ( properties.hasNext() )
872             {
873                 String property = (String) properties.next();
874 
875                 if ( initialcontent.indexOf( "${" + property + "}" ) > 0 )
876                 {
877                     getLogger().warn(
878                         "Archetype uses ${" + property + "} for internal processing, but file " + initialPomFile
879                             + " contains this property already" );
880                 }
881             }
882         }
883         finally
884         {
885             IOUtil.close( in );
886         }
887     }
888 
889     private FileSet createFileSet( final List<String> excludes, final boolean packaged, final boolean filtered,
890                                    final String group, final List<String> includes, String defaultEncoding )
891     {
892         FileSet fileSet = new FileSet();
893 
894         fileSet.setDirectory( group );
895         fileSet.setPackaged( packaged );
896         fileSet.setFiltered( filtered );
897         fileSet.setIncludes( includes );
898         fileSet.setExcludes( excludes );
899         fileSet.setEncoding( defaultEncoding );
900 
901         getLogger().debug( "Created Fileset " + fileSet );
902 
903         return fileSet;
904     }
905 
906     private List<FileSet> createFileSets( List<String> files, int level, boolean packaged, String packageName,
907                                           boolean filtered, String defaultEncoding )
908     {
909         List<FileSet> fileSets = new ArrayList<FileSet>();
910 
911         if ( !files.isEmpty() )
912         {
913             getLogger().debug( "Creating filesets" + ( packaged ? ( " packaged (" + packageName + ")" ) : "" ) + (
914                 filtered
915                     ? " filtered"
916                     : "" ) + " at level " + level );
917             if ( level == 0 )
918             {
919                 List<String> includes = new ArrayList<String>( files );
920                 List<String> excludes = new ArrayList<String>();
921 
922                 if ( !includes.isEmpty() )
923                 {
924                     fileSets.add( createFileSet( excludes, packaged, filtered, "", includes, defaultEncoding ) );
925                 }
926             }
927             else
928             {
929                 Map<String, List<String>> groups = getGroupsMap( files, level );
930 
931                 for ( String group : groups.keySet() )
932                 {
933                     getLogger().debug( "Creating filesets for group " + group );
934 
935                     if ( !packaged )
936                     {
937                         fileSets.add( getUnpackagedFileSet( filtered, group, groups.get( group ), defaultEncoding ) );
938                     }
939                     else
940                     {
941                         fileSets.addAll(
942                             getPackagedFileSets( filtered, group, groups.get( group ), packageName, defaultEncoding ) );
943                     }
944                 }
945             } // end if
946 
947             getLogger().debug( "Resolved fileSets " + fileSets );
948         } // end if
949 
950         return fileSets;
951     }
952 
953     private ModuleDescriptor createModule( Properties reverseProperties, String rootArtifactId, String moduleId,
954                                            String packageName, File basedir, File archetypeFilesDirectory,
955                                            List<String> languages, List<String> filtereds, String defaultEncoding,
956                                            boolean preserveCData, boolean keepParent )
957         throws IOException, XmlPullParserException
958     {
959         ModuleDescriptor archetypeDescriptor = new ModuleDescriptor();
960         getLogger().debug( "Starting module's descriptor " + moduleId );
961 
962         archetypeFilesDirectory.mkdirs();
963         getLogger().debug( "Module's files output directory " + archetypeFilesDirectory );
964 
965         Model pom = pomManager.readPom( FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ) );
966         String replacementId = pom.getArtifactId();
967         String moduleDirectory = pom.getArtifactId();
968 
969         if ( replacementId.indexOf( rootArtifactId ) >= 0 )
970         {
971             replacementId = StringUtils.replace( replacementId, rootArtifactId, "${rootArtifactId}" );
972             moduleDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
973         }
974 
975         if ( moduleId.indexOf( rootArtifactId ) >= 0 )
976         {
977             moduleDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
978         }
979 
980         archetypeDescriptor.setName( replacementId );
981         archetypeDescriptor.setId( replacementId );
982         archetypeDescriptor.setDir( moduleDirectory );
983 
984         setArtifactId( reverseProperties, pom.getArtifactId() );
985 
986         List<String> fileNames = resolveFileNames( pom, basedir );
987 
988         List<FileSet> filesets = resolveFileSets( packageName, fileNames, languages, filtereds, defaultEncoding );
989         getLogger().debug( "Resolved filesets for module " + archetypeDescriptor.getName() );
990 
991         archetypeDescriptor.setFileSets( filesets );
992 
993         createArchetypeFiles( reverseProperties, filesets, packageName, basedir, archetypeFilesDirectory,
994                               defaultEncoding );
995         getLogger().debug( "Created files for module " + archetypeDescriptor.getName() );
996 
997         String parentArtifactId = reverseProperties.getProperty( Constants.PARENT_ARTIFACT_ID );
998         setParentArtifactId( reverseProperties, pom.getArtifactId() );
999 
1000         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
1001         {
1002             String subModuleId = modules.next();
1003 
1004             String subModuleIdDirectory = subModuleId;
1005             if ( subModuleId.indexOf( rootArtifactId ) >= 0 )
1006             {
1007                 subModuleIdDirectory = StringUtils.replace( subModuleId, rootArtifactId, "__rootArtifactId__" );
1008             }
1009 
1010             getLogger().debug( "Creating module " + subModuleId );
1011 
1012             ModuleDescriptor moduleDescriptor =
1013                 createModule( reverseProperties, rootArtifactId, subModuleId, packageName,
1014                               FileUtils.resolveFile( basedir, subModuleId ),
1015                               FileUtils.resolveFile( archetypeFilesDirectory, subModuleIdDirectory ), languages,
1016                               filtereds, defaultEncoding, preserveCData, keepParent );
1017 
1018             archetypeDescriptor.addModule( moduleDescriptor );
1019 
1020             getLogger().debug( "Added module " + moduleDescriptor.getName() + " in " + archetypeDescriptor.getName() );
1021         }
1022 
1023         restoreParentArtifactId( reverseProperties, parentArtifactId );
1024         restoreArtifactId( reverseProperties, pom.getArtifactId() );
1025 
1026         getLogger().debug( "Created Module " + archetypeDescriptor.getName() + " pom" );
1027 
1028         return archetypeDescriptor;
1029     }
1030 
1031     private void createModulePom( Model pom, String rootArtifactId, File archetypeFilesDirectory,
1032                                   Properties pomReversedProperties, File initialPomFile, boolean preserveCData,
1033                                   boolean keepParent )
1034         throws IOException
1035     {
1036         File outputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM );
1037 
1038         if ( preserveCData )
1039         {
1040             getLogger().debug( "Preserving CDATA parts of pom" );
1041             File inputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM + ".tmp" );
1042 
1043             FileUtils.copyFile( initialPomFile, inputFile );
1044 
1045             Reader in = null;
1046             Writer out = null;
1047             try
1048             {
1049                 in = ReaderFactory.newXmlReader( inputFile );
1050 
1051                 String initialcontent = IOUtil.toString( in );
1052 
1053                 String content = getReversedContent( initialcontent, pomReversedProperties );
1054 
1055                 outputFile.getParentFile().mkdirs();
1056 
1057                 out = WriterFactory.newXmlWriter( outputFile );
1058 
1059                 IOUtil.copy( content, out );
1060             }
1061             finally
1062             {
1063                 IOUtil.close( in );
1064                 IOUtil.close( out );
1065             }
1066 
1067             inputFile.delete();
1068         }
1069         else
1070         {
1071             if ( pom.getParent() != null )
1072             {
1073                 pom.getParent().setGroupId( StringUtils.replace( pom.getParent().getGroupId(),
1074                                                                  pomReversedProperties.getProperty(
1075                                                                      Constants.GROUP_ID ),
1076                                                                  "${" + Constants.GROUP_ID + "}" ) );
1077                 if ( pom.getParent().getArtifactId() != null
1078                     && pom.getParent().getArtifactId().indexOf( rootArtifactId ) >= 0 )
1079                 {
1080                     pom.getParent().setArtifactId(
1081                         StringUtils.replace( pom.getParent().getArtifactId(), rootArtifactId, "${rootArtifactId}" ) );
1082                 }
1083                 if ( pom.getParent().getVersion() != null )
1084                 {
1085                     pom.getParent().setVersion( "${" + Constants.VERSION + "}" );
1086                 }
1087             }
1088             pom.setModules( null );
1089 
1090             if ( pom.getGroupId() != null )
1091             {
1092                 pom.setGroupId(
1093                     StringUtils.replace( pom.getGroupId(), pomReversedProperties.getProperty( Constants.GROUP_ID ),
1094                                          "${" + Constants.GROUP_ID + "}" ) );
1095             }
1096 
1097             pom.setArtifactId( "${" + Constants.ARTIFACT_ID + "}" );
1098 
1099             if ( pom.getVersion() != null )
1100             {
1101                 pom.setVersion( "${" + Constants.VERSION + "}" );
1102             }
1103 
1104             rewriteReferences( pom, rootArtifactId, pomReversedProperties.getProperty( Constants.GROUP_ID ) );
1105 
1106             pomManager.writePom( pom, outputFile, initialPomFile );
1107         }
1108 
1109         Reader in = null;
1110         try
1111         {
1112             in = ReaderFactory.newXmlReader( initialPomFile );
1113             String initialcontent = IOUtil.toString( in );
1114 
1115             for ( Iterator<?> properties = pomReversedProperties.keySet().iterator(); properties.hasNext(); )
1116             {
1117                 String property = (String) properties.next();
1118 
1119                 if ( initialcontent.indexOf( "${" + property + "}" ) > 0 )
1120                 {
1121                     getLogger().warn(
1122                         "OldArchetype uses ${" + property + "} for internal processing, but file " + initialPomFile
1123                             + " contains this property already" );
1124                 }
1125             }
1126         }
1127         finally
1128         {
1129             IOUtil.close( in );
1130         }
1131     }
1132 
1133     private Set<String> getExtensions( List<String> files )
1134     {
1135         Set<String> extensions = new HashSet<String>();
1136 
1137         for ( String file : files )
1138         {
1139             extensions.add( FileUtils.extension( file ) );
1140         }
1141 
1142         return extensions;
1143     }
1144 
1145     private Map<String, List<String>> getGroupsMap( final List<String> files, final int level )
1146     {
1147         Map<String, List<String>> groups = new HashMap<String, List<String>>();
1148 
1149         for ( String file : files )
1150         {
1151             String directory = PathUtils.getDirectory( file, level );
1152             // make all groups have unix style
1153             directory = StringUtils.replace( directory, File.separator, "/" );
1154 
1155             if ( !groups.containsKey( directory ) )
1156             {
1157                 groups.put( directory, new ArrayList<String>() );
1158             }
1159 
1160             List<String> group = groups.get( directory );
1161 
1162             String innerPath = file.substring( directory.length() + 1 );
1163             // make all groups have unix style
1164             innerPath = StringUtils.replace( innerPath, File.separator, "/" );
1165 
1166             group.add( innerPath );
1167         }
1168 
1169         getLogger().debug( "Sorted " + groups.size() + " groups in " + files.size() + " files" );
1170         getLogger().debug( "Sorted Files: " + files );
1171 
1172         return groups;
1173     }
1174 
1175     private FileSet getPackagedFileSet( final boolean filtered, final Set<String> packagedExtensions,
1176                                         final String group, final Set<String> unpackagedExtensions,
1177                                         final List<String> unpackagedFiles, String defaultEncoding )
1178     {
1179         List<String> includes = new ArrayList<String>();
1180         List<String> excludes = new ArrayList<String>();
1181 
1182         for ( String extension : packagedExtensions )
1183         {
1184             includes.add( "**/*." + extension );
1185 
1186             if ( unpackagedExtensions.contains( extension ) )
1187             {
1188                 excludes.addAll( archetypeFilesResolver.getFilesWithExtension( unpackagedFiles, extension ) );
1189             }
1190         }
1191 
1192         return createFileSet( excludes, true, filtered, group, includes, defaultEncoding );
1193     }
1194 
1195     private List<FileSet> getPackagedFileSets( final boolean filtered, final String group,
1196                                                final List<String> groupFiles, final String packageName,
1197                                                String defaultEncoding )
1198     {
1199         String packageAsDir = StringUtils.replace( packageName, ".", "/" );
1200 
1201         List<FileSet> packagedFileSets = new ArrayList<FileSet>();
1202         List<String> packagedFiles = archetypeFilesResolver.getPackagedFiles( groupFiles, packageAsDir );
1203         getLogger().debug( "Found packaged Files:" + packagedFiles );
1204 
1205         List<String> unpackagedFiles = archetypeFilesResolver.getUnpackagedFiles( groupFiles, packageAsDir );
1206         getLogger().debug( "Found unpackaged Files:" + unpackagedFiles );
1207 
1208         Set<String> packagedExtensions = getExtensions( packagedFiles );
1209         getLogger().debug( "Found packaged extensions " + packagedExtensions );
1210 
1211         Set<String> unpackagedExtensions = getExtensions( unpackagedFiles );
1212 
1213         if ( !packagedExtensions.isEmpty() )
1214         {
1215             packagedFileSets.add(
1216                 getPackagedFileSet( filtered, packagedExtensions, group, unpackagedExtensions, unpackagedFiles,
1217                                     defaultEncoding ) );
1218         }
1219 
1220         if ( !unpackagedExtensions.isEmpty() )
1221         {
1222             getLogger().debug( "Found unpackaged extensions " + unpackagedExtensions );
1223 
1224             packagedFileSets.add(
1225                 getUnpackagedFileSet( filtered, unpackagedExtensions, unpackagedFiles, group, packagedExtensions,
1226                                       defaultEncoding ) );
1227         }
1228 
1229         return packagedFileSets;
1230     }
1231 
1232     private void setParentArtifactId( Properties properties, String parentArtifactId )
1233     {
1234         properties.setProperty( Constants.PARENT_ARTIFACT_ID, parentArtifactId );
1235     }
1236 
1237     private void processFileSet( File basedir, File archetypeFilesDirectory, String directory,
1238                                  List<String> fileSetResources, boolean packaged, String packageName,
1239                                  Properties reverseProperties, String defaultEncoding )
1240         throws IOException
1241     {
1242         String packageAsDirectory = StringUtils.replace( packageName, ".", File.separator );
1243 
1244         getLogger().debug( "Package as Directory: Package:" + packageName + "->" + packageAsDirectory );
1245 
1246         for ( String inputFileName : fileSetResources )
1247         {
1248             String outputFileName = packaged
1249                 ? StringUtils.replace( inputFileName, packageAsDirectory + File.separator, "" )
1250                 : inputFileName;
1251 
1252             getLogger().debug( "InputFileName:" + inputFileName );
1253             getLogger().debug( "OutputFileName:" + outputFileName );
1254 
1255             File outputFile = new File( archetypeFilesDirectory, outputFileName );
1256             File inputFile = new File( basedir, inputFileName );
1257 
1258             FileCharsetDetector detector = new FileCharsetDetector( inputFile );
1259 
1260             String fileEncoding = detector.isFound() ? detector.getCharset() : defaultEncoding;
1261 
1262             String initialcontent = IOUtil.toString( new FileInputStream( inputFile ), fileEncoding );
1263 
1264             for ( Iterator<?> properties = reverseProperties.keySet().iterator(); properties.hasNext(); )
1265             {
1266                 String property = (String) properties.next();
1267 
1268                 if ( initialcontent.indexOf( "${" + property + "}" ) > 0 )
1269                 {
1270                     getLogger().warn(
1271                         "Archetype uses ${" + property + "} for internal processing, but file " + inputFile
1272                             + " contains this property already" );
1273                 }
1274             }
1275 
1276             String content = getReversedContent( initialcontent, reverseProperties );
1277 
1278             outputFile.getParentFile().mkdirs();
1279 
1280             org.apache.commons.io.IOUtils.write( content, new FileOutputStream( outputFile ), fileEncoding );
1281         }
1282     }
1283 
1284     private List<String> removePackage( List<String> sources, String packageAsDirectory )
1285     {
1286         if ( sources == null )
1287         {
1288             return null;
1289         }
1290 
1291         List<String> unpackagedSources = new ArrayList<String>( sources.size() );
1292 
1293         for ( String source : sources )
1294         {
1295             String unpackagedSource = StringUtils.replace( source, packageAsDirectory, "" );
1296 
1297             unpackagedSources.add( unpackagedSource );
1298         }
1299 
1300         return unpackagedSources;
1301     }
1302 
1303     private Properties getReversedProperties( ArchetypeDescriptor archetypeDescriptor, Properties properties )
1304     {
1305         Properties reversedProperties = new Properties();
1306 
1307         reversedProperties.putAll( properties );
1308         reversedProperties.remove( Constants.ARCHETYPE_GROUP_ID );
1309         reversedProperties.remove( Constants.ARCHETYPE_ARTIFACT_ID );
1310         reversedProperties.remove( Constants.ARCHETYPE_VERSION );
1311 
1312         String packageName = properties.getProperty( Constants.PACKAGE );
1313         String packageInPathFormat = getPackageInPathFormat( packageName );
1314         if ( !packageInPathFormat.equals( packageName ) )
1315         {
1316             reversedProperties.setProperty( Constants.PACKAGE_IN_PATH_FORMAT, packageInPathFormat );
1317         }
1318 
1319         // TODO check that reversed properties are all different and no one is a substring of another?
1320         // to avoid wrong variable replacements
1321 
1322         return reversedProperties;
1323     }
1324 
1325     private List<String> resolveFileNames( final Model pom, final File basedir )
1326         throws IOException
1327     {
1328         getLogger().debug( "Resolving files for " + pom.getId() + " in " + basedir );
1329 
1330         StringBuffer buff = new StringBuffer( "pom.xml*,archetype.properties*,target/**," );
1331         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
1332         {
1333             buff.append( ',' ).append( modules.next() ).append( "/**" );
1334         }
1335 
1336         for ( String defaultExclude : ListScanner.DEFAULTEXCLUDES )
1337         {
1338             buff.append( ',' ).append( defaultExclude ).append( "/**" );
1339         }
1340 
1341         String excludes = PathUtils.convertPathForOS( buff.toString() );
1342 
1343         List<String> fileNames = FileUtils.getFileNames( basedir, "**,.*,**/.*", excludes, false );
1344 
1345         getLogger().debug( "Resolved " + fileNames.size() + " files" );
1346         getLogger().debug( "Resolved Files:" + fileNames );
1347 
1348         return fileNames;
1349     }
1350 
1351     private List<FileSet> resolveFileSets( String packageName, List<String> fileNames, List<String> languages,
1352                                            List<String> filtereds, String defaultEncoding )
1353     {
1354         List<FileSet> resolvedFileSets = new ArrayList<FileSet>();
1355         getLogger().debug(
1356             "Resolving filesets with package=" + packageName + ", languages=" + languages + " and extentions="
1357                 + filtereds );
1358 
1359         List<String> files = new ArrayList<String>( fileNames );
1360 
1361         StringBuilder languageIncludes = new StringBuilder();
1362 
1363         for ( String language : languages )
1364         {
1365             languageIncludes.append( ( ( languageIncludes.length() == 0 ) ? "" : "," ) + language + "/**" );
1366         }
1367 
1368         getLogger().debug( "Using languages includes " + languageIncludes );
1369 
1370         StringBuilder filteredIncludes = new StringBuilder();
1371         for ( String filtered : filtereds )
1372         {
1373             filteredIncludes.append(
1374                 ( ( filteredIncludes.length() == 0 ) ? "" : "," ) + "**/" + ( filtered.startsWith( "." ) ? "" : "*." )
1375                     + filtered );
1376         }
1377 
1378         getLogger().debug( "Using filtered includes " + filteredIncludes );
1379 
1380         /* sourcesMainFiles */
1381         List<String> sourcesMainFiles =
1382             archetypeFilesResolver.findSourcesMainFiles( files, languageIncludes.toString() );
1383         if ( !sourcesMainFiles.isEmpty() )
1384         {
1385             files.removeAll( sourcesMainFiles );
1386 
1387             List<String> filteredFiles =
1388                 archetypeFilesResolver.getFilteredFiles( sourcesMainFiles, filteredIncludes.toString() );
1389             sourcesMainFiles.removeAll( filteredFiles );
1390 
1391             List<String> unfilteredFiles = sourcesMainFiles;
1392             if ( !filteredFiles.isEmpty() )
1393             {
1394                 resolvedFileSets.addAll( createFileSets( filteredFiles, 3, true, packageName, true, defaultEncoding ) );
1395             }
1396 
1397             if ( !unfilteredFiles.isEmpty() )
1398             {
1399                 resolvedFileSets.addAll(
1400                     createFileSets( unfilteredFiles, 3, true, packageName, false, defaultEncoding ) );
1401             }
1402         }
1403 
1404         /* resourcesMainFiles */
1405         List<String> resourcesMainFiles =
1406             archetypeFilesResolver.findResourcesMainFiles( files, languageIncludes.toString() );
1407         if ( !resourcesMainFiles.isEmpty() )
1408         {
1409             files.removeAll( resourcesMainFiles );
1410 
1411             List<String> filteredFiles =
1412                 archetypeFilesResolver.getFilteredFiles( resourcesMainFiles, filteredIncludes.toString() );
1413             resourcesMainFiles.removeAll( filteredFiles );
1414 
1415             List<String> unfilteredFiles = resourcesMainFiles;
1416             if ( !filteredFiles.isEmpty() )
1417             {
1418                 resolvedFileSets.addAll(
1419                     createFileSets( filteredFiles, 3, false, packageName, true, defaultEncoding ) );
1420             }
1421             if ( !unfilteredFiles.isEmpty() )
1422             {
1423                 resolvedFileSets.addAll(
1424                     createFileSets( unfilteredFiles, 3, false, packageName, false, defaultEncoding ) );
1425             }
1426         }
1427 
1428         /* sourcesTestFiles */
1429         List<String> sourcesTestFiles =
1430             archetypeFilesResolver.findSourcesTestFiles( files, languageIncludes.toString() );
1431         if ( !sourcesTestFiles.isEmpty() )
1432         {
1433             files.removeAll( sourcesTestFiles );
1434 
1435             List<String> filteredFiles =
1436                 archetypeFilesResolver.getFilteredFiles( sourcesTestFiles, filteredIncludes.toString() );
1437             sourcesTestFiles.removeAll( filteredFiles );
1438 
1439             List<String> unfilteredFiles = sourcesTestFiles;
1440             if ( !filteredFiles.isEmpty() )
1441             {
1442                 resolvedFileSets.addAll( createFileSets( filteredFiles, 3, true, packageName, true, defaultEncoding ) );
1443             }
1444             if ( !unfilteredFiles.isEmpty() )
1445             {
1446                 resolvedFileSets.addAll(
1447                     createFileSets( unfilteredFiles, 3, true, packageName, false, defaultEncoding ) );
1448             }
1449         }
1450 
1451         /* ressourcesTestFiles */
1452         List<String> resourcesTestFiles =
1453             archetypeFilesResolver.findResourcesTestFiles( files, languageIncludes.toString() );
1454         if ( !resourcesTestFiles.isEmpty() )
1455         {
1456             files.removeAll( resourcesTestFiles );
1457 
1458             List<String> filteredFiles =
1459                 archetypeFilesResolver.getFilteredFiles( resourcesTestFiles, filteredIncludes.toString() );
1460             resourcesTestFiles.removeAll( filteredFiles );
1461 
1462             List<String> unfilteredFiles = resourcesTestFiles;
1463             if ( !filteredFiles.isEmpty() )
1464             {
1465                 resolvedFileSets.addAll(
1466                     createFileSets( filteredFiles, 3, false, packageName, true, defaultEncoding ) );
1467             }
1468             if ( !unfilteredFiles.isEmpty() )
1469             {
1470                 resolvedFileSets.addAll(
1471                     createFileSets( unfilteredFiles, 3, false, packageName, false, defaultEncoding ) );
1472             }
1473         }
1474 
1475         /* siteFiles */
1476         List<String> siteFiles = archetypeFilesResolver.findSiteFiles( files, languageIncludes.toString() );
1477         if ( !siteFiles.isEmpty() )
1478         {
1479             files.removeAll( siteFiles );
1480 
1481             List<String> filteredFiles =
1482                 archetypeFilesResolver.getFilteredFiles( siteFiles, filteredIncludes.toString() );
1483             siteFiles.removeAll( filteredFiles );
1484 
1485             List<String> unfilteredFiles = siteFiles;
1486             if ( !filteredFiles.isEmpty() )
1487             {
1488                 resolvedFileSets.addAll(
1489                     createFileSets( filteredFiles, 2, false, packageName, true, defaultEncoding ) );
1490             }
1491             if ( !unfilteredFiles.isEmpty() )
1492             {
1493                 resolvedFileSets.addAll(
1494                     createFileSets( unfilteredFiles, 2, false, packageName, false, defaultEncoding ) );
1495             }
1496         }
1497 
1498         /* thirdLevelSourcesfiles */
1499         List<String> thirdLevelSourcesfiles =
1500             archetypeFilesResolver.findOtherSources( 3, files, languageIncludes.toString() );
1501         if ( !thirdLevelSourcesfiles.isEmpty() )
1502         {
1503             files.removeAll( thirdLevelSourcesfiles );
1504 
1505             List<String> filteredFiles =
1506                 archetypeFilesResolver.getFilteredFiles( thirdLevelSourcesfiles, filteredIncludes.toString() );
1507             thirdLevelSourcesfiles.removeAll( filteredFiles );
1508 
1509             List<String> unfilteredFiles = thirdLevelSourcesfiles;
1510             if ( !filteredFiles.isEmpty() )
1511             {
1512                 resolvedFileSets.addAll( createFileSets( filteredFiles, 3, true, packageName, true, defaultEncoding ) );
1513             }
1514             if ( !unfilteredFiles.isEmpty() )
1515             {
1516                 resolvedFileSets.addAll(
1517                     createFileSets( unfilteredFiles, 3, true, packageName, false, defaultEncoding ) );
1518             }
1519 
1520             /* thirdLevelResourcesfiles */
1521             List<String> thirdLevelResourcesfiles =
1522                 archetypeFilesResolver.findOtherResources( 3, files, thirdLevelSourcesfiles,
1523                                                            languageIncludes.toString() );
1524             if ( !thirdLevelResourcesfiles.isEmpty() )
1525             {
1526                 files.removeAll( thirdLevelResourcesfiles );
1527                 filteredFiles =
1528                     archetypeFilesResolver.getFilteredFiles( thirdLevelResourcesfiles, filteredIncludes.toString() );
1529                 thirdLevelResourcesfiles.removeAll( filteredFiles );
1530                 unfilteredFiles = thirdLevelResourcesfiles;
1531                 if ( !filteredFiles.isEmpty() )
1532                 {
1533                     resolvedFileSets.addAll(
1534                         createFileSets( filteredFiles, 3, false, packageName, true, defaultEncoding ) );
1535                 }
1536                 if ( !unfilteredFiles.isEmpty() )
1537                 {
1538                     resolvedFileSets.addAll(
1539                         createFileSets( unfilteredFiles, 3, false, packageName, false, defaultEncoding ) );
1540                 }
1541             }
1542         } // end if
1543 
1544         /* secondLevelSourcesfiles */
1545         List<String> secondLevelSourcesfiles =
1546             archetypeFilesResolver.findOtherSources( 2, files, languageIncludes.toString() );
1547         if ( !secondLevelSourcesfiles.isEmpty() )
1548         {
1549             files.removeAll( secondLevelSourcesfiles );
1550 
1551             List<String> filteredFiles =
1552                 archetypeFilesResolver.getFilteredFiles( secondLevelSourcesfiles, filteredIncludes.toString() );
1553             secondLevelSourcesfiles.removeAll( filteredFiles );
1554 
1555             List<String> unfilteredFiles = secondLevelSourcesfiles;
1556             if ( !filteredFiles.isEmpty() )
1557             {
1558                 resolvedFileSets.addAll( createFileSets( filteredFiles, 2, true, packageName, true, defaultEncoding ) );
1559             }
1560             if ( !unfilteredFiles.isEmpty() )
1561             {
1562                 resolvedFileSets.addAll(
1563                     createFileSets( unfilteredFiles, 2, true, packageName, false, defaultEncoding ) );
1564             }
1565         }
1566 
1567         /* secondLevelResourcesfiles */
1568         List<String> secondLevelResourcesfiles =
1569             archetypeFilesResolver.findOtherResources( 2, files, languageIncludes.toString() );
1570         if ( !secondLevelResourcesfiles.isEmpty() )
1571         {
1572             files.removeAll( secondLevelResourcesfiles );
1573 
1574             List<String> filteredFiles =
1575                 archetypeFilesResolver.getFilteredFiles( secondLevelResourcesfiles, filteredIncludes.toString() );
1576             secondLevelResourcesfiles.removeAll( filteredFiles );
1577 
1578             List<String> unfilteredFiles = secondLevelResourcesfiles;
1579             if ( !filteredFiles.isEmpty() )
1580             {
1581                 resolvedFileSets.addAll(
1582                     createFileSets( filteredFiles, 2, false, packageName, true, defaultEncoding ) );
1583             }
1584             if ( !unfilteredFiles.isEmpty() )
1585             {
1586                 resolvedFileSets.addAll(
1587                     createFileSets( unfilteredFiles, 2, false, packageName, false, defaultEncoding ) );
1588             }
1589         }
1590 
1591         /* rootResourcesfiles */
1592         List<String> rootResourcesfiles =
1593             archetypeFilesResolver.findOtherResources( 0, files, languageIncludes.toString() );
1594         if ( !rootResourcesfiles.isEmpty() )
1595         {
1596             files.removeAll( rootResourcesfiles );
1597 
1598             List<String> filteredFiles =
1599                 archetypeFilesResolver.getFilteredFiles( rootResourcesfiles, filteredIncludes.toString() );
1600             rootResourcesfiles.removeAll( filteredFiles );
1601 
1602             List<String> unfilteredFiles = rootResourcesfiles;
1603             if ( !filteredFiles.isEmpty() )
1604             {
1605                 resolvedFileSets.addAll(
1606                     createFileSets( filteredFiles, 0, false, packageName, true, defaultEncoding ) );
1607             }
1608             if ( !unfilteredFiles.isEmpty() )
1609             {
1610                 resolvedFileSets.addAll(
1611                     createFileSets( unfilteredFiles, 0, false, packageName, false, defaultEncoding ) );
1612             }
1613         }
1614 
1615         /**/
1616         if ( !files.isEmpty() )
1617         {
1618             getLogger().info( "Ignored files: " + files );
1619         }
1620 
1621         return resolvedFileSets;
1622     }
1623 
1624     private void restoreArtifactId( Properties properties, String artifactId )
1625     {
1626         if ( StringUtils.isEmpty( artifactId ) )
1627         {
1628             properties.remove( Constants.ARTIFACT_ID );
1629         }
1630         else
1631         {
1632             properties.setProperty( Constants.ARTIFACT_ID, artifactId );
1633         }
1634     }
1635 
1636     private void restoreParentArtifactId( Properties properties, String parentArtifactId )
1637     {
1638         if ( StringUtils.isEmpty( parentArtifactId ) )
1639         {
1640             properties.remove( Constants.PARENT_ARTIFACT_ID );
1641         }
1642         else
1643         {
1644             properties.setProperty( Constants.PARENT_ARTIFACT_ID, parentArtifactId );
1645         }
1646     }
1647 
1648     private String getReversedContent( String content, Properties properties )
1649     {
1650         String result =
1651             StringUtils.replace( StringUtils.replace( content, "$", "${symbol_dollar}" ), "\\", "${symbol_escape}" );
1652 
1653         for ( Iterator<?> propertyIterator = properties.keySet().iterator(); propertyIterator.hasNext(); )
1654         {
1655             String propertyKey = (String) propertyIterator.next();
1656 
1657             result = StringUtils.replace( result, properties.getProperty( propertyKey ), "${" + propertyKey + "}" );
1658         }
1659         // TODO: Replace velocity to a better engine...
1660         return "#set( $symbol_pound = '#' )\n" + "#set( $symbol_dollar = '$' )\n" + "#set( $symbol_escape = '\\' )\n"
1661             + StringUtils.replace( result, "#", "${symbol_pound}" );
1662     }
1663 
1664     private String getTemplateOutputDirectory()
1665     {
1666         return Constants.SRC + File.separator + Constants.MAIN + File.separator + Constants.RESOURCES;
1667     }
1668 
1669     private FileSet getUnpackagedFileSet( final boolean filtered, final String group, final List<String> groupFiles,
1670                                           String defaultEncoding )
1671     {
1672         Set<String> extensions = getExtensions( groupFiles );
1673 
1674         List<String> includes = new ArrayList<String>();
1675         List<String> excludes = new ArrayList<String>();
1676 
1677         for ( String extension : extensions )
1678         {
1679             includes.add( "**/*." + extension );
1680         }
1681 
1682         return createFileSet( excludes, false, filtered, group, includes, defaultEncoding );
1683     }
1684 
1685     private FileSet getUnpackagedFileSet( final boolean filtered, final Set<String> unpackagedExtensions,
1686                                           final List<String> unpackagedFiles, final String group,
1687                                           final Set<String> packagedExtensions, String defaultEncoding )
1688     {
1689         List<String> includes = new ArrayList<String>();
1690         List<String> excludes = new ArrayList<String>();
1691 
1692         for ( String extension : unpackagedExtensions )
1693         {
1694             if ( packagedExtensions.contains( extension ) )
1695             {
1696                 includes.addAll( archetypeFilesResolver.getFilesWithExtension( unpackagedFiles, extension ) );
1697             }
1698             else
1699             {
1700                 includes.add( "**/*." + extension );
1701             }
1702         }
1703 
1704         return createFileSet( excludes, false, filtered, group, includes, defaultEncoding );
1705     }
1706 
1707     private static final String MAVEN_PROPERTIES =
1708         "META-INF/maven/org.apache.maven.archetype/archetype-common/pom.properties";
1709 
1710     public String getArchetypeVersion()
1711     {
1712         InputStream is = null;
1713 
1714         // This should actually come from the pom.properties at testing but it's not generated and put into the JAR, it
1715         // happens as part of the JAR plugin which is crap as it makes testing inconsistent.
1716         String version = "version";
1717 
1718         try
1719         {
1720             Properties properties = new Properties();
1721 
1722             is = getClass().getClassLoader().getResourceAsStream( MAVEN_PROPERTIES );
1723 
1724             if ( is != null )
1725             {
1726                 properties.load( is );
1727 
1728                 String property = properties.getProperty( "version" );
1729 
1730                 if ( property != null )
1731                 {
1732                     return property;
1733                 }
1734             }
1735 
1736             return version;
1737         }
1738         catch ( IOException e )
1739         {
1740             return version;
1741         }
1742         finally
1743         {
1744             IOUtil.close( is );
1745         }
1746     }
1747 }