| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.codehaus.mojo.archetypeng.generator; |
| |
| import org.apache.velocity.VelocityContext; |
| import org.apache.velocity.context.Context; |
| |
| import org.codehaus.mojo.archetypeng.ArchetypeArtifactManager; |
| import org.codehaus.mojo.archetypeng.ArchetypeConfiguration; |
| import org.codehaus.mojo.archetypeng.ArchetypeFactory; |
| import org.codehaus.mojo.archetypeng.ArchetypeFilesResolver; |
| import org.codehaus.mojo.archetypeng.Constants; |
| import org.codehaus.mojo.archetypeng.PomManager; |
| import org.codehaus.mojo.archetypeng.archetype.filesets.AbstractArchetypeDescriptor; |
| import org.codehaus.mojo.archetypeng.archetype.filesets.ArchetypeDescriptor; |
| import org.codehaus.mojo.archetypeng.archetype.filesets.FileSet; |
| import org.codehaus.mojo.archetypeng.archetype.filesets.ModuleDescriptor; |
| import org.codehaus.mojo.archetypeng.exception.ArchetypeGenerationFailure; |
| import org.codehaus.mojo.archetypeng.exception.ArchetypeNotConfigured; |
| import org.codehaus.mojo.archetypeng.exception.InvalidPackaging; |
| import org.codehaus.mojo.archetypeng.exception.OutputFileExists; |
| import org.codehaus.mojo.archetypeng.exception.PomFileExists; |
| import org.codehaus.mojo.archetypeng.exception.ProjectDirectoryExists; |
| import org.codehaus.mojo.archetypeng.exception.UnknownArchetype; |
| |
| import org.codehaus.plexus.logging.AbstractLogEnabled; |
| import org.codehaus.plexus.util.FileUtils; |
| import org.codehaus.plexus.util.IOUtil; |
| import org.codehaus.plexus.util.StringUtils; |
| import org.codehaus.plexus.util.xml.pull.XmlPullParserException; |
| import org.codehaus.plexus.velocity.VelocityComponent; |
| |
| import org.dom4j.DocumentException; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStreamWriter; |
| import java.io.Writer; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipFile; |
| |
| /** |
| * @plexus.component |
| */ |
| public class DefaultFilesetArchetypeGenerator |
| extends AbstractLogEnabled |
| implements FilesetArchetypeGenerator |
| { |
| /** |
| * @plexus.requirement |
| */ |
| private ArchetypeArtifactManager archetypeArtifactManager; |
| |
| /** |
| * @plexus.requirement |
| */ |
| private ArchetypeFactory archetypeFactory; |
| |
| /** |
| * @plexus.requirement |
| */ |
| private ArchetypeFilesResolver archetypeFilesResolver; |
| |
| /** |
| * @plexus.requirement |
| */ |
| private PomManager pomManager; |
| |
| /** |
| * @plexus.requirement |
| */ |
| private VelocityComponent velocity; |
| |
| public void generateArchetype ( Properties properties, File archetypeFile, String basedir ) |
| throws UnknownArchetype, |
| ArchetypeNotConfigured, |
| ProjectDirectoryExists, |
| PomFileExists, |
| OutputFileExists, |
| ArchetypeGenerationFailure |
| { |
| ClassLoader old = Thread.currentThread ().getContextClassLoader (); |
| |
| try |
| { |
| ArchetypeDescriptor archetypeDescriptor = |
| archetypeArtifactManager.getFileSetArchetypeDescriptor ( archetypeFile ); |
| ArchetypeConfiguration archetypeConfiguration = |
| archetypeFactory.createArchetypeConfiguration ( archetypeDescriptor, properties ); |
| |
| if ( !archetypeConfiguration.isConfigured () ) |
| { |
| throw new ArchetypeNotConfigured ( "The archetype is not configured" ); |
| } |
| |
| Context context = prepareVelocityContext ( archetypeConfiguration ); |
| String packageName = |
| archetypeConfiguration.getProperties ().getProperty ( Constants.PACKAGE ); |
| |
| String artifactId = |
| archetypeConfiguration.getProperties ().getProperty ( Constants.ARTIFACT_ID ); |
| File outputDirectoryFile = new File ( basedir, artifactId ); |
| File basedirPom = new File ( basedir, Constants.ARCHETYPE_POM ); |
| File pom = new File ( outputDirectoryFile, Constants.ARCHETYPE_POM ); |
| |
| List archetypeResources = |
| archetypeArtifactManager.getFilesetArchetypeResources ( archetypeFile ); |
| |
| ZipFile archetypeZipFile = |
| archetypeArtifactManager.getArchetypeZipFile ( archetypeFile ); |
| |
| ClassLoader archetypeJarLoader = |
| archetypeArtifactManager.getArchetypeJarLoader ( archetypeFile ); |
| |
| Thread.currentThread ().setContextClassLoader ( archetypeJarLoader ); |
| |
| if ( archetypeDescriptor.isPartial () ) |
| { |
| getLogger ().debug ( |
| "Procesing partial archetype " + archetypeDescriptor.getId () |
| ); |
| if ( outputDirectoryFile.exists () ) |
| { |
| if ( !pom.exists () ) |
| { |
| throw new PomFileExists ( "The pom file already exists" ); |
| } |
| else |
| { |
| processPomWithMerge ( context, pom, "" ); |
| processArchetypeTemplatesWithWarning ( |
| archetypeDescriptor, |
| archetypeResources, |
| archetypeZipFile, |
| "", |
| context, |
| packageName, |
| outputDirectoryFile |
| ); |
| } |
| } |
| else |
| { |
| if ( basedirPom.exists () ) |
| { |
| processPomWithMerge ( context, basedirPom, "" ); |
| processArchetypeTemplatesWithWarning ( |
| archetypeDescriptor, |
| archetypeResources, |
| archetypeZipFile, |
| "", |
| context, |
| packageName, |
| new File ( basedir ) |
| ); |
| } |
| else |
| { |
| processPom ( context, pom, "" ); |
| processArchetypeTemplates ( |
| archetypeDescriptor, |
| archetypeResources, |
| archetypeZipFile, |
| "", |
| context, |
| packageName, |
| outputDirectoryFile |
| ); |
| } |
| } |
| |
| if ( archetypeDescriptor.getModules ().size () > 0 ) |
| { |
| getLogger ().info ( "Modules ignored in partial mode" ); |
| } |
| } |
| else |
| { |
| getLogger ().debug ( |
| "Procesing complete archetype " + archetypeDescriptor.getId () |
| ); |
| if ( outputDirectoryFile.exists () ) |
| { |
| throw new ProjectDirectoryExists ( "The project directory already exists" ); |
| } |
| else |
| { |
| processFilesetModule ( |
| artifactId, |
| archetypeResources, |
| pom, |
| archetypeZipFile, |
| "", |
| basedirPom, |
| outputDirectoryFile, |
| packageName, |
| archetypeDescriptor, |
| context |
| ); |
| } |
| } // end if |
| } |
| catch ( FileNotFoundException ex ) |
| { |
| throw new ArchetypeGenerationFailure ( ex ); |
| } |
| catch ( IOException ex ) |
| { |
| throw new ArchetypeGenerationFailure ( ex ); |
| } |
| catch ( XmlPullParserException ex ) |
| { |
| throw new ArchetypeGenerationFailure ( ex ); |
| } |
| catch ( DocumentException ex ) |
| { |
| throw new ArchetypeGenerationFailure ( ex ); |
| } |
| catch ( ArchetypeGenerationFailure ex ) |
| { |
| throw new ArchetypeGenerationFailure ( ex ); |
| } |
| catch ( InvalidPackaging ex ) |
| { |
| throw new ArchetypeGenerationFailure ( ex ); |
| } |
| finally |
| { |
| Thread.currentThread ().setContextClassLoader ( old ); |
| } |
| } |
| |
| public String getPackageAsDirectory ( String packageName ) |
| { |
| return StringUtils.replace ( packageName, ".", "/" ); |
| } |
| |
| private void copyFile ( |
| final File outFile, |
| final String template, |
| final boolean failIfExists, |
| final ZipFile archetypeZipFile |
| ) |
| throws FileNotFoundException, OutputFileExists, IOException |
| { |
| getLogger ().debug ( "Copying file " + template ); |
| |
| if ( failIfExists && outFile.exists () ) |
| { |
| throw new OutputFileExists ( "Don't rewrite file " + outFile.getName () ); |
| } |
| else if ( outFile.exists () ) |
| { |
| getLogger ().warn ( "CP Don't override file " + outFile ); |
| } |
| else |
| { |
| ZipEntry input = |
| archetypeZipFile.getEntry ( Constants.ARCHETYPE_RESOURCES + "/" + template ); |
| |
| InputStream inputStream = archetypeZipFile.getInputStream ( input ); |
| |
| outFile.getParentFile ().mkdirs (); |
| |
| IOUtil.copy ( inputStream, new FileOutputStream ( outFile ) ); |
| } |
| } |
| |
| private void copyFiles ( |
| String directory, |
| List fileSetResources, |
| boolean packaged, |
| String packageName, |
| File outputDirectoryFile, |
| ZipFile archetypeZipFile, |
| String moduleOffset, |
| boolean failIfExists |
| ) |
| throws OutputFileExists, FileNotFoundException, IOException |
| { |
| Iterator iterator = fileSetResources.iterator (); |
| |
| while ( iterator.hasNext () ) |
| { |
| String template = (String) iterator.next (); |
| |
| String templateName = StringUtils.replaceOnce ( template, directory + "/", "" ); |
| |
| if ( !StringUtils.isEmpty ( moduleOffset ) ) |
| { |
| templateName = StringUtils.replaceOnce ( templateName, moduleOffset + "/", "" ); |
| } |
| templateName = StringUtils.replace ( templateName, File.separator, "/" ); |
| |
| File outFile = |
| new File ( |
| outputDirectoryFile, /*(StringUtils.isEmpty |
| * (moduleOffset)?"":moduleOffset+"/")+*/ |
| directory + "/" + ( packaged ? getPackageAsDirectory ( packageName ) : "" ) |
| + "/" + templateName |
| ); |
| |
| copyFile ( outFile, template, failIfExists, archetypeZipFile ); |
| } // end while |
| } |
| |
| private String getEncoding ( String archetypeEncoding ) |
| { |
| return |
| ( ( null == archetypeEncoding ) || "".equals ( archetypeEncoding ) ) |
| ? "UTF-8" |
| : archetypeEncoding; |
| } |
| |
| private String getOffsetSeparator ( String moduleOffset ) |
| { |
| return ( StringUtils.isEmpty ( moduleOffset ) ? "/" : ( "/" + moduleOffset + "/" ) ); |
| } |
| |
| private void setParentArtifactId ( Context context, String artifactId ) |
| { |
| context.put ( Constants.PARENT_ARTIFACT_ID, artifactId ); |
| } |
| |
| private Context prepareVelocityContext ( ArchetypeConfiguration archetypeConfiguration ) |
| { |
| Context context = new VelocityContext (); |
| Iterator iterator = archetypeConfiguration.getProperties ().keySet ().iterator (); |
| while ( iterator.hasNext () ) |
| { |
| String key = (String) iterator.next (); |
| |
| Object value = archetypeConfiguration.getProperties ().getProperty ( key ); |
| |
| context.put ( key, value ); |
| } |
| return context; |
| } |
| |
| private void processArchetypeTemplates ( |
| AbstractArchetypeDescriptor archetypeDescriptor, |
| List archetypeResources, |
| ZipFile archetypeZipFile, |
| String moduleOffset, |
| Context context, |
| String packageName, |
| File outputDirectoryFile |
| ) |
| throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException |
| { |
| processTemplates ( |
| packageName, |
| outputDirectoryFile, |
| context, |
| archetypeDescriptor, |
| archetypeResources, |
| archetypeZipFile, |
| moduleOffset, |
| false |
| ); |
| } |
| |
| private void processArchetypeTemplatesWithWarning ( |
| org.codehaus.mojo.archetypeng.archetype.filesets.ArchetypeDescriptor archetypeDescriptor, |
| List archetypeResources, |
| ZipFile archetypeZipFile, |
| String moduleOffset, |
| Context context, |
| String packageName, |
| File outputDirectoryFile |
| ) |
| throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException |
| { |
| processTemplates ( |
| packageName, |
| outputDirectoryFile, |
| context, |
| archetypeDescriptor, |
| archetypeResources, |
| archetypeZipFile, |
| moduleOffset, |
| true |
| ); |
| } |
| |
| private void processFileSet ( |
| String directory, |
| List fileSetResources, |
| boolean packaged, |
| String packageName, |
| Context context, |
| File outputDirectoryFile, |
| String moduleOffset, |
| String archetypeEncoding, |
| boolean failIfExists |
| ) |
| throws OutputFileExists, ArchetypeGenerationFailure |
| { |
| Iterator iterator = fileSetResources.iterator (); |
| |
| while ( iterator.hasNext () ) |
| { |
| String template = (String) iterator.next (); |
| |
| String templateName = StringUtils.replaceOnce ( template, directory, "" ); |
| |
| processTemplate ( |
| new File ( |
| outputDirectoryFile, |
| directory + "/" + ( packaged ? getPackageAsDirectory ( packageName ) : "" ) |
| + "/" + templateName.substring ( moduleOffset.length () ) |
| ), |
| context, |
| Constants.ARCHETYPE_RESOURCES + "/" /*+ |
| *getOffsetSeparator(moduleOffset)*/ + template, |
| archetypeEncoding, |
| failIfExists |
| ); |
| } // end while |
| } |
| |
| private void processFilesetModule ( |
| String artifactId, |
| final List archetypeResources, |
| File pom, |
| final ZipFile archetypeZipFile, |
| String moduleOffset, |
| File basedirPom, |
| File outputDirectoryFile, |
| final String packageName, |
| final AbstractArchetypeDescriptor archetypeDescriptor, |
| final Context context |
| ) |
| throws DocumentException, |
| XmlPullParserException, |
| ArchetypeGenerationFailure, |
| InvalidPackaging, |
| IOException, |
| OutputFileExists |
| { |
| outputDirectoryFile.mkdirs (); |
| getLogger ().debug ( "Processing " + artifactId ); |
| |
| processFilesetProject ( |
| archetypeDescriptor, |
| artifactId, |
| archetypeResources, |
| pom, |
| archetypeZipFile, |
| moduleOffset, |
| context, |
| packageName, |
| outputDirectoryFile, |
| basedirPom |
| ); |
| |
| String parentArtifactId = (String) context.get ( Constants.PARENT_ARTIFACT_ID ); |
| Iterator subprojects = archetypeDescriptor.getModules ().iterator (); |
| if ( subprojects.hasNext () ) |
| { |
| getLogger ().debug ( |
| artifactId + " has modules (" + archetypeDescriptor.getModules () + ")" |
| ); |
| setParentArtifactId ( context, artifactId ); |
| } |
| while ( subprojects.hasNext () ) |
| { |
| ModuleDescriptor project = (ModuleDescriptor) subprojects.next (); |
| |
| artifactId = project.getId (); |
| |
| File moduleOutputDirectoryFile = new File ( outputDirectoryFile, artifactId ); |
| context.put ( Constants.ARTIFACT_ID, artifactId ); |
| processFilesetModule ( |
| artifactId, |
| archetypeResources, |
| new File ( moduleOutputDirectoryFile, Constants.ARCHETYPE_POM ), |
| archetypeZipFile, |
| ( StringUtils.isEmpty ( moduleOffset ) ? "" : ( moduleOffset + "/" ) ) + artifactId, |
| pom, |
| moduleOutputDirectoryFile, |
| packageName, |
| project, |
| context |
| ); |
| } |
| restoreParentArtifactId ( context, parentArtifactId ); |
| getLogger ().debug ( "Processed " + artifactId ); |
| } |
| |
| private void processFilesetProject ( |
| final AbstractArchetypeDescriptor archetypeDescriptor, |
| final String artifactId, |
| final List archetypeResources, |
| final File pom, |
| final ZipFile archetypeZipFile, |
| String moduleOffset, |
| final Context context, |
| final String packageName, |
| final File outputDirectoryFile, |
| final File basedirPom |
| ) |
| throws DocumentException, |
| XmlPullParserException, |
| ArchetypeGenerationFailure, |
| InvalidPackaging, |
| IOException, |
| FileNotFoundException, |
| OutputFileExists |
| { |
| if ( basedirPom.exists () ) |
| { |
| processPomWithParent ( |
| |
| context, |
| pom, |
| moduleOffset, |
| basedirPom, |
| artifactId |
| ); |
| } |
| else |
| { |
| processPom ( context, pom, moduleOffset ); |
| } |
| |
| processArchetypeTemplates ( |
| archetypeDescriptor, |
| archetypeResources, |
| archetypeZipFile, |
| moduleOffset, |
| context, |
| packageName, |
| outputDirectoryFile |
| ); |
| } |
| |
| private void processPom ( Context context, File pom, String moduleOffset ) |
| throws OutputFileExists, ArchetypeGenerationFailure |
| { |
| getLogger ().debug ( "Processing pom " + pom ); |
| processTemplate ( |
| pom, |
| context, |
| Constants.ARCHETYPE_RESOURCES + getOffsetSeparator ( moduleOffset ) |
| + Constants.ARCHETYPE_POM, |
| getEncoding ( null ), |
| true |
| ); |
| } |
| |
| private void processPomWithMerge ( Context context, File pom, String moduleOffset ) |
| throws OutputFileExists, IOException, XmlPullParserException, ArchetypeGenerationFailure |
| { |
| getLogger ().debug ( "Processing pom " + pom + " with merge" ); |
| |
| File temporaryPom = getTemporaryFile ( pom ); |
| |
| processTemplate ( |
| temporaryPom, |
| context, |
| Constants.ARCHETYPE_RESOURCES + getOffsetSeparator ( moduleOffset ) |
| + Constants.ARCHETYPE_POM, |
| getEncoding ( null ), |
| true |
| ); |
| |
| pomManager.mergePoms ( pom, temporaryPom ); |
| |
| FileUtils.forceDelete ( temporaryPom ); |
| } |
| |
| private void processPomWithParent ( |
| Context context, |
| File pom, |
| String moduleOffset, |
| File basedirPom, |
| String artifactId |
| ) |
| throws OutputFileExists, |
| FileNotFoundException, |
| XmlPullParserException, |
| DocumentException, |
| IOException, |
| InvalidPackaging, |
| ArchetypeGenerationFailure |
| { |
| getLogger ().debug ( "Processing pom " + pom + " with parent " + basedirPom ); |
| processTemplate ( |
| pom, |
| context, |
| Constants.ARCHETYPE_RESOURCES + getOffsetSeparator ( moduleOffset ) |
| + Constants.ARCHETYPE_POM, |
| getEncoding ( null ), |
| true |
| ); |
| |
| if ( StringUtils.isEmpty ( moduleOffset ) ) |
| { |
| getLogger ().debug ( "Adding module " + artifactId ); |
| pomManager.addModule ( basedirPom, artifactId ); |
| pomManager.addParent ( pom, basedirPom ); |
| } |
| } |
| |
| private void processTemplate ( |
| File outFile, |
| Context context, |
| String templateFileName, |
| String encoding, |
| boolean failIfExists |
| ) |
| throws OutputFileExists, ArchetypeGenerationFailure |
| { |
| templateFileName = templateFileName.replace ( File.separatorChar, '/' ); |
| |
| getLogger ().debug ( "Prosessing template " + templateFileName ); |
| |
| if ( failIfExists && outFile.exists () ) |
| { |
| throw new OutputFileExists ( "Don't rewrite file " + outFile.getName () ); |
| } |
| else if ( outFile.exists () ) |
| { |
| getLogger ().warn ( "PT Don't override file " + outFile ); |
| } |
| else |
| { |
| if ( !outFile.getParentFile ().exists () ) |
| { |
| outFile.getParentFile ().mkdirs (); |
| } |
| |
| Writer writer = null; |
| |
| try |
| { |
| writer = new OutputStreamWriter ( new FileOutputStream ( outFile ), encoding ); |
| |
| velocity.getEngine ().mergeTemplate ( templateFileName, encoding, context, writer ); |
| |
| writer.flush (); |
| } |
| catch ( Exception e ) |
| { |
| throw new ArchetypeGenerationFailure ( |
| "Error merging velocity templates: " + e.getMessage (), |
| e |
| ); |
| } |
| finally |
| { |
| IOUtil.close ( writer ); |
| } |
| } |
| } |
| |
| private void processTemplates ( |
| String packageName, |
| File outputDirectoryFile, |
| Context context, |
| AbstractArchetypeDescriptor archetypeDescriptor, |
| List archetypeResources, |
| ZipFile archetypeZipFile, |
| String moduleOffset, |
| boolean failIfExists |
| ) |
| throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException |
| { |
| Iterator iterator = archetypeDescriptor.getFileSets ().iterator (); |
| if ( iterator.hasNext () ) |
| { |
| getLogger ().debug ( "Processing filesets" ); |
| } |
| while ( iterator.hasNext () ) |
| { |
| FileSet fileSet = (FileSet) iterator.next (); |
| |
| List fileSetResources = |
| archetypeFilesResolver.filterFiles ( moduleOffset, fileSet, archetypeResources ); |
| |
| if ( fileSet.isFiltered () ) |
| { |
| getLogger ().debug ( |
| "Processing fileset " + fileSet + "\n\n\n\n" + fileSetResources + "\n\n" |
| + archetypeResources + "\n\n" |
| ); |
| processFileSet ( |
| fileSet.getDirectory (), |
| fileSetResources, |
| fileSet.isPackaged (), |
| packageName, |
| context, |
| outputDirectoryFile, |
| moduleOffset, |
| getEncoding ( fileSet.getEncoding () ), |
| failIfExists |
| ); |
| getLogger ().debug ( "Processed " + fileSetResources.size () + " files" ); |
| } |
| else |
| { |
| getLogger ().debug ( "Copying fileset " + fileSet ); |
| copyFiles ( |
| fileSet.getDirectory (), |
| fileSetResources, |
| fileSet.isPackaged (), |
| packageName, |
| outputDirectoryFile, |
| archetypeZipFile, |
| moduleOffset, |
| failIfExists |
| ); |
| getLogger ().debug ( "Copied " + fileSetResources.size () + " files" ); |
| } |
| } // end while |
| } |
| |
| private void restoreParentArtifactId ( Context context, String parentArtifactId ) |
| { |
| if ( StringUtils.isEmpty ( parentArtifactId ) ) |
| { |
| context.remove ( Constants.PARENT_ARTIFACT_ID ); |
| } |
| else |
| { |
| context.put ( Constants.PARENT_ARTIFACT_ID, parentArtifactId ); |
| } |
| } |
| |
| private File getTemporaryFile ( File file ) |
| { |
| return FileUtils.getFile ( file.getAbsolutePath () + Constants.TMP ); |
| } |
| } |