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