org.eclipse.m2e.refactoring.exclude.ExcludeArtifactRefactoring.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.m2e.refactoring.exclude.ExcludeArtifactRefactoring.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Sonatype, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *      Sonatype, Inc. - initial API and implementation
 *******************************************************************************/

package org.eclipse.m2e.refactoring.exclude;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.osgi.util.NLS;

import org.apache.maven.model.Dependency;
import org.apache.maven.model.Exclusion;
import org.apache.maven.project.MavenProject;

import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.graph.DependencyNode;
import org.sonatype.aether.graph.DependencyVisitor;
import org.sonatype.aether.util.artifact.JavaScopes;

import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.embedder.ArtifactKey;
import org.eclipse.m2e.core.internal.M2EUtils;
import org.eclipse.m2e.core.project.IMavenProjectFacade;
import org.eclipse.m2e.core.ui.internal.editing.AddDependencyOperation;
import org.eclipse.m2e.core.ui.internal.editing.AddExclusionOperation;
import org.eclipse.m2e.core.ui.internal.editing.PomEdits.CompoundOperation;
import org.eclipse.m2e.core.ui.internal.editing.PomEdits.Operation;
import org.eclipse.m2e.core.ui.internal.editing.PomHelper;
import org.eclipse.m2e.core.ui.internal.editing.RemoveDependencyOperation;
import org.eclipse.m2e.refactoring.Messages;

public class ExcludeArtifactRefactoring extends Refactoring {
    private static final String PLUGIN_ID = "org.eclipse.m2e.refactoring"; //$NON-NLS-1$

    private ArtifactKey[] keys;

    private IFile pomFile;

    private MavenProject exclusionPoint;

    private List<MavenProject> hierarchy;

    public ExcludeArtifactRefactoring(IFile pomFile, ArtifactKey[] keys) {
        this.pomFile = pomFile;
        this.keys = keys;
    }

    public void setExclusionPoint(MavenProject exclusionPoint) {
        this.exclusionPoint = exclusionPoint;
    }

    public void setHierarchy(List<MavenProject> hierarchy) {
        this.hierarchy = hierarchy;
    }

    public IMavenProjectFacade getSource() {
        return getMavenProjectFacade(pomFile);
    }

    protected IMavenProjectFacade getMavenProjectFacade(IFile pom) {
        return MavenPlugin.getMavenProjectRegistry().create(pom, true, new NullProgressMonitor());
    }

    protected IMavenProjectFacade getMavenProjectFacade(MavenProject mavenProject) {
        return MavenPlugin.getMavenProjectRegistry().getMavenProject(mavenProject.getGroupId(),
                mavenProject.getArtifactId(), mavenProject.getVersion());
    }

    /* (non-Javadoc)
     * @see org.eclipse.ltk.core.refactoring.Refactoring#getName()
     */
    public String getName() {
        StringBuilder sb = new StringBuilder();
        for (ArtifactKey key : keys) {
            sb.append(key.toString()).append(',');
        }
        sb.deleteCharAt(sb.length() - 1);
        return NLS.bind(Messages.MavenExcludeWizard_title, sb.toString());
    }

    /* (non-Javadoc)
     * @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
     */
    public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
            throws CoreException, OperationCanceledException {
        exclusionPoint = getMavenProjectFacade(pomFile).getMavenProject(pm);
        if (exclusionPoint == null) {
            return RefactoringStatus
                    .createFatalErrorStatus(Messages.ExcludeArtifactRefactoring_unableToLocateProject);
        }
        return new RefactoringStatus();
    }

    private List<Change> changes;

    /* (non-Javadoc)
     * @see org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor)
     */
    public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
            throws CoreException, OperationCanceledException {
        changes = new ArrayList<Change>();
        Set<ArtifactKey> locatedKeys = new HashSet<ArtifactKey>();
        List<IStatus> statuses = new ArrayList<IStatus>();
        SubMonitor monitor = SubMonitor.convert(pm, getHierarchy().size());

        List<Operation> exclusionOp = new ArrayList<Operation>();
        // Exclusion point
        Visitor visitor = locate(exclusionPoint, monitor.newChild(1));
        for (Entry<Dependency, Set<ArtifactKey>> entry : visitor.getSourceMap().entrySet()) {
            locatedKeys.addAll(entry.getValue());
            Dependency dependency = entry.getKey();
            if (contains(entry.getValue(), dependency)) {
                exclusionOp.add(new RemoveDependencyOperation(dependency));
            } else {
                for (ArtifactKey key : entry.getValue()) {
                    if (!hasExclusion(exclusionPoint, dependency, key)) {
                        exclusionOp.add(new AddExclusionOperation(dependency, key));
                    }
                }
            }
        }

        // Below exclusion point - pull up dependency to exclusion point
        for (MavenProject project : getDescendants()) {
            visitor = locate(project, monitor.newChild(1));
            List<Operation> operations = new ArrayList<Operation>();
            for (Entry<Dependency, Set<ArtifactKey>> entry : visitor.getSourceMap().entrySet()) {
                locatedKeys.addAll(entry.getValue());
                Dependency dependency = entry.getKey();
                operations.add(new RemoveDependencyOperation(dependency));
                if (!contains(entry.getValue(), dependency)) {
                    if (!hasDependency(exclusionPoint, dependency)) {
                        exclusionOp.add(new AddDependencyOperation(dependency));
                    }
                    for (ArtifactKey key : entry.getValue()) {
                        if (!hasExclusion(exclusionPoint, dependency, key)) {
                            exclusionOp.add(new AddExclusionOperation(dependency, key));
                        }
                    }
                }
            }
            if (operations.size() > 0) {
                IFile pom = getFile(project);
                changes.add(PomHelper.createChange(pom,
                        new CompoundOperation(operations.toArray(new Operation[operations.size()])), getName(pom)));
            }
        }

        // Above exclusion - Add dep to exclusionPoint
        for (MavenProject project : getAncestors()) {
            visitor = locate(project, monitor.newChild(1));
            for (Entry<Dependency, Set<ArtifactKey>> entry : locate(project, monitor.newChild(1)).getSourceMap()
                    .entrySet()) {
                locatedKeys.addAll(entry.getValue());
                Dependency dependency = entry.getKey();
                if (contains(entry.getValue(), dependency)) {
                    if (project.getFile() != null) {
                        statuses.add(new Status(IStatus.INFO, PLUGIN_ID,
                                NLS.bind(Messages.ExcludeArtifactRefactoring_removeDependencyFrom,
                                        toString(dependency),
                                        getMavenProjectFacade(project).getPom().getFullPath())));
                        IFile pom = getFile(project);
                        changes.add(PomHelper.createChange(getFile(project),
                                new RemoveDependencyOperation(dependency), getName(pom)));
                    }
                } else {
                    exclusionOp.add(new AddDependencyOperation(dependency));
                    for (ArtifactKey key : entry.getValue()) {
                        if (!hasExclusion(exclusionPoint, dependency, key)) {
                            exclusionOp.add(new AddExclusionOperation(dependency, key));
                        }
                    }
                }
            }
        }
        if (!exclusionOp.isEmpty()) {
            IFile pom = getFile(exclusionPoint);
            changes.add(PomHelper.createChange(pom,
                    new CompoundOperation(exclusionOp.toArray(new Operation[exclusionOp.size()])), getName(pom)));
        }

        if (statuses.size() == 1) {
            return RefactoringStatus.create(statuses.get(0));
        } else if (statuses.size() > 1) {
            return RefactoringStatus
                    .create(new MultiStatus(PLUGIN_ID, 0, statuses.toArray(new IStatus[statuses.size()]),
                            Messages.ExcludeArtifactRefactoring_errorCreatingRefactoring, null));
        } else if (locatedKeys.isEmpty()) {
            return RefactoringStatus.createFatalErrorStatus(Messages.ExcludeArtifactRefactoring_noTargets);
        } else if (locatedKeys.size() != keys.length) {
            StringBuilder sb = new StringBuilder();
            for (ArtifactKey key : keys) {
                if (!locatedKeys.contains(key)) {
                    sb.append(key.toString()).append(',');
                }
            }
            sb.deleteCharAt(sb.length() - 1);
            return RefactoringStatus.createErrorStatus(
                    NLS.bind(Messages.ExcludeArtifactRefactoring_failedToLocateArtifact, sb.toString()));
        }
        return new RefactoringStatus();
    }

    private String getName(IFile file) {
        return new StringBuilder().append(file.getName()).append(" - ").append(file.getProject().getName()) //$NON-NLS-1$
                .toString();
    }

    private Visitor locate(MavenProject project, IProgressMonitor monitor) throws CoreException {
        DependencyNode root = MavenPlugin.getMavenModelManager().readDependencyTree(project, JavaScopes.TEST,
                monitor);
        Visitor visitor = new Visitor(project);
        root.accept(visitor);
        return visitor;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
     */
    public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
        CompositeChange change = new CompositeChange(Messages.ExcludeArtifactRefactoring_changeTitle);
        change.addAll(changes.toArray(new Change[changes.size()]));
        return change;
    }

    private static boolean matches(Dependency d, ArtifactKey a) {
        return d.getArtifactId().equals(a.getArtifactId()) && d.getGroupId().equals(a.getGroupId());
    }

    private static boolean contains(Set<ArtifactKey> keys, Dependency d) {
        for (ArtifactKey key : keys) {
            if (matches(d, key)) {
                return true;
            }
        }
        return false;
    }

    private Collection<MavenProject> getHierarchy() {
        return hierarchy;
    }

    private IFile getFile(MavenProject project) throws CoreException {
        IFile res = M2EUtils.getPomFile(project);

        if (res == null) {
            throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID,
                    NLS.bind(Messages.ExcludeArtifactRefactoring_failedToLocatePom, project.toString())));
        } else {
            return res;
        }
    }

    private Collection<MavenProject> getDescendants() {
        List<MavenProject> descendants = new ArrayList<MavenProject>();
        for (MavenProject project : getHierarchy()) {
            if (project == exclusionPoint) {
                break;
            } else {
                descendants.add(project);
            }
        }
        return descendants;
    }

    private Collection<MavenProject> getAncestors() {
        List<MavenProject> ancestors = new ArrayList<MavenProject>();
        boolean add = false;
        for (MavenProject project : getHierarchy()) {
            if (project == exclusionPoint) {
                add = !add;
            } else if (add) {
                ancestors.add(project);
            }
        }
        return ancestors;
    }

    private static String toString(Dependency dependency) {
        return NLS.bind("{0}:{1}:{2}", //$NON-NLS-1$
                new String[] { dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() });
    }

    private boolean hasDependency(MavenProject project, Dependency dependency) {
        if (project.getOriginalModel().getDependencies() == null) {
            return false;
        }
        for (Dependency dep : project.getOriginalModel().getDependencies()) {
            if (dep.getArtifactId().equals(dependency.getArtifactId())
                    && dep.getGroupId().equals(dependency.getGroupId())
                    && (dep.getVersion() == null || dep.getVersion().equals(dependency.getVersion()))) {
                return true;
            }
        }
        return false;
    }

    private static boolean hasExclusion(MavenProject project, Dependency d, ArtifactKey exclusion) {
        if (project.getOriginalModel().getDependencies() == null) {
            return false;
        }
        Dependency dependency = null;
        for (Dependency dep : project.getOriginalModel().getDependencies()) {
            if (dep.getArtifactId().equals(d.getArtifactId()) && dep.getGroupId().equals(d.getGroupId())
                    && (dep.getVersion() == null || dep.getVersion().equals(d.getVersion()))) {
                dependency = dep;
                break;
            }
        }
        if (dependency == null || dependency.getExclusions() == null) {
            return false;
        }
        for (Exclusion ex : dependency.getExclusions()) {
            if (ex.getArtifactId().equals(exclusion.getArtifactId())
                    && ex.getGroupId().equals(exclusion.getGroupId())) {
                return true;
            }
        }
        return false;
    }

    private class Visitor implements DependencyVisitor {
        private List<Dependency> dependencies;

        private Map<Dependency, Set<ArtifactKey>> sourceMap = new HashMap<Dependency, Set<ArtifactKey>>();

        Visitor(MavenProject project) {
            dependencies = new ArrayList<Dependency>();
            dependencies.addAll(project.getOriginalModel().getDependencies());
            //      for(Profile profile : project.getActiveProfiles()) {
            //        dependencies.addAll(profile.getDependencies());
            //      }
        }

        Map<Dependency, Set<ArtifactKey>> getSourceMap() {
            return sourceMap;
        }

        private int depth;

        private DependencyNode topLevel;

        public boolean visitLeave(DependencyNode node) {
            depth--;
            return true;
        }

        public boolean visitEnter(DependencyNode node) {
            if (depth == 1) {
                topLevel = node;
            }
            depth++;

            if (node.getDependency() != null) {
                Artifact a = node.getDependency().getArtifact();
                for (ArtifactKey key : keys) {
                    if (a.getGroupId().equals(key.getGroupId()) && a.getArtifactId().equals(key.getArtifactId())) {
                        if (topLevel != null) {
                            // need to add exclusion to top-level dependency
                            Dependency dependency = findDependency(topLevel);
                            if (dependency != null) {
                                put(dependency, key);
                            }
                        }
                        return true;
                    }
                }
            }
            return true;
        }

        private void put(Dependency dep, ArtifactKey key) {
            Set<ArtifactKey> keys = sourceMap.get(dep);
            if (keys == null) {
                keys = new HashSet<ArtifactKey>();
                sourceMap.put(dep, keys);
            }
            keys.add(key);
        }

        private Dependency findDependency(String groupId, String artifactId) {
            for (Dependency d : dependencies) {
                if (d.getGroupId().equals(groupId) && d.getArtifactId().equals(artifactId)) {
                    return d;
                }
            }
            return null;
        }

        private Dependency findDependency(DependencyNode node) {
            Artifact artifact;
            if (node.getRelocations().isEmpty()) {
                artifact = node.getDependency().getArtifact();
            } else {
                artifact = node.getRelocations().get(0);
            }
            return findDependency(artifact.getGroupId(), artifact.getArtifactId());
        }
    }
}