1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.archetype.generator;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24 import javax.xml.parsers.ParserConfigurationException;
25 import javax.xml.transform.TransformerException;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStream;
31 import java.io.OutputStreamWriter;
32 import java.io.StringWriter;
33 import java.io.Writer;
34 import java.nio.file.Files;
35 import java.util.ArrayList;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Properties;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
42 import java.util.zip.ZipEntry;
43 import java.util.zip.ZipFile;
44
45 import groovy.lang.Binding;
46 import groovy.lang.GroovyShell;
47 import org.apache.maven.archetype.ArchetypeGenerationRequest;
48 import org.apache.maven.archetype.common.ArchetypeArtifactManager;
49 import org.apache.maven.archetype.common.ArchetypeFilesResolver;
50 import org.apache.maven.archetype.common.Constants;
51 import org.apache.maven.archetype.common.PomManager;
52 import org.apache.maven.archetype.exception.ArchetypeGenerationFailure;
53 import org.apache.maven.archetype.exception.ArchetypeNotConfigured;
54 import org.apache.maven.archetype.exception.InvalidPackaging;
55 import org.apache.maven.archetype.exception.OutputFileExists;
56 import org.apache.maven.archetype.exception.PomFileExists;
57 import org.apache.maven.archetype.exception.ProjectDirectoryExists;
58 import org.apache.maven.archetype.exception.UnknownArchetype;
59 import org.apache.maven.archetype.metadata.AbstractArchetypeDescriptor;
60 import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
61 import org.apache.maven.archetype.metadata.FileSet;
62 import org.apache.maven.archetype.metadata.ModuleDescriptor;
63 import org.apache.maven.archetype.metadata.RequiredProperty;
64 import org.apache.velocity.VelocityContext;
65 import org.apache.velocity.context.Context;
66 import org.codehaus.plexus.util.FileUtils;
67 import org.codehaus.plexus.util.IOUtil;
68 import org.codehaus.plexus.util.StringUtils;
69 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
70 import org.codehaus.plexus.velocity.VelocityComponent;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73 import org.xml.sax.SAXException;
74
75 @Named
76 @Singleton
77 public class DefaultFilesetArchetypeGenerator implements FilesetArchetypeGenerator {
78 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFilesetArchetypeGenerator.class);
79
80 private ArchetypeArtifactManager archetypeArtifactManager;
81
82 private ArchetypeFilesResolver archetypeFilesResolver;
83
84 private PomManager pomManager;
85
86 private VelocityComponent velocity;
87
88 @Inject
89 public DefaultFilesetArchetypeGenerator(
90 ArchetypeArtifactManager archetypeArtifactManager,
91 ArchetypeFilesResolver archetypeFilesResolver,
92 PomManager pomManager,
93 VelocityComponent velocity) {
94 this.archetypeArtifactManager = archetypeArtifactManager;
95 this.archetypeFilesResolver = archetypeFilesResolver;
96 this.pomManager = pomManager;
97 this.velocity = velocity;
98 }
99
100
101
102
103
104 private static final Pattern TOKEN_PATTERN = Pattern.compile("__((?:[^_]+_)*[^_]+)__");
105
106 @Override
107 @SuppressWarnings("checkstyle:MethodLength")
108 public void generateArchetype(ArchetypeGenerationRequest request, File archetypeFile)
109 throws UnknownArchetype, ArchetypeNotConfigured, ProjectDirectoryExists, PomFileExists, OutputFileExists,
110 ArchetypeGenerationFailure, InvalidPackaging {
111 ClassLoader old = Thread.currentThread().getContextClassLoader();
112
113 try {
114 ArchetypeDescriptor archetypeDescriptor =
115 archetypeArtifactManager.getFileSetArchetypeDescriptor(archetypeFile);
116
117 if (!isArchetypeConfigured(archetypeDescriptor, request)) {
118 if (request.isInteractiveMode()) {
119 throw new ArchetypeNotConfigured("No archetype was chosen.", null);
120 }
121
122 StringBuilder exceptionMessage = new StringBuilder(
123 "Archetype " + request.getArchetypeGroupId() + ":" + request.getArchetypeArtifactId() + ":"
124 + request.getArchetypeVersion() + " is not configured");
125
126 List<String> missingProperties = new ArrayList<>(0);
127 for (RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties()) {
128 if (StringUtils.isEmpty(request.getProperties().getProperty(requiredProperty.getKey()))) {
129 exceptionMessage.append("\n\tProperty " + requiredProperty.getKey() + " is missing.");
130
131 missingProperties.add(requiredProperty.getKey());
132 }
133 }
134
135 throw new ArchetypeNotConfigured(exceptionMessage.toString(), missingProperties);
136 }
137
138 Context context = prepareVelocityContext(request);
139
140 String packageName = request.getPackage();
141 String artifactId = request.getArtifactId();
142 File outputDirectoryFile = new File(request.getOutputDirectory(), artifactId);
143 File basedirPom = new File(request.getOutputDirectory(), Constants.ARCHETYPE_POM);
144 File pom = new File(outputDirectoryFile, Constants.ARCHETYPE_POM);
145
146 List<String> archetypeResources = archetypeArtifactManager.getFilesetArchetypeResources(archetypeFile);
147
148 ZipFile archetypeZipFile = archetypeArtifactManager.getArchetypeZipFile(archetypeFile);
149
150 ClassLoader archetypeJarLoader = archetypeArtifactManager.getArchetypeJarLoader(archetypeFile);
151
152 Thread.currentThread().setContextClassLoader(archetypeJarLoader);
153
154 if (archetypeDescriptor.isPartial()) {
155 LOGGER.debug("Processing partial archetype " + archetypeDescriptor.getName());
156 if (outputDirectoryFile.exists()) {
157 if (!pom.exists()) {
158 throw new PomFileExists("This is a partial archetype and the pom.xml file doesn't exist.");
159 }
160
161 processPomWithMerge(context, pom, "");
162
163 processArchetypeTemplatesWithWarning(
164 archetypeDescriptor,
165 archetypeResources,
166 archetypeZipFile,
167 "",
168 context,
169 packageName,
170 outputDirectoryFile);
171 } else {
172 if (basedirPom.exists()) {
173 processPomWithMerge(context, basedirPom, "");
174
175 processArchetypeTemplatesWithWarning(
176 archetypeDescriptor,
177 archetypeResources,
178 archetypeZipFile,
179 "",
180 context,
181 packageName,
182 new File(request.getOutputDirectory()));
183 } else {
184 processPom(context, pom, "");
185
186 processArchetypeTemplates(
187 archetypeDescriptor,
188 archetypeResources,
189 archetypeZipFile,
190 "",
191 context,
192 packageName,
193 outputDirectoryFile);
194 }
195 }
196
197 if (!archetypeDescriptor.getModules().isEmpty()) {
198 LOGGER.info("Modules ignored in partial mode");
199 }
200 } else {
201 LOGGER.debug("Processing complete archetype " + archetypeDescriptor.getName());
202 if (outputDirectoryFile.exists() && pom.exists()) {
203 throw new ProjectDirectoryExists(
204 "A Maven project already exists in the directory " + outputDirectoryFile.getPath());
205 }
206
207 if (outputDirectoryFile.exists()) {
208 LOGGER.warn("The directory " + outputDirectoryFile.getPath() + " already exists.");
209 }
210
211 context.put("rootArtifactId", artifactId);
212
213 processFilesetModule(
214 artifactId,
215 artifactId,
216 archetypeResources,
217 pom,
218 archetypeZipFile,
219 "",
220 basedirPom,
221 outputDirectoryFile,
222 packageName,
223 archetypeDescriptor,
224 context);
225 }
226
227 String postGenerationScript = archetypeArtifactManager.getPostGenerationScript(archetypeFile);
228 if (postGenerationScript != null) {
229 LOGGER.info("Executing " + Constants.ARCHETYPE_POST_GENERATION_SCRIPT + " post-generation script");
230
231 Binding binding = new Binding();
232
233 final Properties archetypeGeneratorProperties = new Properties();
234 archetypeGeneratorProperties.putAll(System.getProperties());
235
236 if (request.getProperties() != null) {
237 archetypeGeneratorProperties.putAll(request.getProperties());
238 }
239
240 for (Map.Entry<Object, Object> entry : archetypeGeneratorProperties.entrySet()) {
241 binding.setVariable(entry.getKey().toString(), entry.getValue());
242 }
243
244 binding.setVariable("request", request);
245
246 GroovyShell shell = new GroovyShell(binding);
247 shell.evaluate(postGenerationScript);
248 }
249
250
251
252
253 if (LOGGER.isInfoEnabled()) {
254 LOGGER.info("Project created from Archetype in dir: " + outputDirectoryFile.getAbsolutePath());
255 }
256 } catch (IOException
257 | XmlPullParserException
258 | ParserConfigurationException
259 | TransformerException
260 | SAXException e) {
261 throw new ArchetypeGenerationFailure(e);
262 } finally {
263 Thread.currentThread().setContextClassLoader(old);
264 }
265 }
266
267 public String getPackageAsDirectory(String packageName) {
268 return StringUtils.replace(packageName, ".", "/");
269 }
270
271 private boolean copyFile(
272 final File outFile, final String template, final boolean failIfExists, final ZipFile archetypeZipFile)
273 throws OutputFileExists, IOException {
274 LOGGER.debug("Copying file " + template);
275
276 if (failIfExists && outFile.exists()) {
277 throw new OutputFileExists("Don't rewrite file " + outFile.getName());
278 } else if (outFile.exists()) {
279 LOGGER.warn("CP Don't override file " + outFile);
280
281 return false;
282 }
283
284 ZipEntry input = archetypeZipFile.getEntry(Constants.ARCHETYPE_RESOURCES + "/" + template);
285
286 if (input.isDirectory()) {
287 outFile.mkdirs();
288 } else {
289 outFile.getParentFile().mkdirs();
290 if (!outFile.exists() && !outFile.createNewFile()) {
291 LOGGER.warn("Could not create new file \"" + outFile.getPath() + "\" or the file already exists.");
292 }
293
294 try (InputStream inputStream = archetypeZipFile.getInputStream(input);
295 OutputStream out = Files.newOutputStream(outFile.toPath())) {
296 IOUtil.copy(inputStream, out);
297 }
298 }
299
300 return true;
301 }
302
303 @SuppressWarnings("checkstyle:ParameterNumber")
304 private int copyFiles(
305 String directory,
306 List<String> fileSetResources,
307 boolean packaged,
308 String packageName,
309 File outputDirectoryFile,
310 ZipFile archetypeZipFile,
311 String moduleOffset,
312 boolean failIfExists,
313 Context context)
314 throws OutputFileExists, IOException {
315 int count = 0;
316
317 for (String template : fileSetResources) {
318 File outputFile = getOutputFile(
319 template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context);
320
321 if (copyFile(outputFile, template, failIfExists, archetypeZipFile)) {
322 count++;
323 }
324 }
325
326 return count;
327 }
328
329 private String getEncoding(String archetypeEncoding) {
330 return (archetypeEncoding == null || archetypeEncoding.isEmpty()) ? "UTF-8" : archetypeEncoding;
331 }
332
333 private String getOffsetSeparator(String moduleOffset) {
334 return (moduleOffset == null || moduleOffset.isEmpty()) ? "/" : ("/" + moduleOffset + "/");
335 }
336
337 private File getOutputFile(
338 String template,
339 String directory,
340 File outputDirectoryFile,
341 boolean packaged,
342 String packageName,
343 String moduleOffset,
344 Context context) {
345 String templateName = StringUtils.replaceOnce(template, directory, "");
346
347 String outputFileName = directory + "/" + (packaged ? getPackageAsDirectory(packageName) : "") + "/"
348 + templateName.substring(moduleOffset.length());
349
350 outputFileName = replaceFilenameTokens(outputFileName, context);
351
352 return new File(outputDirectoryFile, outputFileName);
353 }
354
355
356
357
358
359
360
361
362
363
364 private String replaceFilenameTokens(final String filePath, final Context context) {
365 StringBuffer interpolatedResult = new StringBuffer();
366 Matcher matcher = TOKEN_PATTERN.matcher(filePath);
367
368 while (matcher.find()) {
369 String propertyToken = matcher.group(1);
370 String contextPropertyValue = (String) context.get(propertyToken);
371 if (contextPropertyValue != null && !contextPropertyValue.trim().isEmpty()) {
372 if (LOGGER.isDebugEnabled()) {
373 LOGGER.debug("Replacing property '" + propertyToken + "' in file path '" + filePath
374 + "' with value '" + contextPropertyValue + "'.");
375 }
376 matcher.appendReplacement(interpolatedResult, contextPropertyValue);
377 } else {
378
379 LOGGER.warn("Property '" + propertyToken + "' was not specified, so the token in '" + filePath
380 + "' is not being replaced.");
381 }
382 }
383
384 matcher.appendTail(interpolatedResult);
385
386 if (LOGGER.isDebugEnabled()) {
387 LOGGER.debug("Final interpolated file path: '" + interpolatedResult + "'");
388 }
389
390 return interpolatedResult.toString();
391 }
392
393 private String getPackageInPathFormat(String aPackage) {
394 return StringUtils.replace(aPackage, ".", "/");
395 }
396
397 private boolean isArchetypeConfigured(ArchetypeDescriptor archetypeDescriptor, ArchetypeGenerationRequest request) {
398 for (RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties()) {
399 if (StringUtils.isEmpty(request.getProperties().getProperty(requiredProperty.getKey()))) {
400 return false;
401 }
402 }
403
404 return true;
405 }
406
407 private void setParentArtifactId(Context context, String artifactId) {
408 context.put(Constants.PARENT_ARTIFACT_ID, artifactId);
409 }
410
411 private Context prepareVelocityContext(ArchetypeGenerationRequest request) {
412 Context context = new VelocityContext();
413 context.put(Constants.GROUP_ID, request.getGroupId());
414 context.put(Constants.ARTIFACT_ID, request.getArtifactId());
415 context.put(Constants.VERSION, request.getVersion());
416 context.put(Constants.PACKAGE, request.getPackage());
417 final String packageInPathFormat = getPackageInPathFormat(request.getPackage());
418 context.put(Constants.PACKAGE_IN_PATH_FORMAT, packageInPathFormat);
419
420 if (LOGGER.isInfoEnabled()) {
421 LOGGER.info("----------------------------------------------------------------------------");
422
423 LOGGER.info("Using following parameters for creating project from Archetype: "
424 + request.getArchetypeArtifactId() + ":" + request.getArchetypeVersion());
425
426 LOGGER.info("----------------------------------------------------------------------------");
427 LOGGER.info("Parameter: " + Constants.GROUP_ID + ", Value: " + request.getGroupId());
428 LOGGER.info("Parameter: " + Constants.ARTIFACT_ID + ", Value: " + request.getArtifactId());
429 LOGGER.info("Parameter: " + Constants.VERSION + ", Value: " + request.getVersion());
430 LOGGER.info("Parameter: " + Constants.PACKAGE + ", Value: " + request.getPackage());
431 LOGGER.info("Parameter: " + Constants.PACKAGE_IN_PATH_FORMAT + ", Value: " + packageInPathFormat);
432 }
433
434 for (Iterator<?> iterator = request.getProperties().keySet().iterator(); iterator.hasNext(); ) {
435 String key = (String) iterator.next();
436
437 String value = request.getProperties().getProperty(key);
438
439 if (maybeVelocityExpression(value)) {
440 value = evaluateExpression(context, key, value);
441 }
442
443 context.put(key, value);
444
445 if (LOGGER.isInfoEnabled()) {
446 LOGGER.info("Parameter: " + key + ", Value: " + value);
447 }
448 }
449 return context;
450 }
451
452 private boolean maybeVelocityExpression(String value) {
453 return value != null && value.contains("${");
454 }
455
456 private String evaluateExpression(Context context, String key, String value) {
457 try (StringWriter stringWriter = new StringWriter()) {
458 velocity.getEngine().evaluate(context, stringWriter, key, value);
459 return stringWriter.toString();
460 } catch (Exception ex) {
461 return value;
462 }
463 }
464
465 private void processArchetypeTemplates(
466 AbstractArchetypeDescriptor archetypeDescriptor,
467 List<String> archetypeResources,
468 ZipFile archetypeZipFile,
469 String moduleOffset,
470 Context context,
471 String packageName,
472 File outputDirectoryFile)
473 throws OutputFileExists, ArchetypeGenerationFailure, IOException {
474 processTemplates(
475 packageName,
476 outputDirectoryFile,
477 context,
478 archetypeDescriptor,
479 archetypeResources,
480 archetypeZipFile,
481 moduleOffset,
482 false);
483 }
484
485 private void processArchetypeTemplatesWithWarning(
486 ArchetypeDescriptor archetypeDescriptor,
487 List<String> archetypeResources,
488 ZipFile archetypeZipFile,
489 String moduleOffset,
490 Context context,
491 String packageName,
492 File outputDirectoryFile)
493 throws OutputFileExists, ArchetypeGenerationFailure, IOException {
494 processTemplates(
495 packageName,
496 outputDirectoryFile,
497 context,
498 archetypeDescriptor,
499 archetypeResources,
500 archetypeZipFile,
501 moduleOffset,
502 true);
503 }
504
505 @SuppressWarnings("checkstyle:ParameterNumber")
506 private int processFileSet(
507 String directory,
508 List<String> fileSetResources,
509 boolean packaged,
510 String packageName,
511 Context context,
512 File outputDirectoryFile,
513 String moduleOffset,
514 String archetypeEncoding,
515 boolean failIfExists)
516 throws IOException, OutputFileExists, ArchetypeGenerationFailure {
517 int count = 0;
518
519 for (String template : fileSetResources) {
520 File outputFile = getOutputFile(
521 template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context);
522
523 if (processTemplate(
524 outputFile,
525 context,
526 Constants.ARCHETYPE_RESOURCES + "/" + template,
527 archetypeEncoding,
528 failIfExists)) {
529 count++;
530 }
531 }
532
533 return count;
534 }
535
536 @SuppressWarnings("checkstyle:ParameterNumber")
537 private void processFilesetModule(
538 final String rootArtifactId,
539 final String artifactId,
540 final List<String> archetypeResources,
541 File pom,
542 final ZipFile archetypeZipFile,
543 String moduleOffset,
544 File basedirPom,
545 File outputDirectoryFile,
546 final String packageName,
547 final AbstractArchetypeDescriptor archetypeDescriptor,
548 final Context context)
549 throws XmlPullParserException, IOException, ParserConfigurationException, SAXException,
550 TransformerException, OutputFileExists, ArchetypeGenerationFailure, InvalidPackaging {
551 outputDirectoryFile.mkdirs();
552 LOGGER.debug("Processing module " + artifactId);
553 LOGGER.debug("Processing module rootArtifactId " + rootArtifactId);
554 LOGGER.debug("Processing module pom " + pom);
555 LOGGER.debug("Processing module moduleOffset " + moduleOffset);
556 LOGGER.debug("Processing module outputDirectoryFile " + outputDirectoryFile);
557
558 processFilesetProject(
559 archetypeDescriptor,
560 StringUtils.replace(artifactId, "${rootArtifactId}", rootArtifactId),
561 archetypeResources,
562 pom,
563 archetypeZipFile,
564 moduleOffset,
565 context,
566 packageName,
567 outputDirectoryFile,
568 basedirPom);
569
570 String parentArtifactId = (String) context.get(Constants.PARENT_ARTIFACT_ID);
571
572 Iterator<ModuleDescriptor> subprojects =
573 archetypeDescriptor.getModules().iterator();
574
575 if (subprojects.hasNext()) {
576 LOGGER.debug(artifactId + " has modules (" + archetypeDescriptor.getModules() + ")");
577
578 setParentArtifactId(context, StringUtils.replace(artifactId, "${rootArtifactId}", rootArtifactId));
579 }
580
581 while (subprojects.hasNext()) {
582 ModuleDescriptor project = subprojects.next();
583
584 String modulePath = StringUtils.replace(project.getDir(), "__rootArtifactId__", rootArtifactId);
585 modulePath = replaceFilenameTokens(modulePath, context);
586
587 File moduleOutputDirectoryFile = new File(outputDirectoryFile, modulePath);
588
589 context.put(
590 Constants.ARTIFACT_ID, StringUtils.replace(project.getId(), "${rootArtifactId}", rootArtifactId));
591
592 String moduleArtifactId = StringUtils.replace(project.getDir(), "__rootArtifactId__", rootArtifactId);
593 moduleArtifactId = replaceFilenameTokens(moduleArtifactId, context);
594
595 processFilesetModule(
596 rootArtifactId,
597 moduleArtifactId,
598 archetypeResources,
599 new File(moduleOutputDirectoryFile, Constants.ARCHETYPE_POM),
600 archetypeZipFile,
601 ((moduleOffset == null || moduleOffset.isEmpty()) ? "" : (moduleOffset + "/"))
602 + StringUtils.replace(project.getDir(), "${rootArtifactId}", rootArtifactId),
603 pom,
604 moduleOutputDirectoryFile,
605 packageName,
606 project,
607 context);
608 }
609
610 restoreParentArtifactId(context, parentArtifactId);
611
612 LOGGER.debug("Processed " + artifactId);
613 }
614
615 @SuppressWarnings("checkstyle:ParameterNumber")
616 private void processFilesetProject(
617 final AbstractArchetypeDescriptor archetypeDescriptor,
618 final String moduleId,
619 final List<String> archetypeResources,
620 final File pom,
621 final ZipFile archetypeZipFile,
622 String moduleOffset,
623 final Context context,
624 final String packageName,
625 final File outputDirectoryFile,
626 final File basedirPom)
627 throws XmlPullParserException, IOException, ParserConfigurationException, SAXException,
628 TransformerException, OutputFileExists, ArchetypeGenerationFailure, InvalidPackaging {
629 LOGGER.debug("Processing fileset project moduleId " + moduleId);
630 LOGGER.debug("Processing fileset project pom " + pom);
631 LOGGER.debug("Processing fileset project moduleOffset " + moduleOffset);
632 LOGGER.debug("Processing fileset project outputDirectoryFile " + outputDirectoryFile);
633 LOGGER.debug("Processing fileset project basedirPom " + basedirPom);
634
635 if (basedirPom.exists()) {
636 processPomWithParent(context, pom, moduleOffset, basedirPom, moduleId);
637 } else {
638 processPom(context, pom, moduleOffset);
639 }
640
641 processArchetypeTemplates(
642 archetypeDescriptor,
643 archetypeResources,
644 archetypeZipFile,
645 moduleOffset,
646 context,
647 packageName,
648 outputDirectoryFile);
649 }
650
651 private void processPom(Context context, File pom, String moduleOffset)
652 throws IOException, OutputFileExists, ArchetypeGenerationFailure {
653 LOGGER.debug("Processing pom " + pom);
654
655 processTemplate(
656 pom,
657 context,
658 Constants.ARCHETYPE_RESOURCES + getOffsetSeparator(moduleOffset) + Constants.ARCHETYPE_POM,
659 getEncoding(null),
660 true);
661 }
662
663 private void processPomWithMerge(Context context, File pom, String moduleOffset)
664 throws OutputFileExists, IOException, XmlPullParserException, ArchetypeGenerationFailure {
665 LOGGER.debug("Processing pom " + pom + " with merge");
666
667 File temporaryPom = getTemporaryFile(pom);
668
669 processTemplate(
670 temporaryPom,
671 context,
672 Constants.ARCHETYPE_RESOURCES + getOffsetSeparator(moduleOffset) + Constants.ARCHETYPE_POM,
673 getEncoding(null),
674 true);
675
676 pomManager.mergePoms(pom, temporaryPom);
677
678
679
680 try {
681 FileUtils.forceDelete(temporaryPom);
682 } catch (IOException e) {
683 temporaryPom.deleteOnExit();
684 }
685 }
686
687 private void processPomWithParent(Context context, File pom, String moduleOffset, File basedirPom, String moduleId)
688 throws XmlPullParserException, IOException, ParserConfigurationException, SAXException,
689 TransformerException, OutputFileExists, ArchetypeGenerationFailure, InvalidPackaging {
690 LOGGER.debug("Processing pom " + pom + " with parent " + basedirPom);
691
692 processTemplate(
693 pom,
694 context,
695 Constants.ARCHETYPE_RESOURCES + getOffsetSeparator(moduleOffset) + Constants.ARCHETYPE_POM,
696 getEncoding(null),
697 true);
698
699 LOGGER.debug("Adding module " + moduleId);
700
701 pomManager.addModule(basedirPom, moduleId);
702
703 pomManager.addParent(pom, basedirPom);
704 }
705
706 @SuppressWarnings("deprecation")
707 private boolean processTemplate(
708 File outFile, Context context, String templateFileName, String encoding, boolean failIfExists)
709 throws IOException, OutputFileExists, ArchetypeGenerationFailure {
710 templateFileName = templateFileName.replace(File.separatorChar, '/');
711
712 String localTemplateFileName = templateFileName.replace('/', File.separatorChar);
713 if (!templateFileName.equals(localTemplateFileName)
714 && !velocity.getEngine().resourceExists(templateFileName)
715 && velocity.getEngine().resourceExists(localTemplateFileName)) {
716 templateFileName = localTemplateFileName;
717 }
718
719 LOGGER.debug("Processing template " + templateFileName);
720
721 if (outFile.exists()) {
722 if (failIfExists) {
723 throw new OutputFileExists("Don't override file " + outFile.getAbsolutePath());
724 }
725
726 LOGGER.warn("Don't override file " + outFile);
727
728 return false;
729 }
730
731 if (templateFileName.endsWith("/")) {
732 LOGGER.debug("Creating directory " + outFile);
733
734 outFile.mkdirs();
735
736 return true;
737 }
738
739 if (!outFile.getParentFile().exists()) {
740 outFile.getParentFile().mkdirs();
741 }
742
743 if (!outFile.exists() && !outFile.createNewFile()) {
744 LOGGER.warn("Could not create new file \"" + outFile.getPath() + "\" or the file already exists.");
745 }
746
747 LOGGER.debug("Merging into " + outFile);
748
749 try (Writer writer = new OutputStreamWriter(Files.newOutputStream(outFile.toPath()), encoding)) {
750 StringWriter stringWriter = new StringWriter();
751
752 velocity.getEngine().mergeTemplate(templateFileName, encoding, context, stringWriter);
753
754 writer.write(StringUtils.unifyLineSeparators(stringWriter.toString()));
755 } catch (Exception e) {
756 throw new ArchetypeGenerationFailure("Error merging velocity templates: " + e.getMessage(), e);
757 }
758
759 return true;
760 }
761
762 @SuppressWarnings("checkstyle:ParameterNumber")
763 private void processTemplates(
764 String packageName,
765 File outputDirectoryFile,
766 Context context,
767 AbstractArchetypeDescriptor archetypeDescriptor,
768 List<String> archetypeResources,
769 ZipFile archetypeZipFile,
770 String moduleOffset,
771 boolean failIfExists)
772 throws OutputFileExists, ArchetypeGenerationFailure, IOException {
773 Iterator<FileSet> iterator = archetypeDescriptor.getFileSets().iterator();
774 if (iterator.hasNext()) {
775 LOGGER.debug("Processing filesets" + "\n " + archetypeResources);
776 }
777
778 int count = 0;
779 while (iterator.hasNext()) {
780 FileSet fileSet = iterator.next();
781 count++;
782
783 final String includeCondition = fileSet.getIncludeCondition();
784 if (includeCondition != null && !includeCondition.isEmpty()) {
785 final String evaluatedCondition = evaluateExpression(context, "includeCondition", includeCondition);
786 if (!Boolean.parseBoolean(evaluatedCondition)) {
787 LOGGER.debug(String.format(
788 "Skipping fileset %s due to includeCondition: %s being: %s",
789 fileSet, includeCondition, evaluatedCondition));
790 continue;
791 }
792 }
793
794 List<String> fileSetResources =
795 archetypeFilesResolver.filterFiles(moduleOffset, fileSet, archetypeResources);
796
797
798
799 getOutputFile(
800 moduleOffset,
801 fileSet.getDirectory(),
802 outputDirectoryFile,
803 fileSet.isPackaged(),
804 packageName,
805 moduleOffset,
806 context)
807 .mkdirs();
808
809 if (fileSet.isFiltered()) {
810 LOGGER.debug(" Processing fileset " + fileSet + " -> " + fileSetResources.size() + ":\n "
811 + fileSetResources);
812
813 int processed = processFileSet(
814 fileSet.getDirectory(),
815 fileSetResources,
816 fileSet.isPackaged(),
817 packageName,
818 context,
819 outputDirectoryFile,
820 moduleOffset,
821 getEncoding(fileSet.getEncoding()),
822 failIfExists);
823
824 LOGGER.debug(" Processed " + processed + " files.");
825 } else {
826 LOGGER.debug(" Copying fileset " + fileSet + " -> " + fileSetResources.size() + ":\n "
827 + fileSetResources);
828
829 int copied = copyFiles(
830 fileSet.getDirectory(),
831 fileSetResources,
832 fileSet.isPackaged(),
833 packageName,
834 outputDirectoryFile,
835 archetypeZipFile,
836 moduleOffset,
837 failIfExists,
838 context);
839
840 LOGGER.debug(" Copied " + copied + " files.");
841 }
842 }
843
844 LOGGER.debug("Processed " + count + " filesets");
845 }
846
847 private void restoreParentArtifactId(Context context, String parentArtifactId) {
848 if (parentArtifactId == null || parentArtifactId.isEmpty()) {
849 context.remove(Constants.PARENT_ARTIFACT_ID);
850 } else {
851 context.put(Constants.PARENT_ARTIFACT_ID, parentArtifactId);
852 }
853 }
854
855 private File getTemporaryFile(File file) {
856 File tmp = FileUtils.createTempFile(file.getName(), Constants.TMP, file.getParentFile());
857
858 tmp.deleteOnExit();
859
860 return tmp;
861 }
862 }