package com.javaforge.bobber.plugin.archetype; /* * Copyright 2001-2005 The Apache Software Foundation. * * Licensed 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. */ import com.javaforge.bobber.archeytpe.model.io.xpp3.BobberArchetypeXpp3Reader; import com.javaforge.bobber.archeytpe.model.Variable; import com.javaforge.bobber.archeytpe.model.Template; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.maven.archetype.Archetype; import org.apache.maven.archetype.ArchetypeDescriptorException; import org.apache.maven.archetype.ArchetypeNotFoundException; import org.apache.maven.archetype.ArchetypeTemplateProcessingException; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.velocity.VelocityContext; import org.codehaus.plexus.logging.AbstractLogEnabled; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.codehaus.plexus.velocity.VelocityComponent; import org.apache.maven.settings.MavenSettingsBuilder; import org.codehaus.plexus.components.interactivity.InputHandler; //source blatantly copied from org.apache.maven.archetype.DefaultArchetype. Also stole code from DefaultPluginVersionManager.java //and maven-model for the mdo public class BobberArchetype extends AbstractLogEnabled implements Archetype { // ---------------------------------------------------------------------- // Components // ---------------------------------------------------------------------- /** * @component */ private VelocityComponent velocity; /** * @component */ private ArtifactResolver artifactResolver; /** * @component */ private InputHandler inputHandler; /** * @component */ private ArtifactFactory artifactFactory; /** * @component */ private MavenSettingsBuilder settingsBuilder; public void createArchetype( String archetypeGroupId, String archetypeArtifactId, String archetypeVersion, ArtifactRepository localRepository, List remoteRepositories, Map parameters ) throws ArchetypeNotFoundException, ArchetypeDescriptorException, ArchetypeTemplateProcessingException { // --------------------------------------------------------------------- //locate the archetype file // --------------------------------------------------------------------- Artifact archetypeArtifact = artifactFactory.createArtifact( archetypeGroupId, archetypeArtifactId, archetypeVersion, Artifact.SCOPE_RUNTIME, "jar" ); try { artifactResolver.resolve( archetypeArtifact, remoteRepositories, localRepository ); } catch ( ArtifactResolutionException e ) { throw new ArchetypeDescriptorException( "Error attempting to download archetype: " + e.getMessage(), e ); } // ---------------------------------------------------------------------- // Load the archetype descriptor // ---------------------------------------------------------------------- BobberArchetypeXpp3Reader builder = new BobberArchetypeXpp3Reader(); com.javaforge.bobber.archeytpe.model.BobberArchetype archetype; JarFile archetypeJarFile; try { archetypeJarFile = new JarFile(archetypeArtifact.getFile()); InputStream is = archetypeJarFile.getInputStream(archetypeJarFile.getEntry(ARCHETYPE_DESCRIPTOR)); if ( is == null ) { throw new ArchetypeDescriptorException( "The " + ARCHETYPE_DESCRIPTOR + " descriptor cannot be found." ); } archetype = builder.read( new InputStreamReader( is ) ); archetypeJarFile.close(); } catch ( IOException e ) { throw new ArchetypeDescriptorException( "Error reading the " + ARCHETYPE_DESCRIPTOR + " descriptor.", e ); } catch ( XmlPullParserException e ) { throw new ArchetypeDescriptorException( "Error reading the " + ARCHETYPE_DESCRIPTOR + " descriptor.", e ); } // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- String basedir = (String) parameters.get( "basedir" ); String artifactId = (String) parameters.get( "artifactId" ); File pomFile = new File( basedir, ARCHETYPE_POM ); File outputDirectoryFile; if ( pomFile.exists() && archetype.isAllowPartial() ) { outputDirectoryFile = new File( basedir ); } else { outputDirectoryFile = new File( basedir, artifactId ); if ( outputDirectoryFile.exists() ) { throw new ArchetypeTemplateProcessingException( outputDirectoryFile.getName() + " already exists - please run from a clean directory" ); } outputDirectoryFile.mkdir(); } String outputDirectory = outputDirectoryFile.getAbsolutePath(); // ---------------------------------------------------------------------- // Set up the Velocity context // ---------------------------------------------------------------------- VelocityContext context = new VelocityContext(); String packageName = (String) parameters.get( "package" ); context.put( "package", packageName ); context.put( "packagePath", StringUtils.replace(packageName,".","/" )); for ( Iterator iterator = parameters.keySet().iterator(); iterator.hasNext(); ) { String key = (String) iterator.next(); Object value = parameters.get( key ); context.put( key, value ); } //add in the specified system properties //if this were a mojo could have set the settings using the ${settings} expression. Since it is not need to get it from the settings builder boolean inInteractiveMode = false ; try{ inInteractiveMode = settingsBuilder.buildSettings().getInteractiveMode().booleanValue(); }catch (Exception ie){ throw new ArchetypeTemplateProcessingException("unable to read settings ",ie); } if (inInteractiveMode){ getLogger().info( "Please enter the values for the following archetype variables:" ); } for ( Iterator iterator = archetype.getVariables().iterator(); iterator.hasNext(); ) { Variable var = (Variable) iterator.next(); String val = System.getProperty(var.getName(),var.getDefvalue()); if (inInteractiveMode){ StringBuffer message = new StringBuffer(); message.append(var.getName()).append(": ").append(var.getDescription()).append(" [").append(val).append("] >"); getLogger().info(message.toString()); try{ String answer = inputHandler.readLine(); if ( !StringUtils.isEmpty( answer ) ){ val = answer; } }catch (IOException ie){ throw new ArchetypeTemplateProcessingException(ie); } } context.put( var.getName(), val ); } // --------------------------------------------------------------------- // Get Logger and display all parameters used // --------------------------------------------------------------------- if ( getLogger().isInfoEnabled() ) { Object [] keys = context.getKeys(); if ( keys.length >0 ) { getLogger().info( "----------------------------------------------------------------------------" ); getLogger().info( "Using following parameters for creating Archetype: " + archetypeArtifactId + ":" + archetypeVersion ); getLogger().info( "----------------------------------------------------------------------------" ); for (int i = 0; i< keys.length; i++){ String parameterName = (String)keys[i]; Object parameterValue = context.get( parameterName ); getLogger().info( "Parameter: " + parameterName + ", Value: " + parameterValue ); } } else { getLogger().info( "No Parameters found for creating Archetype" ); } } // ---------------------------------------------------------------------- // Extract the archetype to the chosen directory // ---------------------------------------------------------------------- try { archetypeJarFile = new JarFile(archetypeArtifact.getFile()); Enumeration entries = archetypeJarFile.entries(); while(entries.hasMoreElements()) { JarEntry entry = (JarEntry)entries.nextElement(); String path = entry.getName(); if (!path.startsWith(ARCHETYPE_RESOURCES ) || path.endsWith(".vm")){ continue; } File t = new File(outputDirectory, path.substring(19)); if(entry.isDirectory()) { // Assume directories are stored parents first then children. getLogger().debug("Extracting directory: " + entry.getName() + " to " + t.getAbsolutePath()); t.mkdir(); continue; } getLogger().debug("Extracting file: " + entry.getName() + " to " + t.getAbsolutePath()); t.createNewFile(); IOUtil.copy(archetypeJarFile.getInputStream(entry),new FileOutputStream(t)); } archetypeJarFile.close(); //remove the archetype descriptor File t = new File(outputDirectory, ARCHETYPE_DESCRIPTOR); t.delete(); } catch (IOException ioe) { throw new ArchetypeTemplateProcessingException("Error extracting archetype",ioe); } // ---------------------------------------------------------------------- // Process the templates // ---------------------------------------------------------------------- // use the out of the box codehaus velocity component that loads templates //from the class path ClassLoader old = Thread.currentThread().getContextClassLoader(); try { URL[] urls = new URL[1]; urls[0] = archetypeArtifact.getFile().toURI().toURL(); URLClassLoader archetypeJarLoader = new URLClassLoader( urls ); Thread.currentThread().setContextClassLoader( archetypeJarLoader ); for (Iterator i = archetype.getTemplates().iterator(); i.hasNext();){ Template template = (Template)i.next(); processTemplate(template,outputDirectory, context ); } } catch (MalformedURLException mfe){ throw new ArchetypeTemplateProcessingException("Error loading archetype resources into the classpath",mfe); } finally { Thread.currentThread().setContextClassLoader( old ); } // ---------------------------------------------------------------------- // Log message on Archetype creation // ---------------------------------------------------------------------- if ( getLogger().isInfoEnabled() ) { getLogger().info( "Archetype created in dir: " + outputDirectory ); } } protected void processTemplate( Template template, String outputDirectory, VelocityContext context ) throws ArchetypeTemplateProcessingException { File outFile; try{ StringWriter wout = new StringWriter(); velocity.getEngine().evaluate( context, wout, "output value", template.getOutput()); outFile = new File(outputDirectory,wout.toString()); getLogger().debug(outFile.getAbsolutePath()); FileUtils.forceMkdir(outFile.getParentFile()); } catch (Exception e){ throw new ArchetypeTemplateProcessingException("error evaluating output file name " + template.getOutput(), e); } Writer writer = null; try { writer = new FileWriter( outFile ); String templateLocation = ARCHETYPE_RESOURCES + "/" + template.getFile(); velocity.getEngine().mergeTemplate( templateLocation, context, writer ); writer.flush(); } catch ( Exception e ) { throw new ArchetypeTemplateProcessingException( "Error merging velocity templates", e ); } finally { IOUtil.close( writer ); } } public static void main (String [] args){ try { BobberArchetypeXpp3Reader builder = new BobberArchetypeXpp3Reader(); com.javaforge.bobber.archeytpe.model.BobberArchetype archetype = builder.read( new InputStreamReader(new FileInputStream("C:\\dev\\cpsg\\bobber\\archetypes\\jbi-component\\src\\main\\resources\\META-INF\\archetype.xml") ) ); System.out.println(archetype.getVariables()); } catch ( Exception e ) { e.printStackTrace(); } } }