org.codehaus.mojo.setup.AbstractSetupMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.mojo.setup.AbstractSetupMojo.java

Source

package org.codehaus.mojo.setup;

/*
 * 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.
 */

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.List;

import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.RuntimeInformation;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.mojo.setup.SetupExecutionRequest.MergeType;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;

/**
 * Abstract Mojo for all setup goals
 * 
 * @requiresProject false
 * @author Robert Scholte
 * @since 1.0.0
 */
public abstract class AbstractSetupMojo extends AbstractMojo implements Contextualizable, Initializable {

    // set during contextualization 
    /**
     * RuntimeInformation to discover the Maven version
     */
    private RuntimeInformation rti;

    /**
     * @parameter expression="${session}"
     * @readonly
     * @required
     */
    private MavenSession session;

    /**
     * Base directory of the project.
     * 
     * @parameter expression="${basedir}" //never project.basedir, because pom is not required
     * @readonly
     */
    private File baseDirectory;

    /**
     * Location of the settingstemplate, can be an URL, a relative or absolute path to the file
     * 
     * @parameter alias="templateFile" expression="${templateFile}"
     */
    private String templateFilename;

    /**
     * Define how to merge. Valid values are: none, update, expand and overwrite No default value, so we can detect if
     * it is set by commandline
     * 
     * @parameter expression="${merge}"
     */
    private String merge;

    /**
     * With dryRun the execution will run as normal, but the target-file won't change.
     * Instead a folder will be created with the same name as the directory-name containing the target file.
     * Although there will be a backup-file, this way you can check the result before really changing the file.  
     * 
     * @parameter expression="${dryRun}"
     * 
     */
    private boolean dryRun = false;

    /**
     * Setup execution request to use for the setup manager 
     */
    private SetupExecutionRequest setupRequest = new DefaultSetupExecutionRequest();

    /**
     * {@inheritDoc}
     * @since 1.0.0
     */
    public void contextualize(Context context) throws ContextException {
        PlexusContainer container = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY);
        try {
            rti = (RuntimeInformation) container.lookup(RuntimeInformation.class.getName());
        } catch (ComponentLookupException e) {
            getLog().info("Could not retrieve RuntimeInformation to check maven version.");
        }
    }

    /**
     * {@inheritDoc}
     * @since 1.0.0
     */
    @Override
    public void initialize() throws InitializationException {
        try {
            if (!isRequiredMavenVersion(getMavenVersionRange())) {
                throw new InitializationException(
                        "\nThis goal is not supported. You're using Maven " + rti.getApplicationVersion()
                                + ", it must be within this range: " + getMavenVersionRange().toString());
            }
        } catch (InvalidVersionSpecificationException e) {
            throw new InitializationException(e.getMessage());
        }
    }

    // protected getters for subclasses
    /**
     * @return the MavenSession
     * @since 1.0.0
     */
    protected MavenSession getSession() {
        return session;
    }

    /**
     * 
     * @return the baseDirectory as File
     * @since 1.0.0
     */
    protected File getBaseDirectory() {
        return baseDirectory;
    }

    /**
     * 
     * @return the template filename
     * @since 1.0.0
     */
    protected String getTemplateFilename() {
        return templateFilename;
    }

    /**
     * 
     * @return the setup request
     * @since 1.0.0
     */
    protected SetupExecutionRequest getSetupRequest() {
        return setupRequest;
    }

    // protected abstract getters, which subclasses must provide

    /**
     * @return the default-template filename
     * @since 1.0.0
     */
    protected abstract String getDefaultTemplateFilename();

    /**
     * 
     * @return the properties filename
     * @since 1.0.0
     */
    protected abstract String getPropertiesFilename();

    /**
     * 
     * @return the setup manager
     * @since 1.0.0
     */
    protected abstract SetupManager getSetupManager();

    // helper methods

    /**
     * Exceptionless method to check is the value is a valid URL
     * 
     * @param value the potential URL
     * @return true is it's a URL, otherwise false
     */
    private boolean isUrl(String value) {
        boolean result = true;

        try {
            new URL(value);
        } catch (MalformedURLException e) {
            result = false;
        }

        return result;
    }

    /**
     * The prototype is an (xml)-file which contains comments on the tags to use.
     * 
     * @return the prototype as InputStream, since it may be part of a jar
     * @throws IOException if input stream can't be resolved
     * @since 1.0.0
     */
    protected InputStream getPrototypeInputStream() throws IOException {
        return getSetupManager().getPrototypeInputStream();
    }

    /**
     * Get the templatefile, either a custom or the default template file
     * 
     * @return resolved templateFile or null
     * @since 1.0.0
     */
    protected File resolveTemplateFile() {
        File result = null;

        if (StringUtils.isNotEmpty(getTemplateFilename())) {
            if (isUrl(getTemplateFilename())) {
                try {
                    result = FileUtils.toFile(new URL(getTemplateFilename()));
                } catch (MalformedURLException e) {
                    // nop
                }
            } else {
                result = FileUtils.resolveFile(getBaseDirectory(), getTemplateFilename());
            }
        } else {
            File templateFile = new File(getBaseDirectory(), getDefaultTemplateFilename());

            if (templateFile.exists()) {
                result = templateFile;

                if (getLog().isDebugEnabled()) {
                    getLog().debug("using " + templateFile);
                }
            }
        }

        return result;
    }

    /**
     * {@inheritDoc}
     * @since 1.0.0
     */
    public void execute() throws MojoExecutionException, MojoFailureException {
        preProcess();
        try {
            File settingsTemplate = resolveTemplateFile();

            if (settingsTemplate != null || !getSetupRequest().getAdditionalProperties().isEmpty()) {
                // Using merge as String, because translation to MergeType requires a switch/case or a valueOf(), which
                // might break;
                getSetupRequest().setSession(getSession()).setTemplateFile(resolveTemplateFile())
                        .setPropertyFilenames(getPropertyFiles()).setDryRun(dryRun);

                if (merge != null) {
                    getSetupRequest().setMergeType(MergeType.valueOf(merge.toUpperCase()));
                }
                getSetupManager().process(getSetupRequest());
            } else if (merge == null) { // copy prototype as default template to baseDirectory
                IOUtil.copy(getPrototypeInputStream(),
                        new FileWriter(FileUtils.resolveFile(getBaseDirectory(), getDefaultTemplateFilename())));

                if (getLog().isInfoEnabled()) {
                    getLog().info(getDefaultTemplateFilename() + " has been created in the current directory.");
                    getLog().info("Change this file for your own configuration and rerun the last maven-goal.");
                    getLog().info("This way it will try to copy the file to the proper location.");
                }
            } else {
                throw new MojoFailureException("merge-property was set, but there was no template available");
            }
        } catch (IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        } catch (SetupExecutionException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
        postProcess();
    }

    /**
     * Use VersionRange.createFromVersionSpec( String ) to define the range for which the goal can be used
     * 
     * @return the versionRange
     * @throws InvalidVersionSpecificationException The specification can't be converted to a range
     * @since 1.0.0
     */
    protected abstract VersionRange getMavenVersionRange() throws InvalidVersionSpecificationException;

    /**
     * Can be overridden, if you want to add extra info before processing. For instance: setup:security-settings uses
     * this method to encrypt the master-password
     * 
     * @throws MojoExecutionException possible executionException
     * @throws MojoFailureException possible failureException
     * @since 1.0.0
     */
    protected void preProcess() throws MojoExecutionException, MojoFailureException {
    }

    /**
     * Can be overridden, if you want to take actions after processing
     * 
     * @throws MojoExecutionException possible executionException
     * @throws MojoFailureException possible failureException
     * @since 1.0.0
     */
    protected void postProcess() throws MojoExecutionException, MojoFailureException {

    }

    /**
     * Return list of propertyFiles as String, because that's how MavenFileFilter expects them
     * 
     * @return List of propertyFilePaths or null
     * @since 1.0.0
     */
    protected List<String> getPropertyFiles() {
        List<String> result = null;
        File propertyFile = FileUtils.resolveFile(getBaseDirectory(), getPropertiesFilename());
        if (propertyFile.exists()) {
            result = Collections.singletonList(propertyFile.getAbsolutePath());
        }
        return result;
    }

    /**
     * During the initializingPhase we can check if the required Maven version is used.
     * 
     * @param range the version range of Maven for which this goal is executable. 
     * @return true is version is within range, otherwise false.
     */
    private boolean isRequiredMavenVersion(VersionRange range) {
        return range.containsVersion(rti.getApplicationVersion());
    }
}