Package com.javaforge.bobber.plugin.archetype

Source Code of com.javaforge.bobber.plugin.archetype.BobberArchetype

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.archetype.model.Template;
import com.javaforge.bobber.archetype.model.Variable;
import com.javaforge.bobber.archetype.model.io.xpp3.BobberArchetypeXpp3Reader;

import java.io.File;
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.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

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.maven.settings.MavenSettingsBuilder;
import org.apache.velocity.VelocityContext;
import org.codehaus.plexus.components.interactivity.InputHandler;
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;

//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 {

    private static final String NEW_LINE = System.getProperty("line.separator");

    // ----------------------------------------------------------------------
    // Components
    // ----------------------------------------------------------------------

    /**
     * @component
     */
    private VelocityComponent velocity;

    /**
     * @component
     */
    private ArtifactResolver artifactResolver;

    /**
     * @component
     */
    private InputHandler inputHandler;

    /**
     * @component
     */
    private ArtifactFactory artifactFactory;


    /**
     * @component
     */
    private MavenSettingsBuilder settingsBuilder;
    private static final int MESSAGE_LINE_LENGTH = 80;


    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.archetype.model.BobberArchetype archetype;

        JarFile archetypeJarFile;

        try {

            archetypeJarFile = new JarFile(archetypeArtifact.getFile());

            final ZipEntry zipEntry = archetypeJarFile.getEntry(ARCHETYPE_DESCRIPTOR);
            InputStream is = archetypeJarFile.getInputStream(zipEntry);

            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);

            // TODO temporarily allow partial generation, remove it later
            if (!archetype.isAllowPartial() &&
                    outputDirectoryFile.exists() &&
                    outputDirectoryFile.listFiles().length > 0) {
                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:");
        }


        final List variables = archetype.getVariables();
        processVariables(variables.iterator(), context, inInteractiveMode);


        // ---------------------------------------------------------------------
        // 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 + " = " + 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();) {
                final Template template = (Template) i.next();

                // Check the optional 'condition' property on the template.
                // If present and the variable it points to is 'true', then
                // continue processing. If it's false, then skip.
                // If condition is not specified, assume the template should
                // be processed.
                boolean shouldProcess = true;
                String condition = template.getDependsOnVar();
                String requiredValue=null;
                List options = new ArrayList();
                if (StringUtils.isNotEmpty(condition)) {
                    //Crappy logic processing -- for now
                    boolean not=false;
                    //Allow very simple matching logic to match templates against variable values
                    int x = condition.indexOf("!=");
                    getLogger().debug("Processing Condition : " + condition);                                       
                    if(x > -1) {
                        not=true;
                        requiredValue = condition.substring(x+2).trim();
                        options = getListOfValues(requiredValue);
                        condition = condition.substring(0, x).trim();
                    }
                    else {
                        x = condition.indexOf("=");
                        if(x > -1) {
                            requiredValue = condition.substring(x+1);
                            options = getListOfValues(requiredValue);
                            condition = condition.substring(0, x);
                        }
                    }
                    getLogger().debug("Not Expr: " + not);
                    getLogger().debug("Condition Value: '" + condition + "'");
                    getLogger().debug("Required Value: '" + requiredValue + "'");
                    final Variable var = (Variable) findVariable(condition, variables);
                    if (var != null) {
                        final String strValue = (String) context.get(var.getName());
                        getLogger().debug("Variable Value is: '" + strValue + "'");
                        if(requiredValue==null)
                        {
                            if (!Boolean.valueOf(strValue).booleanValue()) {
                                shouldProcess = false;
                            }
                        } else {
                            if(!options.contains(strValue))
                            {
                                shouldProcess = false;
                            }
                        }

                    } else {
                        getLogger().debug("Variable Value is: null");                                               
                        shouldProcess=false;
                    }
                    if(not) {
                        shouldProcess = !shouldProcess;
                    }
                }

                if (shouldProcess) {
                    processTemplate(template, outputDirectory, context);
                } else {
                    getLogger().debug("Condition not met, skipping " + template.getOutput());
                }
            }

        }
        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 processVariables(Iterator variables, VelocityContext context, final boolean interactiveMode) throws ArchetypeTemplateProcessingException
    {
        while (variables.hasNext()) {
            Variable var = (Variable) variables.next();
            String val = System.getProperty(var.getName(), var.getDefvalue());

            if (interactiveMode) {

                    StringBuffer message = new StringBuffer();
                    message.append(var.getName()).append(": ")
                            .append(NEW_LINE)
                            .append(StringUtils.repeat("*", MESSAGE_LINE_LENGTH))
                            .append(NEW_LINE)
                            .append(NEW_LINE)
                            .append(StringUtils.center(var.getDescription(), MESSAGE_LINE_LENGTH))
                            .append(NEW_LINE)
                            .append(StringUtils.leftPad("[default: " + val + "]", MESSAGE_LINE_LENGTH))
                            .append(NEW_LINE)
                            .append(StringUtils.repeat("*", MESSAGE_LINE_LENGTH));
                    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);
            }
            else
            {
                context.put(var.getName(), val);
            }

            if(val.toLowerCase().equals("false") || val.toLowerCase().equals("n"))
            {
                if(var.getVariables() !=null)
                {
                    //keep processing the variables picking up the default values
                    processVariables(var.getVariables().iterator(), context, false);

                }
            } else if(var.getVariables() !=null)
            {
                //keep processing the variables picking up the default values
                processVariables(var.getVariables().iterator(), context, true);

            }
        }

    }

    protected List getListOfValues(String s) {
        List options = new ArrayList();
        for (StringTokenizer stringTokenizer = new StringTokenizer(s, "|"); stringTokenizer.hasMoreTokens();)
        {
            options.add(stringTokenizer.nextToken());
        }
        return options;
    }

    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());
            getLogger().debug("Created directory: " + outFile.getParentFile() + ", Dir exists = " + outFile.getParentFile().exists());

        } catch (Exception e) {
            e.printStackTrace();
            throw new ArchetypeTemplateProcessingException("error evaluating output file name " + template.getOutput(), e);
        }


        Writer writer = null;
        try {
            getLogger().info("Processing Template: " + template.getFile());
            String templateLocation = ARCHETYPE_RESOURCES + "/" + template.getFile();

            writer = new FileWriter(outFile);
            velocity.getEngine().mergeTemplate(templateLocation, context, writer);
            writer.flush();

        } catch (Exception e) {
            throw new ArchetypeTemplateProcessingException("Error merging velocity templates", e);
        } finally {
            IOUtil.close(writer);
            getLogger().info("Written Template to: " + outFile + ", file exists = " + outFile.exists());
        }

        // Delete archetype-originated folders in case the output path is also templated.
        // Otherwise, there will be a processed folder AND the original folder.
        try {
            final File templateFile = new File(outputDirectory, template.getFile());
            final String templateDir = FileUtils.dirname(templateFile.getCanonicalPath());
            final String outputDir = FileUtils.dirname(outFile.getCanonicalPath());
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("TemplateDir=" + templateDir);
                getLogger().debug("OutputDir=" + outputDir);
            }
            if (!outputDir.startsWith(templateDir)) {
                getLogger().debug("Deleting Template Dir:" + templateDir);
                FileUtils.forceDelete(templateDir);
            }
        } catch (IOException e) {
            throw new ArchetypeTemplateProcessingException("Failed to cleanup the working dir.", e);
        }
    }


    /**
     * Find the  variable.
     * @param variableName name
     * @param variables all variables of the artifact
     * @return variable value or null of not found
     */
    protected Object findVariable (String variableName, List variables) {

        for (int i = 0; i < variables.size(); i++) {
            Variable var = (Variable) variables.get(i);
            if (variableName.equals(var.getName())) {
                return var;
            } else if(var.getVariables()!=null) {
                Object o = findVariable(variableName, var.getVariables());
                if(o!=null) {
                    return o;
                }
            }
        }

        return null;
    }

}



TOP

Related Classes of com.javaforge.bobber.plugin.archetype.BobberArchetype

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.