Package com.chaschev.install.jcabi

Source Code of com.chaschev.install.jcabi.Classpath

/**
* Copyright (c) 2012-2013, JCabi.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: 1) Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer. 2) Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution. 3) Neither the name of the jcabi.com nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.chaschev.install.jcabi;

import com.jcabi.aspects.Loggable;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.model.Dependency;
import org.apache.maven.project.MavenProject;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.resolution.ArtifactResult;
import org.sonatype.aether.resolution.DependencyResolutionException;
import org.sonatype.aether.util.artifact.DefaultArtifact;
import org.sonatype.aether.util.artifact.JavaScopes;

import javax.validation.constraints.NotNull;
import java.io.File;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
* A classpath of a Maven Project.
*
* <p>It is a convenient wrapper around {@link Aether} class, that allows you
* to fetch all dependencies of a Maven Project by their scope. The class
* implements a {@link java.util.Set} of {@link java.io.File}s and can be used like this:
*
* <pre> String classpath = StringUtils.join(
*   new Classpath(project, localRepo, "runtime")
*   System.getProperty("path.separator")
* );</pre>
*
* <p>Important to notice that this class resolves artifacts from repositories
* only once per instance. It means that once resolved the list of files
* is cached and never flushes. In order to resolve again (if you think that
* content of repositories is changed), make a new instance of the class.
*
* @author Yegor Bugayenko (yegor@tpc2.com)
* @version $Id$
* @since 0.7.16
* @see Aether
* @checkstyle ClassDataAbstractionCoupling (500 lines)
*/
@EqualsAndHashCode(callSuper = false, of = { "project", "aether", "scopes" })
@Loggable(
    value = Loggable.DEBUG,
    limit = 1, unit = TimeUnit.MINUTES,
    trim = false
)
public final class Classpath extends AbstractSet<File> implements Set<File> {

    /**
     * Maven Project.
     */
    private final transient MavenProject project;

    /**
     * Aether to work with.
     */
    private final transient Aether aether;

    /**
     * Artifact scopes to include.
     */
    private final transient Set<String> scopes;

    /**
     * Public ctor.
     * @param prj The Maven project
     * @param repo Local repository location (directory path)
     * @param scp The scope to use, e.g. "runtime" or "compile"
     */
    public Classpath(@NotNull final MavenProject prj,
        @NotNull final File repo, @NotNull final String scp) {
        this(prj, repo, Arrays.asList(scp));
    }

    /**
     * Public ctor.
     * @param prj The Maven project
     * @param repo Local repository location (directory path)
     * @param scps All scopes to include
     */
    public Classpath(@NotNull final MavenProject prj,
        @NotNull final File repo, @NotNull final Collection<String> scps) {
        super();
        this.project = prj;
        this.aether = new Aether(prj, repo);
        this.scopes = new HashSet<String>(scps);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return StringUtils.join(this.roots(), "\n");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<File> iterator() {
        try {
            return this.fetch().iterator();
        } catch (DependencyResolutionException ex) {
            throw new IllegalStateException(ex);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int size() {
        try {
            return this.fetch().size();
        } catch (DependencyResolutionException ex) {
            throw new IllegalStateException(ex);
        }
    }

    /**
     * Fetch all files found (JAR, ZIP, directories, etc).
     * @return Set of files
     * @throws org.sonatype.aether.resolution.DependencyResolutionException If can't resolve
     */
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
    private Set<File> fetch() throws DependencyResolutionException {
        final Set<File> files = new LinkedHashSet<File>(0);
        for (String path : this.elements()) {
            files.add(new File(path));
        }
        for (Artifact artifact : this.artifacts()) {
            files.add(artifact.getFile());
        }
        return files;
    }

    /**
     * Get Maven Project elements.
     * @return Collection of them
     */
    private Collection<String> elements() {
        final Collection<String> elements = new LinkedList<String>();
        try {
            if (this.scopes.contains(JavaScopes.TEST)) {
                elements.addAll(this.project.getTestClasspathElements());
            }
            if (this.scopes.contains(JavaScopes.RUNTIME)) {
                elements.addAll(this.project.getRuntimeClasspathElements());
            }
            if (this.scopes.contains(JavaScopes.SYSTEM)) {
                elements.addAll(this.project.getSystemClasspathElements());
            }
            if (this.scopes.contains(JavaScopes.COMPILE)
                || this.scopes.contains(JavaScopes.PROVIDED)) {
                elements.addAll(this.project.getCompileClasspathElements());
            }
        } catch (DependencyResolutionRequiredException ex) {
            throw new IllegalStateException("Failed to read classpath", ex);
        }
        return elements;
    }

    /**
     * Set of unique artifacts, which should be available in classpath.
     *
     * <p>This method gets a full list of artifacts of the project,
     * including their transitive dependencies.
     *
     * @return The set of artifacts
     * @throws org.sonatype.aether.resolution.DependencyResolutionException If can't resolve some of them
     */
    private Set<Artifact> artifacts() throws DependencyResolutionException {
        final Set<Artifact> artifacts = new LinkedHashSet<Artifact>(0);
        for (RootArtifact root : this.roots()) {
            for (ArtifactResult child : root.children()) {
                Artifact childArtifact = child.getArtifact();
                if (Classpath.contains(childArtifact, artifacts)) {
                    continue;
                }
                if (root.excluded(childArtifact)) {
                    continue;
                }
                artifacts.add(childArtifact);
            }
        }
        return artifacts;
    }

    /**
     * Convert dependencies to root artifacts.
     *
     * <p>The method is getting a list of artifacts from Maven Project, without
     * their transitive dependencies (that's why they are called "root"
     * artifacts).
     *
     * @return The set of root artifacts
     */
    private Set<RootArtifact> roots() {
        final Set<RootArtifact> roots = new LinkedHashSet<RootArtifact>(0);
        for (Dependency dep : this.project.getDependencies()) {
            if (!this.scopes.contains(dep.getScope())) {
                continue;
            }
            roots.add(this.root(dep));
        }
        return roots;
    }

    /**
     * Convert dependency to root artifact.
     * @param dep Dependency
     * @return Root artifact
     */
    private RootArtifact root(final Dependency dep) {
        return new RootArtifact(
            this.aether,
            new DefaultArtifact(
                dep.getGroupId(),
                dep.getArtifactId(),
                dep.getClassifier(),
                dep.getType(),
                dep.getVersion()
            ),
            dep.getExclusions()
        );
    }

    /**
     * Artifact exists in collection?
     * @param artifact The artifact
     * @param artifacts Collection of them
     * @return TRUE if it is already there
     */
    private static boolean contains(final Artifact artifact,
        final Collection<Artifact> artifacts) {
        boolean contains = false;
        for (Artifact exists : artifacts) {
            if (artifact.getArtifactId().equals(exists.getArtifactId())
                && artifact.getGroupId().equals(exists.getGroupId())
                && artifact.getClassifier().equals(exists.getClassifier())) {
                contains = true;
                break;
            }
        }
        return contains;
    }

}
TOP

Related Classes of com.chaschev.install.jcabi.Classpath

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.