org.apache.maven.plugin.idea.AbstractIdeaMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.maven.plugin.idea.AbstractIdeaMojo.java

Source

package org.apache.maven.plugin.idea;

/*
 * 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 org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * @author Edwin Punzalan
 */
public abstract class AbstractIdeaMojo extends AbstractMojo {
    /**
     * The Maven Project.
     *
     * @parameter expression="${executedProject}"
     * @required
     * @readonly
     */
    protected MavenProject executedProject;

    /* holder for the log object only */
    protected Log log;

    /**
     * Whether to update the existing project files or overwrite them.
     *
     * @parameter expression="${overwrite}" default-value="false"
     */
    protected boolean overwrite;

    /**
     * @component
     */
    protected ArtifactFactory artifactFactory;

    /**
     * @parameter expression="${localRepository}"
     * @required
     * @readonly
     */
    protected ArtifactRepository localRepo;

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

    /**
     * @component role="org.apache.maven.artifact.metadata.ArtifactMetadataSource" hint="maven"
     */
    protected ArtifactMetadataSource artifactMetadataSource;

    public void initParam(MavenProject project, ArtifactFactory artifactFactory, ArtifactRepository localRepo,
            ArtifactResolver artifactResolver, ArtifactMetadataSource artifactMetadataSource, Log log,
            boolean overwrite) {
        this.executedProject = project;

        this.log = log;

        this.artifactFactory = artifactFactory;

        this.localRepo = localRepo;

        this.artifactResolver = artifactResolver;

        this.artifactMetadataSource = artifactMetadataSource;

        this.overwrite = overwrite;
    }

    protected Document readXmlDocument(File file, String altFilename) throws DocumentException {
        SAXReader reader = new SAXReader();
        if (file.exists() && !overwrite) {
            return reader.read(file);
        } else {
            File altFile = new File(executedProject.getBasedir(), "src/main/idea/" + altFilename);
            if (altFile.exists()) {
                return reader.read(altFile);
            } else {
                return reader.read(getClass().getResourceAsStream("/templates/default/" + altFilename));
            }
        }
    }

    protected void writeXmlDocument(File file, Document document) throws IOException {
        XMLWriter writer = new IdeaXmlWriter(file);
        writer.write(document);
        writer.close();
    }

    /**
     * Finds element from the module element.
     *
     * @param module Xpp3Dom element
     * @param name   Name attribute to find
     * @return component  Returns the Xpp3Dom element found.
     */
    protected Element findComponent(Element module, String name) {
        return findElement(module, "component", name);
    }

    protected Element findElement(Element element, String elementName, String attributeName) {
        for (Iterator children = element.elementIterator(elementName); children.hasNext();) {
            Element child = (Element) children.next();
            if (attributeName.equals(child.attributeValue("name"))) {
                return child;
            }
        }
        return createElement(element, elementName).addAttribute("name", attributeName);
    }

    protected Element findElement(Element component, String name) {
        Element element = component.element(name);
        if (element == null) {
            element = createElement(component, name);
        }
        return element;
    }

    /**
     * Creates an Xpp3Dom element.
     *
     * @param module Xpp3Dom element
     * @param name   Name of the element
     * @return component Xpp3Dom element
     */
    protected Element createElement(Element module, String name) {
        return module.addElement(name);
    }

    /**
     * Translate the absolutePath into its relative path.
     *
     * @param basedir      The basedir of the project.
     * @param absolutePath The absolute path that must be translated to relative path.
     * @return relative  Relative path of the parameter absolute path.
     */
    protected String toRelative(String basedir, String absolutePath) {
        String relative;

        // Convert drive letter
        String convertedBasedir = convertDriveLetter(basedir);
        String convertedAbsolutePath = convertDriveLetter(absolutePath);

        // Normalize path separators
        convertedBasedir = StringUtils.replace(convertedBasedir, "\\", "/");
        convertedAbsolutePath = StringUtils.replace(convertedAbsolutePath, "\\", "/");

        // Strip trailing slash
        if (convertedBasedir.endsWith("/")) {
            convertedBasedir = convertedBasedir.substring(0, convertedBasedir.length() - 1);
        }
        if (convertedAbsolutePath.endsWith("/")) {
            convertedAbsolutePath = convertedAbsolutePath.substring(0, convertedAbsolutePath.length() - 1);
        }

        // IDEA-103 Make sure that the basedir is appended with a / before we attempt to match it to the absolute path
        String matchableBasedir = convertedBasedir + "/";
        if (convertedAbsolutePath.startsWith(matchableBasedir)
                && convertedAbsolutePath.length() > matchableBasedir.length()) {
            // Simple case, path starts with basepath
            relative = convertedAbsolutePath.substring(matchableBasedir.length());
        } else {
            // It's more complex...
            StringTokenizer baseTokens = new StringTokenizer(convertedBasedir, "/", false);

            int baseCount = baseTokens.countTokens();
            List baseTokenList = new ArrayList(baseCount);
            while (baseTokens.hasMoreTokens()) {
                baseTokenList.add(baseTokens.nextToken());
            }

            StringTokenizer pathTokens = new StringTokenizer(convertedAbsolutePath, "/", false);

            int pathCount = pathTokens.countTokens();
            List pathTokenList = new ArrayList(pathCount);
            while (pathTokens.hasMoreTokens()) {
                pathTokenList.add(pathTokens.nextToken());
            }

            int maxCount = Math.max(baseTokenList.size(), pathTokenList.size());
            int differIndex = -1;
            for (int i = 0; i < maxCount; i++) {
                if (i >= pathTokenList.size() || i >= baseTokenList.size()) {
                    differIndex = i;
                    break;
                }
                String basePart = (String) baseTokenList.get(i);
                String pathPart = (String) pathTokenList.get(i);
                if (!basePart.equals(pathPart)) {
                    differIndex = i;
                    break;
                }
            }
            if (getLog().isDebugEnabled()) {
                getLog().debug("Construction of relative path... differIndex=" + differIndex);
            }
            if (differIndex < 1) {
                // Paths are either equal or completely different
                relative = convertedAbsolutePath;
            } else {
                StringBuilder result = new StringBuilder();
                int parentCount = baseTokenList.size() - differIndex;
                if (getLog().isDebugEnabled()) {
                    getLog().debug("parentCount=" + parentCount);
                }
                boolean isFirst = true;
                for (int i = 0; i < parentCount; i++) {
                    // Add parents
                    if (isFirst) {
                        isFirst = false;
                    } else {
                        result.append("/");
                    }
                    result.append("..");
                }
                for (int i = differIndex; i < pathTokenList.size(); i++) {
                    // Add the remaining path elements
                    if (isFirst) {
                        isFirst = false;
                    } else {
                        result.append("/");
                    }
                    result.append(pathTokenList.get(i));
                }
                relative = result.toString();
            }
        }

        if (getLog().isDebugEnabled()) {
            getLog().debug("toRelative(" + basedir + ", " + absolutePath + ") => " + relative);
        }

        return relative;
    }

    /**
     * Convert the drive letter, if there is one, to upper case. This is done
     * to avoid case mismatch when running cygwin on Windows.
     *
     * @param absolutePath The path to convert
     * @return The path that came in with its drive letter converted to upper case
     */
    String convertDriveLetter(String absolutePath) {
        if (absolutePath != null && absolutePath.length() >= 3 && !absolutePath.startsWith("/")) {
            // See if the path starts with "?:\", where ? must be a letter
            if (Character.isLetter(absolutePath.substring(0, 1).charAt(0))
                    && absolutePath.substring(1, 3).equals(":\\")) {
                // In that case we convert the first character to upper case
                return absolutePath.substring(0, 1).toUpperCase() + absolutePath.substring(1);
            }
        }
        return absolutePath;
    }

    /**
     * Remove elements from content (Xpp3Dom).
     *
     * @param content Xpp3Dom element
     * @param name    Name of the element to be removed
     */
    protected void removeOldElements(Element content, String name) {
        for (Iterator children = content.elementIterator(); children.hasNext();) {
            Element child = (Element) children.next();
            if (name.equals(child.getName())) {
                content.remove(child);
            }
        }
    }

    protected void doDependencyResolution(MavenProject project, ArtifactRepository localRepo)
            throws InvalidDependencyVersionException, ProjectBuildingException,
            InvalidVersionSpecificationException {
        Map managedVersions = createManagedVersionMap(artifactFactory, project.getId(),
                project.getDependencyManagement());

        try {
            ArtifactResolutionResult result = artifactResolver.resolveTransitively(getProjectArtifacts(),
                    project.getArtifact(), managedVersions, localRepo, project.getRemoteArtifactRepositories(),
                    artifactMetadataSource);

            project.setArtifacts(result.getArtifacts());
        } catch (ArtifactNotFoundException e) {
            getLog().debug(e.getMessage(), e);

            StringBuilder msg = new StringBuilder();
            msg.append("An error occurred during dependency resolution.\n\n");
            msg.append("    Failed to retrieve " + e.getDownloadUrl() + "\n");
            msg.append("from the following repositories:");
            for (Iterator repositories = e.getRemoteRepositories().iterator(); repositories.hasNext();) {
                ArtifactRepository repository = (ArtifactRepository) repositories.next();
                msg.append("\n    " + repository.getId() + "(" + repository.getUrl() + ")");
            }
            msg.append("\nCaused by: " + e.getMessage());

            getLog().warn(msg);
        } catch (ArtifactResolutionException e) {
            getLog().debug(e.getMessage(), e);

            StringBuilder msg = new StringBuilder();
            msg.append("An error occurred during dependency resolution of the following artifact:\n\n");
            msg.append("    " + e.getGroupId() + ":" + e.getArtifactId() + e.getVersion() + "\n\n");
            msg.append("Caused by: " + e.getMessage());

            getLog().warn(msg);
        }
    }

    /*
    * @todo we need a more permanent feature that does this properly
    */
    protected String getPluginSetting(String artifactId, String optionName, String defaultValue) {
        for (Iterator it = executedProject.getBuildPlugins().iterator(); it.hasNext();) {
            Plugin plugin = (Plugin) it.next();
            if (plugin.getArtifactId().equals(artifactId)) {
                Xpp3Dom o = (Xpp3Dom) plugin.getConfiguration();
                if (o != null && o.getChild(optionName) != null) {
                    return o.getChild(optionName).getValue();
                }
            }
        }
        return defaultValue;
    }

    private Set getProjectArtifacts() throws InvalidVersionSpecificationException {
        Set artifacts = new HashSet();

        for (Iterator dependencies = executedProject.getDependencies().iterator(); dependencies.hasNext();) {
            Dependency dep = (Dependency) dependencies.next();

            String groupId = dep.getGroupId();
            String artifactId = dep.getArtifactId();
            VersionRange versionRange = VersionRange.createFromVersionSpec(dep.getVersion());
            String type = dep.getType();
            if (type == null) {
                type = "jar";
            }
            String classifier = dep.getClassifier();
            boolean optional = dep.isOptional();
            String scope = dep.getScope();
            if (scope == null) {
                scope = Artifact.SCOPE_COMPILE;
            }

            Artifact artifact = artifactFactory.createDependencyArtifact(groupId, artifactId, versionRange, type,
                    classifier, scope, optional);

            if (scope.equalsIgnoreCase(Artifact.SCOPE_SYSTEM)) {
                artifact.setFile(new File(dep.getSystemPath()));
            }

            List exclusions = new ArrayList();
            for (Iterator j = dep.getExclusions().iterator(); j.hasNext();) {
                Exclusion e = (Exclusion) j.next();
                exclusions.add(e.getGroupId() + ":" + e.getArtifactId());
            }

            ArtifactFilter newFilter = new ExcludesArtifactFilter(exclusions);

            artifact.setDependencyFilter(newFilter);

            artifacts.add(artifact);
        }

        return artifacts;
    }

    private Map createManagedVersionMap(ArtifactFactory artifactFactory, String projectId,
            DependencyManagement dependencyManagement) throws ProjectBuildingException {
        Map map;
        if (dependencyManagement != null && dependencyManagement.getDependencies() != null) {
            map = new HashMap();
            for (Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext();) {
                Dependency d = (Dependency) i.next();

                try {
                    VersionRange versionRange = VersionRange.createFromVersionSpec(d.getVersion());
                    Artifact artifact = artifactFactory.createDependencyArtifact(d.getGroupId(), d.getArtifactId(),
                            versionRange, d.getType(), d.getClassifier(), d.getScope(), d.isOptional());
                    map.put(d.getManagementKey(), artifact);
                } catch (InvalidVersionSpecificationException e) {
                    throw new ProjectBuildingException(projectId, "Unable to parse version '" + d.getVersion()
                            + "' for dependency '" + d.getManagementKey() + "': " + e.getMessage(), e);
                }
            }
        } else {
            map = Collections.EMPTY_MAP;
        }
        return map;
    }

    public Log getLog() {
        if (log == null) {
            log = super.getLog();
        }

        return log;
    }
}