net.java.jpatch.maven.common.AbstractMavenMojo.java Source code

Java tutorial

Introduction

Here is the source code for net.java.jpatch.maven.common.AbstractMavenMojo.java

Source

/*
 * Copyright 2012 Andrej Petras <andrej@ajka-andrej.com>.
 *
 * 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 net.java.jpatch.maven.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.java.jpatch.maven.PatchMojo;
import net.java.jpatch.maven.logger.JPatchLogger;
import net.java.jpatch.maven.util.FileUtil;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.*;
import org.apache.maven.project.path.PathTranslator;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.settings.Settings;
import org.codehaus.mojo.versions.api.DefaultVersionsHelper;
import org.codehaus.mojo.versions.api.VersionsHelper;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.zip.ZipArchiver;
import org.codehaus.plexus.archiver.zip.ZipUnArchiver;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.components.io.fileselectors.FileInfo;
import org.codehaus.plexus.components.io.fileselectors.FileSelector;
import org.sonatype.aether.impl.internal.SimpleLocalRepositoryManager;
import org.sonatype.aether.util.DefaultRepositorySystemSession;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.cli.ExecutionEventLogger;
import org.apache.maven.execution.*;
import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.scm.manager.ScmManager;
import org.apache.maven.shared.invoker.InvocationRequest;
import org.apache.maven.shared.invoker.InvocationResult;
import org.apache.maven.shared.invoker.Invoker;
import org.apache.maven.shared.invoker.MavenCommandLineBuilder;
import org.codehaus.mojo.versions.api.ArtifactVersions;

/**
 * The abstract MAVEN class.
 *
 * @author Andrej Petras <andrej@ajka-andrej.com>
 */
public abstract class AbstractMavenMojo extends AbstractMojo {

    /** The property: RELEASE_PROPERTY_DATE */
    protected static final String RELEASE_PROPERTY_DATE = "Date";

    /** The property: RELEASE_PROPERTY_USER_NAME */
    protected static final String RELEASE_PROPERTY_USER_NAME = "User";

    /** The property: RELEASE_PROPERTY_JAVA_VERSION */
    protected static final String RELEASE_PROPERTY_JAVA_VERSION = "Java";

    /** The property: RELEASE_PROPERTY_OS_NAME */
    protected static final String RELEASE_PROPERTY_OS_NAME = "Os";

    /**
     * Include packages to run. 
     * @parameter expression="${includePackages}" default-value="jar,war,ejb,ear"
     */
    private String includePackages;

    /**
     * Exclude file types from the build package/release process. 
     * 
     * @parameter expression="${excludeExt}" default-value="jar,war,ear,zip,rar"
     */
    private String excludeExt;

    /**
     * The list of projects.
     *
     * @parameter expression="${projects}" 
     * @required
     */
    protected List<String> projects;

    /**
     * The MAVEN file.
     *
     * @parameter expression="${mavenFile}" default-value="pom.xml"
     */
    protected String mavenFile;

    /**
     * The release name.
     *
     * @parameter expression="${releaseSuffix}" default-value="RELEASE"
     */
    private String releaseSuffix;

    /**
     * The patch name.
     *
     * @parameter expression="${patchSuffix}" default-value="FP"
     */
    private String patchSuffix;

    /**
     * @parameter expression="${localRepository}" 
     * @required 
     * @readonly
     */
    protected ArtifactRepository localRepository;
    /**
     * @parameter expression="${project.remoteArtifactRepositories}" 
     * @required
     * @readonly
     */
    protected List<ArtifactRepository> remoteRepositories;
    /**
     * The project builder.
     *
     * @component
     */
    @Requirement
    private ProjectBuilder projectBuilder;

    /**
     * The execution event catapult.
     * 
     * @component
     */
    private ExecutionEventCatapult eventCatapult;

    /**
     * The MAVEN invoker.
     * 
     * @component
     */
    private Invoker invoker;

    /**
     * The SCM manager.
     * 
     * @component
     */
    protected ScmManager scmManager;

    /**
     * Component used to create an artifact.
     *
     * @component
     */
    protected RepositorySystem repositorySystem;
    /**
     * The MAVEN project.
     *
     * @parameter default-value="${project}" 
     * @required 
     * @readonly
     */
    protected MavenProject mavenProject;

    /**
     * Goals to run on subproject. 
     * @parameter expression="${goals}" default-value="install"
     */
    private String goals;

    /**
     * Goals to run on subproject. 
     * @parameter expression="${profiles}"
     */
    private String profiles;

    /** 
     * The build properties. 
     * @parameter expression="${properties}"
     */
    private Properties properties;

    /**
     * Gets the patch number from the artifact version.
     * 
     * @param version the artifact version.
     * 
     * @return the patch number.
     */
    protected int getPatchNumber(ArtifactVersion version) {
        int result = -1;
        String tmp = version.toString();
        int index = tmp.lastIndexOf(patchSuffix);
        if (index != -1) {
            try {
                tmp = tmp.substring(index + patchSuffix.length());
                result = Integer.parseInt(tmp);
            } catch (Exception ex) {
                // do nothing
            }
        }
        return result;
    }

    protected Artifact createPatchArtifact(int number) {
        return createPatchArtifact(mavenProject.getVersion() + "-" + patchSuffix + number);
    }

    protected Artifact createPatchArtifact(String version) {
        return createArtifact(mavenProject.getGroupId(), mavenProject.getArtifactId(), version, "zip");
    }

    protected Artifact createPatchArtifact() {
        return createPatchArtifact(mavenProject.getVersion() + "-" + patchSuffix);
    }

    protected Artifact createReleaseArtifact() {
        return createArtifact(mavenProject.getGroupId(), mavenProject.getArtifactId(),
                mavenProject.getVersion() + "-" + releaseSuffix, "zip");
    }

    protected Properties loadReleaseProperties() throws MojoExecutionException {
        Artifact releaseArtifact = createReleaseArtifact();
        File directory = createTargetDirectory(releaseArtifact.getVersion());

        Properties result = new Properties();
        try {
            File propFile = new File(directory, mavenProject.getBuild().getFinalName() + ".properties");
            result.load(new FileInputStream(propFile));
        } catch (IOException e) {
            throw new MojoExecutionException("Error creating the release properties file!", e);
        }
        return result;
    }

    protected Artifact resolveReleaseArtifact() {
        // Create release artifact
        Artifact releaseArtifact = createReleaseArtifact();

        // Search for existing release
        resolveArtifactFromLocalRepository(releaseArtifact);
        return releaseArtifact;
    }

    /**
     * Setups the release artifact.
     * - create release artifact
     * - unpack release artifact
     * - load the release properties
     * 
     * @return the release properties.
     * 
     * @throws MojoExecutionException if the method fails.
     * @throws MojoFailureException if the method fails.
     */
    protected File setupReleaseDirectory() throws MojoExecutionException, MojoFailureException {

        // Resolve release artifact
        Artifact releaseArtifact = resolveReleaseArtifact();
        File releaseFile = releaseArtifact.getFile();

        // Check existing release
        if (releaseFile == null || !releaseFile.exists()) {
            getLog().info(releaseFile.getAbsolutePath());
            getLog().error("Release file does not exist! For new release execute first jpatch:release.");
            throw new MojoFailureException("Release package does not exist!");
        }

        // Create release directory
        File directory = createTargetDirectory(releaseArtifact.getVersion());

        // Unpack release in the target directory
        unpackFile(directory.getParentFile(), releaseArtifact.getFile(), directory.getName());

        return directory;
    }

    /**
     * Setups the release artifact.
     * - create release artifact
     * - unpack release artifact
     * - load the release properties
     * 
     * @return the release properties.
     * 
     * @throws MojoExecutionException if the method fails.
     * @throws MojoFailureException if the method fails.
     */
    protected Properties setupReleaseArtifact() throws MojoExecutionException, MojoFailureException {

        File releaseDirectory = setupReleaseDirectory();

        // Open release properties file
        Properties releaseProperties = loadReleaseProperties();
        return releaseProperties;
    }

    /**
     * Finds all version of the artifact.
     * 
     * @param artifact the artifact.
     * 
     * @return the list of artifact versions.
     * 
     * @throws MojoExecutionException if the method fails.
     */
    protected List<ArtifactVersion> findAllVersionOfArtifact(Artifact artifact) throws MojoExecutionException {
        List<ArtifactVersion> result = new ArrayList<ArtifactVersion>();
        try {
            ArtifactVersions versions = getHelper().lookupArtifactVersions(artifact, false);
            if (versions != null) {
                versions.setIncludeSnapshots(true);
                result.addAll(Arrays.asList(versions.getVersions()));
            }
        } catch (ArtifactMetadataRetrievalException ex) {
            throw new MojoExecutionException(
                    "Error by searching the artifact version. Artifact " + artifact.getId(), ex);
        }
        return result;
    }

    /**
     * Executes the build of the list of projects.
     * 
     * @param projects the list of projects.
     * 
     * @throws MojoExecutionException if the method fails.
     * @throws MojoFailureException if the method fails.
     */
    protected void executeBuildProjects(List<MavenProject> projects)
            throws MojoExecutionException, MojoFailureException {
        // Execute projects
        getLog().info("Execute build projects");
        MavenSession mavenSession = createMavenSession(projects);
        buildMavenSession(mavenSession);

        // Check the build result
        if (mavenSession.getResult().hasExceptions()) {
            Throwable throwable = mavenSession.getResult().getExceptions().get(0);
            throw new MojoFailureException("Error by executing the build!", throwable);
        }
    }

    protected static List<MavenProject> filterMavenProjects(List<MavenProject> projects, Set<String> packages)
            throws MojoExecutionException {
        List<MavenProject> result = new ArrayList<MavenProject>();
        for (MavenProject project : projects) {
            if (packages.contains(project.getPackaging())) {
                result.add(project);
            }
        }
        return result;
    }

    protected void packDirectory(File directory, File file) {
        ZipArchiver archiver = new ZipArchiver();
        archiver.setDestFile(file);
        archiver.addDirectory(directory);
        try {
            archiver.createArchive();
        } catch (ArchiverException ex) {
            Logger.getLogger(PatchMojo.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PatchMojo.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    protected void unpackFile(File directory, File file) {
        unpackFile(directory, file, file.getName());
    }

    protected void unpackFile(File directory, File file, String name) {
        getLog().info("Unpack file " + file.getName());
        File unpackDir = new File(directory, name);
        unpackDir.mkdirs();
        ZipUnArchiver unArchiver = new ZipUnArchiver(file);
        unArchiver.setDestDirectory(unpackDir);
        unArchiver.enableLogging(new JPatchLogger(getLog()));
        unArchiver.extract();
    }

    protected File unpackArtifactFile(File directory, File file) {
        return unpackArtifactFile(directory, file, file.getName());
    }

    protected File unpackArtifactFile(File directory, File file, String name) {

        getLog().info("Unpack file " + file.getName());

        File unpackDir = new File(directory, name);
        unpackDir.mkdirs();

        ZipUnArchiver unArchiver = new ZipUnArchiver(file);
        unArchiver.setDestDirectory(unpackDir);
        unArchiver.enableLogging(new JPatchLogger(getLog()));

        final Set<String> exclude = getExcludeExt();

        FileSelector selector = new FileSelector() {
            @Override
            public boolean isSelected(FileInfo fi) throws IOException {
                boolean result;
                String name = fi.getName();
                if (fi.isDirectory()) {
                    name = name.substring(0, name.length() - 1);
                }

                String ext = FileUtil.getFileNameExt(name);
                result = !exclude.contains(ext);
                if (result) {
                    int index = name.indexOf("/");
                    if (index != -1) {
                        String prefix = name.substring(0, index);
                        ext = FileUtil.getFileNameExt(prefix);
                        result = !exclude.contains(ext);
                    }
                }
                return result;
            }
        };

        unArchiver.setFileSelectors(new FileSelector[] { selector });
        unArchiver.extract();

        return unpackDir;
    }

    protected File createAndAttachedPackage(File directory) {
        String fileName = mavenProject.getBuild().getFinalName();
        File packFile = new File(mavenProject.getBuild().getDirectory(), fileName + ".zip");
        packDirectory(directory, packFile);
        addAttachedArtifact(mavenProject.getGroupId(), mavenProject.getArtifactId(), mavenProject.getVersion(),
                "zip", packFile);
        return packFile;
    }

    protected void addAttachedArtifact(String groupId, String artifactId, String version, String packaging,
            File file) {
        Artifact pack = repositorySystem.createArtifact(groupId, artifactId, version, packaging);
        pack.setFile(file);
        mavenProject.addAttachedArtifact(pack);
    }

    private Artifact createArtifact(String groupId, String artifactId, String version, String packaging) {
        return repositorySystem.createArtifact(groupId, artifactId, version, packaging);
    }

    protected void addAttachedArtifact(String groupId, String artifactId, String version, String type,
            String classifier, File file) {
        Artifact result = repositorySystem.createArtifactWithClassifier(groupId, artifactId, version, type,
                classifier);
        result.setFile(file);
        mavenProject.addAttachedArtifact(result);
    }

    protected File createTargetDirectory(String name) {
        File result = new File(mavenProject.getBuild().getDirectory(), name);
        if (!result.exists()) {
            result.mkdirs();
        }
        return result;
    }

    protected File createBuildFile() {
        String fileName = mavenProject.getBuild().getFinalName();
        String buildDirectory = mavenProject.getBuild().getDirectory();
        String packaging = mavenProject.getPackaging();

        File buildFile = new File(buildDirectory, fileName + "." + packaging);
        try {
            buildFile.createNewFile();
        } catch (IOException ex) {
            Logger.getLogger(PatchMojo.class.getName()).log(Level.SEVERE, null, ex);
        }
        mavenProject.getArtifact().setFile(buildFile);
        return buildFile;
    }

    protected void resolveArtifactFromLocalRepository(Artifact artifact) {
        ArtifactResolutionRequest request = new ArtifactResolutionRequest();
        request.setLocalRepository(localRepository);
        request.setArtifact(artifact);
        repositorySystem.resolve(request);
    }

    protected Set<String> getExcludeExt() {
        List<String> tmp = Arrays.asList(excludeExt.split(","));
        Set<String> result = new HashSet<String>(tmp);
        return result;
    }

    protected Set<String> getPackages() {
        List<String> tmp = Arrays.asList(includePackages.split(","));
        Set<String> result = new HashSet<String>(tmp);
        return result;
    }

    /**
     * Loads the list of projects.
     *
     * @param directories the list of project directories.
     *
     * @return the list of the MAVEN projects.
     *
     * @throws MojoExecutionException
     * @throws ProjectBuildingException
     */
    protected List<MavenProject> loadMavenProjects() throws MojoExecutionException {
        List<File> files = new ArrayList<File>();
        for (String item : projects) {
            File file = new File(item, mavenFile);
            files.add(file);
        }

        DefaultRepositorySystemSession mavenSession = new DefaultRepositorySystemSession();
        mavenSession.setLocalRepositoryManager(new SimpleLocalRepositoryManager(localRepository.getBasedir()));

        DefaultProjectBuildingRequest config = new DefaultProjectBuildingRequest();
        config.setLocalRepository(localRepository);
        config.setRemoteRepositories(remoteRepositories);
        config.setRepositorySession(mavenSession);

        List<ProjectBuildingResult> results = null;
        try {
            results = projectBuilder.build(files, true, config);
        } catch (ProjectBuildingException ex) {
            throw new MojoExecutionException("Error create the maven project!", ex);
        }

        List<MavenProject> result = new ArrayList<MavenProject>();
        for (ProjectBuildingResult item : results) {
            result.add(item.getProject());
        }
        return result;
    }

    /**
     * Creates the MAVEN session.
     * 
     * @return the MAVEN session.
     */
    protected MavenSession createMavenSession(List<MavenProject> mavenProjects) {
        JPatchLogger jpatchLogger = new JPatchLogger(getLog());
        ExecutionListener listener = new ExecutionEventLogger(jpatchLogger);
        MavenExecutionRequest execRequest = new DefaultMavenExecutionRequest();
        execRequest.setStartTime(new Date());
        execRequest.setExecutionListener(listener);

        MavenExecutionResult execResult = new DefaultMavenExecutionResult();
        MavenSession result = new MavenSession(null, null, execRequest, execResult);
        result.setProjects(mavenProjects);
        return result;
    }

    //    /**
    //     * Short the MAVEN project.
    //     * 
    //     * @param mavenProjects the list of MAVEN projects.
    //     * 
    //     * @return shorted list of MAVEN projects.
    //     */
    //    protected List<MavenProject> createBuildOrder(List<MavenProject> mavenProjects) throws MojoFailureException {
    //        List<MavenProject> result = new ArrayList<MavenProject>();
    //        try {
    //            ProjectSorter sorter = new ProjectSorter(mavenProjects);
    //            result.addAll(sorter.getSortedProjects());
    //        } catch (Exception ex) {
    //            getLog().error("Error by creating the build order.", ex);
    //            throw new MojoFailureException("Error by creating the build order.", ex);
    //        }
    //        return result;
    //    }

    /**
     * Builds the MAVEN session.
     * 
     * @param session the MAVEN session.
     * 
     */
    protected void buildMavenSession(MavenSession session) {
        List<String> buildGoals = Arrays.asList(goals.split(","));
        List<String> buildProfiles = null;
        if (profiles != null) {
            buildProfiles = Arrays.asList(profiles.split(","));
        }

        eventCatapult.fire(ExecutionEvent.Type.SessionStarted, session, null);
        for (MavenProject project : session.getProjects()) {
            BuildSummary buildSummary = buildMavenProject(project, buildGoals, buildProfiles);
            session.getResult().addBuildSummary(buildSummary);
            if (buildSummary instanceof BuildFailure) {
                BuildFailure bf = (BuildFailure) buildSummary;
                session.getResult().addException(bf.getCause());
                break;
            }
        }
        eventCatapult.fire(ExecutionEvent.Type.SessionEnded, session, null);
    }

    /**
     * Build MAVEN project.
     * 
     * @param project the MAVEN project.
     * @param buildGoals the goals;
     * @param buildProfiles the profiles;
     * 
     * @return the build summary.
     */
    private BuildSummary buildMavenProject(MavenProject project, List<String> buildGoals,
            List<String> buildProfiles) {
        BuildSummary result;
        InvocationRequest request = new InvocationBuildRequest();
        request.setPomFile(project.getFile());
        request.setGoals(buildGoals);
        request.setRecursive(false);
        request.setProfiles(buildProfiles);
        request.setProperties(properties);

        Date startTime = new Date();
        try {
            getLog().info("");
            getLog().info("Build project [" + project.getId() + "]");
            getLog().info("Command " + new MavenCommandLineBuilder().build(request));
            getLog().info("");

            InvocationResult invokerResult = invoker.execute(request);
            if (invokerResult.getExecutionException() != null) {
                throw invokerResult.getExecutionException();
            }
            if (invokerResult.getExitCode() != 0) {
                throw new MojoFailureException("Exit code was " + invokerResult.getExitCode());
            }
            result = new BuildSuccess(project, new Date().getTime() - startTime.getTime());
        } catch (Exception e) {
            Date finished = new Date();
            result = new BuildFailure(project, finished.getTime() - startTime.getTime(), e);
        }
        return result;
    }

    /**
       * @component
       * @since 1.0-alpha-1
       */
    protected org.apache.maven.artifact.factory.ArtifactFactory artifactFactory;

    /**
     * @component
     * @since 1.0-alpha-1
     */
    protected org.apache.maven.artifact.resolver.ArtifactResolver resolver;

    /**
     * @parameter expression="${reactorProjects}"
     * @required
    * @readonly
    * @since 1.0-alpha-1
    */
    protected List reactorProjects;

    /**
     * The artifact metadata source to use.
     *
     * @component
     * @required
     * @readonly
     * @since 1.0-alpha-1
     */
    protected ArtifactMetadataSource artifactMetadataSource;

    /**
     * @parameter expression="${project.remoteArtifactRepositories}"
     * @readonly
     * @since 1.0-alpha-3
     */
    protected List remoteArtifactRepositories;

    /**
     * @parameter expression="${project.pluginArtifactRepositories}"
     * @readonly
     * @since 1.0-alpha-3
     */
    protected List remotePluginRepositories;

    /**
     * @component
     * @since 1.0-alpha-3
     */
    private WagonManager wagonManager;

    /**
     * @parameter expression="${settings}"
     * @readonly
     * @since 1.0-alpha-3
     */
    protected Settings settings;

    /**
     * settings.xml's server id for the URL.
     * This is used when wagon needs extra authentication information.
     *
     * @parameter expression="${maven.version.rules.serverId}" default-value="serverId";
     * @since 1.0-alpha-3
     */
    private String serverId;

    /**
     * The Wagon URI of a ruleSet file containing the rules that control how to compare version numbers.
     *
     * @parameter expression="${maven.version.rules}"
     * @since 1.0-alpha-3
     */
    private String rulesUri;

    /**      
     * Whether to allow snapshots when searching for the latest version of an artifact.
     *
     * @parameter expression="${allowSnapshots}" default-value="false"
     * @since 1.0-alpha-1
     */
    protected Boolean allowSnapshots;

    /**
     * Our versions helper.
     */
    private VersionsHelper helper;

    /**
     * The Maven Session.
     *
     * @parameter expression="${session}"
     * @required
     * @readonly
     * @since 1.0-alpha-1
     */
    protected MavenSession session;

    /**
     * @component
     */
    protected PathTranslator pathTranslator;

    /**
     * @component
     */
    protected ArtifactResolver artifactResolver;

    public VersionsHelper getHelper() throws MojoExecutionException {
        if (helper == null) {
            helper = new DefaultVersionsHelper(artifactFactory, artifactMetadataSource, remoteArtifactRepositories,
                    remotePluginRepositories, localRepository, wagonManager, settings, serverId, rulesUri, getLog(),
                    session, pathTranslator);

        }
        return helper;
    }
}