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