All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bluestemsoftware.open.eoa.plugin.util.ClasspathHelper Maven / Gradle / Ivy

/**
 * Copyright 2008 Bluestem Software LLC.  All Rights Reserved.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 * 
 */

package org.bluestemsoftware.open.eoa.plugin.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
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 org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
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.ArtifactCollector;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.ResolutionListener;
import org.apache.maven.artifact.resolver.ResolutionNode;
import org.apache.maven.artifact.resolver.WarningResolutionListener;
import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.artifact.resolver.filter.TypeArtifactFilter;
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.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.bluestemsoftware.open.eoa.plugin.surefire.cfg.Test;
import org.codehaus.plexus.logging.Logger;

public class ClasspathHelper {

    static final String LINE_BREAK = System.getProperty("line.separator");
    static final Map EMPTY_MAP = new HashMap();

    private Logger logger = null;
    private File basedir;
    private MavenProject project;
    private ArtifactFactory artifactFactory;
    private ArtifactCollector artifactCollector;
    private ArtifactMetadataSource metadataSource;
    private List remoteRepositories;
    private ArtifactResolver artifactResolver;
    private ArtifactRepository localRepository;
    private Test test;
    private File systemTestClassesDirectory;
    private File clientTestClassesDirectory;

    private Map parentClasspath;
    private Map sharedClasspath;
    private Map systemTestClasspath;
    private Map clientTestClasspath;

    private boolean isRuntime;

    /**
     * Constructs helper.
     * 
     * @param logger
     * @param basedir
     * @param project
     * @param isRuntime
     *        true if runtime classpath. false if compilation classpath
     */
    public ClasspathHelper(Logger logger, File basedir, MavenProject project, boolean isRuntime) {
        this.logger = logger;
        this.basedir = basedir;
        this.project = project;
        this.isRuntime = isRuntime;
    }

    public void setArtifactCollector(ArtifactCollector artifactCollector) {
        this.artifactCollector = artifactCollector;
    }

    public void setArtifactFactory(ArtifactFactory artifactFactory) {
        this.artifactFactory = artifactFactory;
    }

    public void setArtifactResolver(ArtifactResolver artifactResolver) {
        this.artifactResolver = artifactResolver;
    }

    public void setLocalRepository(ArtifactRepository localRepository) {
        this.localRepository = localRepository;
    }

    public void setMetadataSource(ArtifactMetadataSource metadataSource) {
        this.metadataSource = metadataSource;
    }

    public void setRemoteRepositories(List remoteRepositories) {
        this.remoteRepositories = remoteRepositories;
    }

    public void setTest(Test test) {
        this.test = test;
    }

    public void setSystemTestClassesDirectory(File systemTestClassesDirectory) {
        this.systemTestClassesDirectory = systemTestClassesDirectory;
    }

    public void setClientTestClassesDirectory(File clientTestClassesDirectory) {
        this.clientTestClassesDirectory = clientTestClassesDirectory;
    }

    public Map getParentClasspath(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        if (parentClasspath != null) {
            return parentClasspath;
        }

        parentClasspath = new HashMap();

        for (Artifact artifact : getParentClasspathArtifacts(projectDependencies, versionlessKeys)) {
            try {
                String constituent = artifact.getFile().toURI().toURL().toExternalForm();
                String dependencyTrail = artifact.getDependencyTrail() == null ? "root" : artifact
                        .getDependencyTrail().toString();
                parentClasspath.put(constituent, dependencyTrail);
            } catch (IOException ie) {
                throw new MojoExecutionException("Error configuring parent classpath. " + ie);
            }
        }

        return parentClasspath;

    }

    public Set getParentClasspathArtifacts(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        Set result = new HashSet();

        // add provided dependencies as defined by eoa specification to
        // parent classloader, i.e. parent of all eoa classloaders

        for (Artifact artifact : projectDependencies) {
            if (!artifact.getScope().equals(Artifact.SCOPE_SYSTEM)) {
                continue;
            }
            if (!artifact.getType().equals("jar")) {
                continue;
            }
            String key = ArtifactUtils.versionlessKey(artifact);
            if (versionlessKeys.contains(key)) {
                continue;
            }
            DependencyHelper.resolveArtifact(artifact, remoteRepositories, artifactResolver, localRepository);
            versionlessKeys.add(key);
            result.add(artifact);
        }

        // add log4j classes to provided classpath to provide logging
        // impl required by standalone system implementation

        Artifact artifact = artifactFactory.createArtifact("log4j", "log4j", "1.2.14", "runtime", "jar");
        String key = ArtifactUtils.versionlessKey(artifact);
        if (!versionlessKeys.contains(key)) {
            versionlessKeys.add(key);
            DependencyHelper.resolveArtifact(artifact, remoteRepositories, artifactResolver, localRepository);
            result.add(artifact);
        }

        return result;

    }

    /**
     * Gets shared classpath urls.
     * 
     * @param projectDependencies
     * @param versionlessKeys
     * @param isProjectClasspath
     *        if true, indicates that shared dependencies flagged as optional are included,
     *        i.e. see SharedDependency.isRequired() for comments.
     * @return
     * @throws MojoExecutionException
     */
    public Map getSharedClasspath(Set projectDependencies, Set versionlessKeys, boolean isProjectClasspath) throws MojoExecutionException {

        if (sharedClasspath != null) {
            return sharedClasspath;
        }

        sharedClasspath = new HashMap();

        Set artifacts = getSharedClasspathArtifacts(projectDependencies, versionlessKeys,
                isProjectClasspath);

        for (Artifact dependency : artifacts) {
            try {
                String constituent = dependency.getFile().toURI().toURL().toExternalForm();
                String dependencyTrail = dependency.getDependencyTrail() == null ? "root" : dependency
                        .getDependencyTrail().toString();
                sharedClasspath.put(constituent, dependencyTrail);
            } catch (IOException ie) {
                throw new MojoExecutionException("Error configuring shared classpath. " + ie);
            }
        }

        return sharedClasspath;

    }

    /**
     * Gets shared classpath artifacts.
     * 
     * @param projectDependencies
     * @param versionlessKeys
     * @param isProjectClasspath
     *        if true, indicates that shared dependencies flagged as optional are included,
     *        i.e. see SharedDependency.isRequired() for comments.
     * @return
     * @throws MojoExecutionException
     */
    public Set getSharedClasspathArtifacts(Set projectDependencies, Set versionlessKeys, boolean isProjectClasspath) throws MojoExecutionException {

        Set result = new HashSet();

        // return all artifacts with provided scope and jar packaging. note that eoa spec
        // requires that latest version be added to path unless shared artifact is managed.
        // this doesn't apply here, because we are only processing shared artifacts defined
        // within a single project, i.e. not a system which is comprised of multiple
        // projects. shared dependencies are not processed transitively. we therefore are
        // working off of the latest version of each, which was determined by maven

        for (Artifact dependency : projectDependencies) {
            if (!dependency.getScope().equals(Artifact.SCOPE_PROVIDED)) {
                continue;
            }
            if (!dependency.getType().equals("jar")) {
                continue;
            }
            if (dependency.isOptional()) {
                if (!isProjectClasspath) {
                    continue;
                }
            }
            String key = ArtifactUtils.versionlessKey(dependency);
            if (versionlessKeys.contains(key)) {
                continue;
            }
            versionlessKeys.add(key);
            DependencyHelper.resolveArtifact(dependency, remoteRepositories, artifactResolver, localRepository);
            result.add(dependency);
        }

        return result;

    }

    public Map getDeploymentClasspath(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        Map deploymentClasspath = new HashMap();

        File outputDir = new File(basedir, "target/classes");
        File eoaInfDir = new File(outputDir, "EOA-INF");
        if (eoaInfDir.exists() == false) {
            // resources mojo didn't run, i.e. project defined no resources dir.
            // so we create the eoa-inf dir here
            eoaInfDir.mkdir();
        }

        // add all jars defined within optional lib subdirectory to
        // classpath

        File libDir = new File(eoaInfDir, "lib/");
        if (libDir.exists() && libDir.isDirectory()) {
            File[] contents = libDir.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    return pathname.toString().endsWith("jar");
                }
            });
            if (contents.length > 0) {
                for (int i = 0; i < contents.length; i++) {
                    try {
                        String decodedPath = contents[i].toURI().getSchemeSpecificPart();
                        deploymentClasspath.put(new File(decodedPath).toURI().toURL().toExternalForm(), "none");
                    } catch (MalformedURLException me) {
                        throw new MojoExecutionException("Error configuring deployment classpath. " + me);
                    }
                }
            }
        }

        // add root of optional classes directory to deployment classpath
        // which makes all classes contained within visible to loader.
        // dir is optional because component deployment may not define
        // classes. if dir is empty and it's an extension deployment,
        // the dir should exist

        File classesDir = new File(eoaInfDir, "classes/");
        if (classesDir.exists() && classesDir.isDirectory()) {
            try {
                String decodedPath = classesDir.toURI().getSchemeSpecificPart();
                deploymentClasspath.put(new File(decodedPath).toURI().toURL().toExternalForm(), "none");
            } catch (MalformedURLException me) {
                throw new MojoExecutionException("Error configuring deployment classpath. " + me);
            }
        }

        Set artifacts = getDeploymentClasspathArtifacts(projectDependencies, versionlessKeys);
        for (Artifact dependency : artifacts) {
            try {
                String constituent = dependency.getFile().toURI().toURL().toExternalForm();
                String dependencyTrail = dependency.getDependencyTrail() == null ? "none" : dependency
                        .getDependencyTrail().toString();
                deploymentClasspath.put(constituent, dependencyTrail);
            } catch (IOException ie) {
                throw new MojoExecutionException("Error configuring deployment classpath. " + ie);
            }
        }

        return deploymentClasspath;

    }

    public Set getDeploymentClasspathArtifacts(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        Set result = new HashSet();

        // add all jar artifacts other than system and provided scoped artifacts which
        // were added to parent and shared classpaths respectively, to deployment
        // classpath. exclude artifacts with test scope

        Set explicitArtifacts = new HashSet();

        for (Artifact dependency : projectDependencies) {

            if (!dependency.getScope().equals(Artifact.SCOPE_COMPILE)) {
                continue;
            }

            if (!dependency.getType().equals("jar")) {
                continue;
            }

            if (!dependency.isOptional()) {
                continue;
            }

            // if we make it this far, artifact qualifies as a deployment scoped
            // artifact. add to result set now, so that it cannot be overridden
            // by transitive artifacts with diff version

            String key = ArtifactUtils.versionlessKey(dependency);
            if (!versionlessKeys.contains(key)) {
                versionlessKeys.add(key);
                DependencyHelper
                        .resolveArtifact(dependency, remoteRepositories, artifactResolver, localRepository);
                result.add(dependency);
                explicitArtifacts.add(dependency);
            }

        }

        // take all explicity declared artifacts which qualify as a deployment
        // scoped artifacts and resolve transitively. note that maven will handle
        // version conflict resolution for transitive artifacts with same key

        Set transitiveArtifacts;
        try {
            transitiveArtifacts = resolveArtifactsTransitively(explicitArtifacts);
        } catch (Exception ex) {
            throw new MojoExecutionException("Error configuring deployment classpath. " + ex);
        }

        for (Artifact transitiveArtifact : transitiveArtifacts) {
            String key = ArtifactUtils.versionlessKey(transitiveArtifact);
            if (!versionlessKeys.contains(key)) {
                versionlessKeys.add(key);
                result.add(transitiveArtifact);
            }
        }

        return result;

    }

    public Set getNonEOAProjectArtifacts(Set projectDependencies) throws MojoExecutionException {

        Set result = new HashSet();
        Set explicitArtifacts = new HashSet();
        
        for (Artifact artifact : projectDependencies) {
            
            if (artifact.getScope().equals(Artifact.SCOPE_TEST)) {

                // add artifact to result set before converting so that it will
                // retain test scope, then convert to runtime scope and add to
                // explicit artifacts set so that it will be resolved transitively

                DependencyHelper
                        .resolveArtifact(artifact, remoteRepositories, artifactResolver, localRepository);
                result.add(artifact);
                explicitArtifacts.add(adjustTestScope(artifact));

            } else {
                
                explicitArtifacts.add(artifact);
                
            }
            
        }

        Set transitiveArtifacts;
        try {
            transitiveArtifacts = resolveArtifactsTransitively(explicitArtifacts);
        } catch (Exception ex) {
            throw new MojoExecutionException("Error configuring project classpath. " + ex);
        }
        
        for (Artifact transitiveArtifact : transitiveArtifacts) {
            if (!result.contains(transitiveArtifact)) {
                result.add(transitiveArtifact);
            }
        }

        return result;

    }

    public Map getSystemTestClasspath(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        if (systemTestClasspath != null) {

            // consitituents within systemTestClasspath list are static. add dynamic
            // consitituent, i.e. test classes dir to a separate list and return

            Map answer = new HashMap(systemTestClasspath);
            try {
                answer.put(systemTestClassesDirectory.toURI().toURL().toExternalForm(), "none");
            } catch (MalformedURLException me) {
                throw new MojoExecutionException("Error configuring system test classpath. " + me);
            }

            return answer;

        }

        systemTestClasspath = new HashMap();

        File outputDir = new File(basedir, "target/classes");
        File eoaInfDir = new File(outputDir, "EOA-INF");
        if (eoaInfDir.exists() == false) {
            throw new MojoExecutionException("Error configuring system test classpath."
                    + " Deployment missing required 'EOA-INF' sub-directory");
        }

        // add all jars within optional lib sub-directory as constituents

        File libDir = new File(eoaInfDir, "lib/");
        if (libDir.exists() && libDir.isDirectory()) {
            File[] contents = libDir.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    return pathname.toString().endsWith("jar");
                }
            });
            if (contents.length > 0) {
                for (int i = 0; i < contents.length; i++) {
                    try {
                        String decodedPath = contents[i].toURI().getSchemeSpecificPart();
                        systemTestClasspath.put(new File(decodedPath).toURI().toURL().toExternalForm(), "none");
                    } catch (MalformedURLException me) {
                        throw new MojoExecutionException("Error configuring system test classpath. " + me);
                    }
                }
            }
        }

        // add root of optional classes directory to deployment classpath
        // which makes all classes contained within visible to loader.
        // dir is optional because component deployment may not define
        // classes. if dir is empty and it's an extension deployment,
        // the dir should exist

        File classesDir = new File(eoaInfDir, "classes/");
        if (classesDir.exists() && classesDir.isDirectory()) {
            try {
                String decodedPath = classesDir.toURI().getSchemeSpecificPart();
                systemTestClasspath.put(new File(decodedPath).toURI().toURL().toExternalForm(), "none");
            } catch (MalformedURLException me) {
                throw new MojoExecutionException("Error configuring system test classpath. " + me);
            }
        }

        Set artifacts = getSystemTestClasspathArtifacts(projectDependencies, versionlessKeys);
        for (Artifact dependency : artifacts) {
            try {
                String constituent = dependency.getFile().toURI().toURL().toExternalForm();
                String dependencyTrail = dependency.getDependencyTrail() == null ? "none" : dependency
                        .getDependencyTrail().toString();
                systemTestClasspath.put(constituent, dependencyTrail);
            } catch (IOException ie) {
                throw new MojoExecutionException("Error configuring system test classpath. " + ie);
            }
        }

        // consitituents within systemTestClasspath map are static. add dynamic
        // consitituent, i.e. test classes dir to a separate map and return

        Map answer = new HashMap(systemTestClasspath);
        try {
            answer.put(systemTestClassesDirectory.toURI().toURL().toExternalForm(), "none");
        } catch (MalformedURLException me) {
            throw new MojoExecutionException("Error configuring system test classpath. " + me);
        }

        return answer;

    }

    public Set getSystemTestClasspathArtifacts(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        Set result = new HashSet();

        // retrieve optional configuration, which if defined, identifies which
        // dependencies with test scope are added to system test classpath, i.e.
        // as opposed to client test classpath

        Set systemTestDependencies = null;
        if (test != null && test.getSystem() != null) {
            systemTestDependencies = new HashSet();
            for (org.bluestemsoftware.open.eoa.plugin.surefire.cfg.Dependency dep : test.getSystem()) {
                systemTestDependencies.add(dep.getGroupId() + ":" + dep.getArtifactId());
            }
        }

        // if system test dependencies defined via plugin configuration, verify
        // the ref matches a test scoped artifact within parent project

        if (systemTestDependencies != null) {
            Set testArtifacts = new HashSet();
            for (Artifact artifact : projectDependencies) {
                if (!artifact.getScope().equals(Artifact.SCOPE_TEST)) {
                    continue;
                }
                if (!artifact.getType().equals("jar")) {
                    continue;
                }
                testArtifacts.add(artifact.getGroupId() + ":" + artifact.getArtifactId());
            }
            for (String dep : systemTestDependencies) {
                if (!testArtifacts.contains(dep)) {
                    throw new MojoExecutionException("system test dependency "
                            + dep
                            + ", defined via plugin configuration must be defined as an"
                            + " artifact within parent project with scope 'test'.");
                }
            }
        }

        // add all jar artifacts with compile scope and/or test scope, to
        // collection of explicit declared artifacts which qualify as a
        // deployment scoped artifact

        Set explicitArtifacts = new HashSet();

        for (Artifact dependency : projectDependencies) {

            if (dependency.getScope().equals(Artifact.SCOPE_SYSTEM)) {
                continue;
            }

            if (dependency.getScope().equals(Artifact.SCOPE_PROVIDED)) {
                continue;
            }

            if (dependency.getScope().equals(Artifact.SCOPE_RUNTIME)) {
                continue;
            }

            if (!dependency.getType().equals("jar")) {
                continue;
            }

            if (dependency.getScope().equals(Artifact.SCOPE_COMPILE)) {
                if (!dependency.isOptional()) {
                    continue;
                }
            }

            // if we make it this far, artifact qualifies as a deployment scoped
            // artifact. add to result set now, so that it cannot be overridden
            // by transitive artifacts with diff version

            if (dependency.getScope().equals(Artifact.SCOPE_TEST)) {

                // if dependencies are given via plugin configuration and artifact
                // has test scope and ref is not defined, skip it. if it is defined,
                // or if no configuration was provided, include it

                if (systemTestDependencies != null) {
                    String ref = dependency.getGroupId() + ":" + dependency.getArtifactId();
                    if (!systemTestDependencies.contains(ref)) {
                        logger.debug("test scoped artifact "
                                + ref
                                + ", not defined as a dependency within plugin configuration."
                                + " excluding from system tests classpath.");
                        continue;
                    }
                }

                // add artifact to result set before converting so that it will
                // retain test scope, then convert to runtime scope and add to
                // explicit artifacts set so that it will be resolved transitively

                versionlessKeys.add(ArtifactUtils.versionlessKey(dependency));
                DependencyHelper
                        .resolveArtifact(dependency, remoteRepositories, artifactResolver, localRepository);
                result.add(dependency);
                explicitArtifacts.add(adjustTestScope(dependency));

            } else {

                String key = ArtifactUtils.versionlessKey(dependency);
                if (!versionlessKeys.contains(key)) {
                    versionlessKeys.add(key);
                    DependencyHelper.resolveArtifact(dependency, remoteRepositories, artifactResolver,
                            localRepository);
                    result.add(dependency);
                    explicitArtifacts.add(dependency);
                }

            }

        }

        // take all explicity declared artifacts which qualify as a deployment
        // scoped artifacts and resolve transitively. note that maven will handle
        // version conflict resolution for transitive artifacts with same key

        Set transitiveArtifacts;
        try {
            transitiveArtifacts = resolveArtifactsTransitively(explicitArtifacts);
        } catch (Exception ex) {
            throw new MojoExecutionException("Error configuring deployment classpath. " + ex);
        }

        for (Artifact transitiveArtifact : transitiveArtifacts) {
            String key = ArtifactUtils.versionlessKey(transitiveArtifact);
            if (!versionlessKeys.contains(key)) {
                versionlessKeys.add(key);
                result.add(transitiveArtifact);
            }
        }

        return result;

    }

    public Map getClientTestClasspath(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        if (clientTestClassesDirectory == null) {
            return EMPTY_MAP;
        }

        if (clientTestClasspath != null) {

            // consitituents within clientTestClasspath list are static. add dynamic
            // consitituent, i.e. test classes dir to a separate list and return

            Map answer = new HashMap(clientTestClasspath);
            try {
                answer.put(clientTestClassesDirectory.toURI().toURL().toExternalForm(), "none");
            } catch (MalformedURLException me) {
                throw new MojoExecutionException("Error configuring deployment classpath. " + me);
            }

            return answer;

        }

        clientTestClasspath = new HashMap();

        Set artifacts = getClientTestClasspathArtifacts(projectDependencies, versionlessKeys);
        for (Artifact dependency : artifacts) {
            try {
                String constituent = dependency.getFile().toURI().toURL().toExternalForm();
                String dependencyTrail = dependency.getDependencyTrail() == null ? "none" : dependency
                        .getDependencyTrail().toString();
                clientTestClasspath.put(constituent, dependencyTrail);
            } catch (IOException ie) {
                throw new MojoExecutionException("Error configuring deployment classpath. " + ie);
            }
        }

        // consitituents within clientTestClasspath list are static. add dynamic
        // consitituent, i.e. test classes dir to a separate list and return

        Map answer = new HashMap(clientTestClasspath);
        try {
            answer.put(clientTestClassesDirectory.toURI().toURL().toExternalForm(), "none");
        } catch (MalformedURLException me) {
            throw new MojoExecutionException("Error configuring deployment classpath. " + me);
        }

        return answer;

    }

    public Set getClientTestClasspathArtifacts(Set projectDependencies, Set versionlessKeys) throws MojoExecutionException {

        Set result = new HashSet();

        // retrieve optional configuration, which if defined, identifies which
        // dependencies with test scope are added to client test classpath, i.e.
        // as opposed to system test classpath

        Set clientTestDependencies = null;
        if (test != null && test.getClient() != null) {
            clientTestDependencies = new HashSet();
            for (org.bluestemsoftware.open.eoa.plugin.surefire.cfg.Dependency dep : test.getClient()) {
                clientTestDependencies.add(dep.getGroupId() + ":" + dep.getArtifactId());
            }
        }

        // if client test dependencies defined via plugin configuration, verify
        // the ref matches a test scoped artifact within parent project

        if (clientTestDependencies != null) {
            Set testArtifacts = new HashSet();
            for (Artifact artifact : projectDependencies) {
                if (!artifact.getScope().equals(Artifact.SCOPE_TEST)) {
                    continue;
                }
                if (!artifact.getType().equals("jar")) {
                    continue;
                }
                testArtifacts.add(artifact.getGroupId() + ":" + artifact.getArtifactId());
            }
            for (String dep : clientTestDependencies) {
                if (!testArtifacts.contains(dep)) {
                    throw new MojoExecutionException("client test dependency "
                            + dep
                            + ", defined via plugin configuration must be defined as an"
                            + " artifact within parent project with scope 'test'.");
                }
            }
        }

        Set explicitArtifacts = new HashSet();

        for (Artifact dependency : projectDependencies) {

            if (!dependency.getScope().equals(Artifact.SCOPE_TEST)) {
                continue;
            }

            if (!dependency.getType().equals("jar")) {
                continue;
            }

            // if dependencies are given via plugin configuration and ref
            // is not defined, skip it. if it is defined, or if no configuration
            // was provided, include it

            if (clientTestDependencies != null) {
                String ref = dependency.getGroupId() + ":" + dependency.getArtifactId();
                if (!clientTestDependencies.contains(ref)) {
                    logger.debug("test scoped artifact "
                            + ref
                            + ", not defined as a dependency within plugin configuration."
                            + " excluding from client tests classpath.");
                    continue;
                }
            }

            // add artifact to result set before converting so that it will
            // retain test scope, then convert to runtime scope and add to
            // explicit artifacts set so that it will be resolved transitively

            versionlessKeys.add(ArtifactUtils.versionlessKey(dependency));
            DependencyHelper.resolveArtifact(dependency, remoteRepositories, artifactResolver, localRepository);
            result.add(dependency);
            explicitArtifacts.add(adjustTestScope(dependency));

        }

        // take all explicity declared artifacts which qualify as a client test
        // artifact and resolve transitively. note that maven will handle
        // version conflict resolution for transitive artifacts with same key

        Set transitiveArtifacts;
        try {
            transitiveArtifacts = resolveArtifactsTransitively(explicitArtifacts);
        } catch (Exception ex) {
            throw new MojoExecutionException("Error configuring client classpath. " + ex);
        }

        for (Artifact transitiveArtifact : transitiveArtifacts) {
            String key = ArtifactUtils.versionlessKey(transitiveArtifact);
            if (!versionlessKeys.contains(key)) {
                versionlessKeys.add(key);
                result.add(transitiveArtifact);
            }
        }

        return result;

    }

    private Set resolveArtifactsTransitively(Set artifacts) throws MojoExecutionException {

        List listeners = new ArrayList();
        listeners.add(new WarningResolutionListener(logger));

        // set scope filter according to classpath type. if classpath is to be used
        // for compilation only, set scope to compile. if classpath is to be used
        // as -classpath argument for jvm, set to runtime scope

        String scope = null;
        if (isRuntime) {
            scope = Artifact.SCOPE_RUNTIME;
        } else {
            scope = Artifact.SCOPE_COMPILE;
        }

        ArtifactResolutionResult arr;
        try {
            AndArtifactFilter artifactFilter = new AndArtifactFilter();
            artifactFilter.add(new ScopeArtifactFilter(scope));
            artifactFilter.add(new TypeArtifactFilter("jar"));
            Map managedVersionMap = createManagedVersionMap(project);
            Artifact dummy = artifactFactory.createBuildArtifact("dummy", "dummy", "1.0", "jar");
            arr = artifactCollector.collect(artifacts, dummy, managedVersionMap, localRepository,
                    remoteRepositories, metadataSource, artifactFilter, listeners);
        } catch (Exception ex) {
            throw new MojoExecutionException("Error resolving artifacts. " + ex);
        }

        Set resolvedArtifacts = new HashSet();
        Iterator itr = arr.getArtifactResolutionNodes().iterator();
        while (itr.hasNext()) {
            ResolutionNode node = (ResolutionNode)itr.next();
            Artifact ra = node.getArtifact();
            DependencyHelper.resolveArtifact(ra, node.getRemoteRepositories(), artifactResolver, localRepository);
            resolvedArtifacts.add(ra);
        }

        return resolvedArtifacts;
    }

    private Map createManagedVersionMap(MavenProject extensionFactoryProject) throws InvalidVersionSpecificationException {
        DependencyManagement dependencyManagement = extensionFactoryProject.getDependencyManagement();
        if (dependencyManagement == null) {
            return new HashMap();
        }
        if (dependencyManagement.getDependencies() == null) {
            return new HashMap();
        }
        Map managedVersionMap = new HashMap();
        Iterator itr = dependencyManagement.getDependencies().iterator();
        while (itr.hasNext()) {
            Dependency d = (Dependency)itr.next();
            VersionRange versionRange = VersionRange.createFromVersionSpec(d.getVersion());
            Artifact artifact = artifactFactory.createDependencyArtifact(d.getGroupId(), d.getArtifactId(),
                    versionRange, d.getType(), d.getClassifier(), d.getScope(), d.isOptional());
            managedVersionMap.put(d.getManagementKey(), artifact);
        }
        return managedVersionMap;
    }

    private Artifact adjustTestScope(Artifact testArtifact) throws MojoExecutionException {
        String groupID = testArtifact.getGroupId();
        String artifactID = testArtifact.getArtifactId();
        String version = testArtifact.getVersion();
        String type = testArtifact.getType();

        String scope = null;
        if (isRuntime) {
            scope = Artifact.SCOPE_RUNTIME;
        } else {
            scope = Artifact.SCOPE_COMPILE;
        }

        Artifact converted = artifactFactory.createArtifact(groupID, artifactID, version, scope, type);
        try {
            DependencyHelper.resolveArtifact(converted, remoteRepositories, artifactResolver, localRepository);
        } catch (Exception ex) {
            throw new MojoExecutionException("Error converting test artifact to runtime scope. " + ex);
        }
        return converted;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy