org.wso2.maven.AbstractMavenReleaseMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.maven.AbstractMavenReleaseMojo.java

Source

/*
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.
*/
package org.wso2.maven;

import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.BuildPluginManager;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.io.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;

import static org.twdata.maven.mojoexecutor.MojoExecutor.*;

/**
 * Abstract Mojo for wso2 maven release plugin.
 */
public abstract class AbstractMavenReleaseMojo extends AbstractMojo {

    /**
      * String constants
      */
    protected static final String ARTIFACT_XML = "artifact.xml";
    protected static final String ARTIFACT_XML_REGEX = "**/artifact.xml";
    protected static final String EMPTY_STRING = "";
    protected static final String POM_XML = "pom.xml";
    protected static final String PROJECT_PREFIX = "project.";
    protected static final String RELEASE_PROPERTIES = "release.properties";
    protected static final String WSO2_RELEASE_PLUGIN_PREFIX = "[wso2-release-plugin]";
    protected static final String ARTIFACT = "artifact";
    protected static final String VERSION = "version";

    /**
     * maven scm plugin meta data
     */
    protected static final String MAVEN_PLUGINS_GROUP = "org.apache.maven.plugins";
    protected static final String MAVEN_SCM_PLUGIN = "maven-scm-plugin";
    protected static final String SCM_PLUGIN_VERSION = "1.9.4";
    protected static final String GOAL_CHECK_IN = "checkin";

    /**
     * maven scm plugin params
     */
    protected static final String PARAMETER_BASEDIR = "basedir";
    protected static final String PARAMETER_MESSAGE = "message";
    protected static final String PARAM_INCLUDES = "includes";
    protected static final String PARAM_USERNAME = "username";
    protected static final String PARAM_PASSWORD = "password";

    /**
     * release plugin scm properties
     */
    protected static final String PROP_SCM_TAG = "scm.tag";
    protected static final String PROP_SCM_USERNAME = "scm.username";
    protected static final String PROP_SCM_PASSWORD = "scm.password";

    /**
      * The project currently being build.
      *
      * @parameter expression="${project}"
      * @required
      */
    protected MavenProject mavenProject;

    /**
     * The current Mjava.lang.Stringaven session.
     *
     * @parameter expression="${session}"
     * @required
     */
    protected MavenSession mavenSession;

    /**
     * The Maven BuildPluginManager component.
     *
     * @component
     * @required
     */
    protected BuildPluginManager pluginManager;

    /**
     * Properties loaded from release.properties file.
     */
    protected Properties releaseProperties;

    /**
     * Logger for mojo.
     */
    protected final Log log = getLog();

    /**
     * Method to indicate current goal.
     *
     * @return Current Goal.
     */
    protected abstract String getGoal();

    /**
     * Method to retrieve the file prefix to be used in dryRunMode of current goal.
     *
     * @return File prefix for dryRunMode.
     */
    protected abstract String getDryRunFilePrefix();

    /**
     * Method to get the customised commit message for each goal.
     *
     * @param releaseProperties Properties generated by maven release plugin.
     * @return Commit message for current goal.
     */
    protected abstract String getCommitMessage(Properties releaseProperties);

    /**
     * Method to get the new version for the artifacts. Implementation depends on
     * the goals(prepare-release, prepare-snapshots and rollback).
     *
     * @param artifactXml artifact.xml file of the project.
     * @return new version.
     * @throws IOException
     * @throws XmlPullParserException
     */
    protected abstract String getNewVersion(File artifactXml) throws IOException, XmlPullParserException;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {

        File parentProjectBaseDir = mavenProject.getBasedir();
        File releasePropertiesFile = new File(parentProjectBaseDir, RELEASE_PROPERTIES);
        releaseProperties = new Properties();

        // execute only for the project in repository root.
        if (releasePropertiesFile.exists()) {
            try {
                InputStream inputStream = new FileInputStream(releasePropertiesFile);
                releaseProperties.load(inputStream);
            } catch (IOException e) {
                String errorMessage = "Error while reading " + RELEASE_PROPERTIES;
                throw new MojoExecutionException(errorMessage, e);
            }
            // iterate recursively and filter out files named artifact.xml
            Collection<File> artifactXMLFiles = FileUtils.listFiles(parentProjectBaseDir, new ArtifactXMLFilter(),
                    TrueFileFilter.INSTANCE);
            for (File artifactXML : artifactXMLFiles) {

                File projectPath = new File(artifactXML.getPath().replaceAll(ARTIFACT_XML + "$", EMPTY_STRING));
                File pomFile = new File(projectPath, POM_XML);
                // if not a maven project, continue.
                if (!pomFile.exists()) {
                    log.warn("Skipping project since " + artifactXML.getPath()
                            + " does not belong to a maven project.");
                    continue;
                }
                try {
                    // getNewVersion() depends on current goal.
                    // Eg: for prepare-release, it should be the releasing version
                    //     for prepare-snapshot, it should be the next development version
                    //     for rollback, it should be the previous development version
                    String newVersion = getNewVersion(artifactXML);
                    if (StringUtils.isNotEmpty(newVersion)) {
                        updateArtifactVersions(artifactXML, newVersion);
                    } else {
                        String errorMessage = "Cannot update artifact.xml as new version is empty/null. "
                                + "Project: " + pomFile.getPath() + " Goal: " + getGoal();
                        throw new MojoFailureException(errorMessage);
                    }
                } catch (IOException | XmlPullParserException e) {
                    String errorMessage = "Error occurred while getting the new version for artifacts."
                            + " Project: " + pomFile.getPath() + " Goal: " + getGoal();
                    throw new MojoFailureException(errorMessage, e);
                } catch (Exception e) {
                    String errorMessage = "Error occurred while updating artifact versions. Project: "
                            + pomFile.getPath() + " Goal: " + getGoal();
                    throw new MojoFailureException(errorMessage, e);
                }
            }
            // commit changes only if not running in dryRun mode
            if (isInDryRunMode()) {
                log.info("Skipped committing changes in dryRun mode.");
            } else {
                try {
                    executeMojo(
                            plugin(groupId(MAVEN_PLUGINS_GROUP), artifactId(MAVEN_SCM_PLUGIN),
                                    version(SCM_PLUGIN_VERSION)),
                            goal(GOAL_CHECK_IN), configuration(getScmPluginProperties(parentProjectBaseDir)),
                            executionEnvironment(mavenProject, mavenSession, pluginManager));
                } catch (MojoExecutionException e) {
                    throw new MojoExecutionException("Error occurred while invoking maven scm plug-in.", e);
                }
            }
        } else {
            log.debug("Skipping project since the " + RELEASE_PROPERTIES + " file was not found in project root.");
        }
    }

    /**
     * Update versions in the given artifact.xml file of a ESB/DSS project.
     *
     * @param artifactXml artifact.xml file of a ESB/DSS project.
     * @param newVersion  new version to which, the artifacts should be updated.
     * @throws Exception
     */
    protected void updateArtifactVersions(File artifactXml, String newVersion) throws Exception {
        InputStream inputStream = new FileInputStream(artifactXml);
        XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
        StAXOMBuilder builder = new StAXOMBuilder(xmlStreamReader);
        OMElement documentElement = builder.getDocumentElement();
        Iterator artifacts = documentElement.getChildrenWithName(new QName(ARTIFACT));
        while (artifacts.hasNext()) {
            OMElement artifact = (OMElement) artifacts.next();
            OMAttribute version = artifact.getAttribute(new QName(VERSION));
            if (version != null) {
                version.setAttributeValue(newVersion);
            }
        }
        if (isInDryRunMode()) {
            artifactXml = new File(artifactXml.getPath() + getDryRunFilePrefix());
        }
        FileOutputStream outputStream = new FileOutputStream(artifactXml);
        XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(outputStream);
        builder.getDocument().serialize(xmlStreamWriter);
        inputStream.close();
        xmlStreamReader.close();
        outputStream.close();
        xmlStreamWriter.close();
    }

    /**
     * Method to check  whether release plugin is running in dryRunMode.
     *
     * @return true, if running in dryRun mode.
     */
    protected boolean isInDryRunMode() {
        File projectBaseDir = mavenProject.getBasedir();
        File dryRunPomFile = new File(projectBaseDir, POM_XML + getDryRunFilePrefix());
        return dryRunPomFile.exists();
    }

    /**
     * Method to generate configuration for maven scm plugin.
     *
     * @param parentProjectBaseDir root of the repository.
     * @return configuration for maven scm plugin.
     */
    protected Element[] getScmPluginProperties(File parentProjectBaseDir) {

        // if username is available in release.properties file, scm credentials are passed
        // via console args. Hence we need to forward them to scm plugin also.
        // if username is not available, credentials may configured in settings.xml file and we can avoid passing
        // them as args to scm plugin
        if (releaseProperties.containsKey(PROP_SCM_USERNAME)) {
            log.debug("SCM credentials are found in release.properties file.");
            return new Element[] { element(name(PARAMETER_BASEDIR), parentProjectBaseDir.getAbsolutePath()),
                    element(name(PARAMETER_MESSAGE),
                            WSO2_RELEASE_PLUGIN_PREFIX + " " + getCommitMessage(releaseProperties).trim()),
                    element(name(PARAM_INCLUDES), ARTIFACT_XML_REGEX),
                    element(name(PARAM_USERNAME), releaseProperties.getProperty(PROP_SCM_USERNAME)),
                    element(name(PARAM_PASSWORD), releaseProperties.getProperty(PROP_SCM_PASSWORD)) };

        } else {
            log.debug("SCM credentials are not found in release.properties file.");
            return new Element[] { element(name(PARAMETER_BASEDIR), parentProjectBaseDir.getAbsolutePath()),
                    element(name(PARAMETER_MESSAGE),
                            WSO2_RELEASE_PLUGIN_PREFIX + " " + getCommitMessage(releaseProperties).trim()),
                    element(name(PARAM_INCLUDES), ARTIFACT_XML_REGEX) };
        }
    }

    /**
     * Method to instantiate a Maven project model from a pom file.
     *
     * @param pomFile Path to pom file.
     * @return Project model
     * @throws IOException
     * @throws org.codehaus.plexus.util.xml.pull.XmlPullParserException
     */
    protected MavenProject getMavenProject(final File pomFile) throws IOException, XmlPullParserException {
        MavenXpp3Reader xpp3Reader = new MavenXpp3Reader();
        FileReader reader = new FileReader(pomFile);
        Model model = xpp3Reader.read(reader);
        return new MavenProject(model);
    }

    /**
     * Filter for artifact.xml files.
     */
    class ArtifactXMLFilter implements IOFileFilter {
        @Override
        public boolean accept(File file) {
            if (file.getPath().endsWith(ARTIFACT_XML)) {
                return true;
            }
            return false;
        }

        @Override
        public boolean accept(File file, String name) {
            if (name.endsWith(ARTIFACT_XML)) {
                return true;
            }
            return false;
        }
    }
}