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