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