net.sourceforge.vulcan.maven.MavenBuildPlugin.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.vulcan.maven.MavenBuildPlugin.java

Source

/*
 * Vulcan Build Manager
 * Copyright (C) 2005-2012 Chris Eldredge
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package net.sourceforge.vulcan.maven;

import static net.sourceforge.vulcan.ant.AntBuildPlugin.addSystemJavaHomeIfMissing;
import static org.apache.commons.lang.StringUtils.isNotBlank;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import net.sourceforge.vulcan.BuildTool;
import net.sourceforge.vulcan.ant.JavaHome;
import net.sourceforge.vulcan.dto.BuildToolConfigDto;
import net.sourceforge.vulcan.dto.PluginConfigDto;
import net.sourceforge.vulcan.exception.ConfigException;
import net.sourceforge.vulcan.integration.BuildToolPlugin;
import net.sourceforge.vulcan.integration.ConfigurablePlugin;
import net.sourceforge.vulcan.integration.support.PluginSupport;
import net.sourceforge.vulcan.maven.integration.MavenIntegration;

import org.apache.commons.io.FileUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MavenBuildPlugin extends PluginSupport
        implements BuildToolPlugin, ConfigurablePlugin, ApplicationContextAware {

    public static final String PLUGIN_ID = "net.sourceforge.vulcan.maven";
    public static final String PLUGIN_NAME = "Apache Maven";

    public static final String M2_POM_NS = "http://maven.apache.org/POM/4.0.0";

    MavenConfig config = new MavenConfig();
    MavenBuildToolFactory mavenBuildToolFactory = new MavenBuildToolFactory();

    MavenProjectConfiguratorFactory configuratorFactory;

    String maven2HomeDirectory;
    String maven2ProfileName;
    String defaultGoals;

    ApplicationContext applicationContext;

    public void init() {
        addSystemJavaHomeIfMissing(config, applicationContext);
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public String getId() {
        return PLUGIN_ID;
    }

    public String getName() {
        return PLUGIN_NAME;
    }

    public BuildTool createInstance(BuildToolConfigDto projectConfig) throws ConfigException {
        final MavenProjectConfig mavenProjectConfig = (MavenProjectConfig) projectConfig;

        final String javaHomeName = mavenProjectConfig.getJavaHome();
        final JavaHome javaHome;

        if (isNotBlank(javaHomeName) && javaHomeName.startsWith("System")) {
            javaHome = getSelectedEnvironment(this.config.getJavaHomes(), "System", null, true);
        } else {
            javaHome = getSelectedEnvironment(this.config.getJavaHomes(), javaHomeName, "ant.java.profile.missing");
        }

        final MavenHome mavenHome = getSelectedEnvironment(this.config.getMavenHomes(),
                mavenProjectConfig.getMavenHome(), "maven.home.profile.missing");

        return mavenBuildToolFactory.createMavenBuildTool(mavenProjectConfig, config, javaHome, mavenHome);
    }

    public MavenProjectBuildConfigurator createProjectConfigurator(String url, File buildSpecFile,
            Document xmlDocument) throws ConfigException {
        if (xmlDocument == null) {
            return null;
        }

        final Element rootNode = xmlDocument.getRootElement();
        if (!M2_POM_NS.equals(rootNode.getNamespace().getURI())) {
            final Element modelVersionNode = rootNode.getChild("modelVersion");
            if (modelVersionNode == null || !"4.0.0".equals(modelVersionNode.getText())) {
                return null;
            }
        }

        if (configuratorFactory == null) {
            createConfigurationFactory();
        }

        return configuratorFactory.createProjectConfigurator(buildSpecFile, maven2ProfileName, defaultGoals,
                applicationContext);
    }

    public MavenProjectConfig getDefaultConfig() {
        return new MavenProjectConfig();
    }

    public void setDefaultGoals(String defaultGoals) {
        this.defaultGoals = defaultGoals;
    }

    public MavenConfig getConfiguration() {
        return config;
    }

    public void setConfiguration(PluginConfigDto config) {
        this.config = (MavenConfig) config;
        addSystemJavaHomeIfMissing(this.config, applicationContext);
    }

    void createConfigurationFactory() throws ConfigException {
        // find maven2 home
        for (MavenHome home : config.getMavenHomes()) {
            if (MavenBuildTool.isMaven2(home.getDirectory())) {
                maven2HomeDirectory = home.getDirectory();
                maven2ProfileName = home.getDescription();
                break;
            }
        }

        if (maven2HomeDirectory == null) {
            throw new ConfigException("maven.maven2.required", null);
        }

        // create classloader
        final URLClassLoader classLoader = new PackageFilteringClassLoader(createURLs(maven2HomeDirectory),
                getClass().getClassLoader(), MavenIntegration.class.getPackage().getName());

        // load integration provider
        try {
            configuratorFactory = (MavenProjectConfiguratorFactory) classLoader
                    .loadClass(MavenIntegration.class.getName()).newInstance();
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            }
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    static URL[] createURLs(String mavenHomeDirectory) throws ConfigException {
        final String[] extensions = new String[] { "jar" };

        try {
            final List<File> files = new ArrayList<File>();

            files.addAll(FileUtils.listFiles(new File(mavenHomeDirectory), extensions, true));

            final URL[] urls = new URL[files.size() + 1];

            for (int i = 0; i < files.size(); i++) {
                urls[i] = files.get(i).toURI().toURL();
            }

            urls[urls.length - 1] = MavenBuildTool.getLocalClassPathEntry(MavenBuildPlugin.class, null).toURI()
                    .toURL();

            return urls;
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * ClassLoader forces classes in a specified package (or sub-package)to be loaded
     * by this instance instead of delegating to the parent first.  This allows classes
     * in the integration package to be loaded by the same instance that has the jars
     * in the Maven 2 home.  This is required to avoid packaging all of those jars, which
     * would increase the size of this plugin by nearly 2 megabytes.
     */
    static class PackageFilteringClassLoader extends URLClassLoader {
        private final String packageName;

        public PackageFilteringClassLoader(URL[] urls, ClassLoader parent, String packageName) {
            super(urls, parent);
            this.packageName = packageName;
        }

        @Override
        protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
            if (!name.startsWith(packageName)) {
                return super.loadClass(name, resolve);
            }

            // Against standard practice, do NOT delegate to parent first:

            Class<?> c = findLoadedClass(name);
            if (c == null) {
                c = findClass(name);
            }

            if (resolve) {
                resolveClass(c);
            }

            return c;
        }
    }
}