Coverage Report - com.jcabi.aether.MavenClasspath
 
Classes in this File Line Coverage Branch Coverage Complexity
MavenClasspath
53%
33/62
23%
11/46
2.75
MavenClasspath$1
50%
1/2
N/A
2.75
MavenClasspath$AjcClosure1
100%
1/1
N/A
2.75
MavenClasspath$AjcClosure3
0%
0/1
N/A
2.75
 
 1  2
 /**
 2  
  * Copyright (c) 2012-2014, jcabi.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the jcabi.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.jcabi.aether;
 31  
 
 32  
 import com.jcabi.aspects.Loggable;
 33  
 import java.io.File;
 34  
 import java.util.AbstractSet;
 35  
 import java.util.Arrays;
 36  
 import java.util.Collection;
 37  
 import java.util.HashSet;
 38  
 import java.util.Iterator;
 39  
 import java.util.LinkedHashSet;
 40  
 import java.util.LinkedList;
 41  
 import java.util.Set;
 42  
 import java.util.concurrent.TimeUnit;
 43  
 import javax.validation.constraints.NotNull;
 44  
 import lombok.EqualsAndHashCode;
 45  
 import org.apache.commons.lang3.StringUtils;
 46  
 import org.apache.maven.artifact.Artifact;
 47  
 import org.apache.maven.artifact.DefaultArtifact;
 48  
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 49  
 import org.apache.maven.artifact.handler.DefaultArtifactHandler;
 50  
 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
 51  
 import org.apache.maven.execution.MavenSession;
 52  
 import org.apache.maven.model.Dependency;
 53  
 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
 54  
 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
 55  
 import org.apache.maven.shared.dependency.graph.DependencyNode;
 56  
 
 57  
 /**
 58  
  * A classpath of a Maven Project.
 59  
  *
 60  
  * @author Krzysztof Krason (Krzysztof.Krason@gmail.com)
 61  
  * @version $Id$
 62  
  * @checkstyle ClassDataAbstractionCoupling (500 lines)
 63  
  */
 64  2
 @EqualsAndHashCode(callSuper = false, of = { "builder", "scopes" })
 65  
 @Loggable(
 66  
     value = Loggable.DEBUG,
 67  
     limit = 1, unit = TimeUnit.MINUTES,
 68  
     trim = false
 69  
 )
 70  0
 public final class MavenClasspath extends AbstractSet<File> {
 71  
 
 72  
     /**
 73  
      * Maven test scope.
 74  
      */
 75  
     public static final String TEST_SCOPE = "test";
 76  
 
 77  
     /**
 78  
      * Maven runtime scope.
 79  
      */
 80  
     public static final String RUNTIME_SCOPE = "runtime";
 81  
 
 82  
     /**
 83  
      * Maven system scope.
 84  
      */
 85  
     public static final String SYSTEM_SCOPE = "system";
 86  
 
 87  
     /**
 88  
      * Maven compile scope.
 89  
      */
 90  
     public static final String COMPILE_SCOPE = "compile";
 91  
 
 92  
     /**
 93  
      * Maven provided scope.
 94  
      */
 95  
     public static final String PROVIDED_SCOPE = "provided";
 96  
 
 97  
     /**
 98  
      * Artifact scopes to include.
 99  
      */
 100  
     private final transient Set<String> scopes;
 101  
 
 102  
     /**
 103  
      * Dependency graph builder.
 104  
      */
 105  
     private final transient DependencyGraphBuilder builder;
 106  
 
 107  
     /**
 108  
      * The current repository/network configuration of Maven.
 109  
      */
 110  
     private final transient MavenSession session;
 111  
 
 112  
     /**
 113  
      * Public ctor.
 114  
      * @param bldr Dependency graph builder.
 115  
      * @param sess Maven session.
 116  
      * @param scp The scope to use, e.g. "runtime" or "compile"
 117  
      */
 118  
     public MavenClasspath(@NotNull final DependencyGraphBuilder bldr,
 119  
         @NotNull final MavenSession sess,
 120  
         @NotNull final String scp) {
 121  2
         this(bldr, sess, Arrays.asList(scp));
 122  2
     }
 123  
 
 124  
     /**
 125  
      * Public ctor.
 126  
      * @param bldr Dependency graph builder.
 127  
      * @param sess Maven session.
 128  
      * @param scps All scopes to include
 129  
      */
 130  
     public MavenClasspath(@NotNull final DependencyGraphBuilder bldr,
 131  
         @NotNull final MavenSession sess,
 132  
         @NotNull final Collection<String> scps) {
 133  2
         super();
 134  2
         this.builder = bldr;
 135  2
         this.session = sess;
 136  2
         this.scopes = new HashSet<String>(scps);
 137  2
     }
 138  
 
 139  
     /**
 140  
      * {@inheritDoc}
 141  
      */
 142  
     @Override
 143  
     public String toString() {
 144  0
         return StringUtils.join(this.roots(), "\n");
 145  
     }
 146  
 
 147  
     /**
 148  
      * {@inheritDoc}
 149  
      */
 150  
     @Override
 151  
     public Iterator<File> iterator() {
 152  4
         return this.fetch().iterator();
 153  
     }
 154  
 
 155  
     /**
 156  
      * {@inheritDoc}
 157  
      */
 158  
     @Override
 159  
     public int size() {
 160  0
         return this.fetch().size();
 161  
     }
 162  
 
 163  
     /**
 164  
      * Fetch all files found (JAR, ZIP, directories, etc).
 165  
      * @return Set of files
 166  
      */
 167  
     @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
 168  
     private Set<File> fetch() {
 169  2
         final Set<File> files = new LinkedHashSet<File>(0);
 170  2
         for (final String path : this.elements()) {
 171  2
             files.add(new File(path));
 172  2
         }
 173  
         try {
 174  2
             files.addAll(this.dependencies(this.graph(), this.scopes));
 175  0
         } catch (final DependencyGraphBuilderException ex) {
 176  0
             throw new IllegalStateException(ex);
 177  2
         }
 178  2
         return files;
 179  
     }
 180  
 
 181  
     /**
 182  
      * Build dependency graph.
 183  
      * @return Root of dependency graph.
 184  
      * @throws DependencyGraphBuilderException In case of error.
 185  
      */
 186  
     private DependencyNode graph() throws DependencyGraphBuilderException {
 187  2
         return this.builder.buildDependencyGraph(
 188  
             this.session.getCurrentProject(),
 189  2
             new ArtifactFilter() {
 190  
                 @Override
 191  
                 public boolean include(
 192  
                     final Artifact artifact) {
 193  0
                     return MavenClasspath.this.scopes
 194  
                         .contains(artifact.getScope());
 195  
                 }
 196  
             }
 197  
         );
 198  
     }
 199  
 
 200  
     /**
 201  
      * Convert dependencies to root artifacts.
 202  
      *
 203  
      * <p>The method is getting a list of artifacts from Maven Project, without
 204  
      * their transitive dependencies (that's why they are called "root"
 205  
      * artifacts).
 206  
      *
 207  
      * @return The set of root artifacts
 208  
      */
 209  
     private Set<MavenRootArtifact> roots() {
 210  0
         final Set<MavenRootArtifact> roots =
 211  
             new LinkedHashSet<MavenRootArtifact>(0);
 212  
         for (final Dependency dep
 213  0
             : this.session.getCurrentProject().getDependencies()) {
 214  0
             if (!this.scopes.contains(dep.getScope())) {
 215  0
                 continue;
 216  
             }
 217  0
             roots.add(this.root(dep));
 218  0
         }
 219  0
         return roots;
 220  
     }
 221  
 
 222  
     /**
 223  
      * Convert dependency to root artifact.
 224  
      * @param dep Dependency
 225  
      * @return Root artifact
 226  
      */
 227  
     private MavenRootArtifact root(final Dependency dep) {
 228  0
         final DefaultArtifact artifact = new DefaultArtifact(
 229  
             dep.getGroupId(),
 230  
             dep.getArtifactId(),
 231  
             dep.getVersion(),
 232  
             dep.getScope(),
 233  
             dep.getType(),
 234  
             dep.getClassifier(),
 235  
             new DefaultArtifactHandler()
 236  
         );
 237  
         try {
 238  0
             final Collection<Artifact> children = new LinkedList<Artifact>();
 239  0
             for (final DependencyNode child : this.graph().getChildren()) {
 240  0
                 children.add(child.getArtifact());
 241  0
             }
 242  0
             return new MavenRootArtifact(
 243  
                 artifact,
 244  
                 dep.getExclusions(),
 245  
                 children
 246  
             );
 247  0
         } catch (final DependencyGraphBuilderException ex) {
 248  0
             throw new IllegalStateException(ex);
 249  
         }
 250  
     }
 251  
 
 252  
     /**
 253  
      * Get Maven Project elements.
 254  
      * @return Collection of them
 255  
      */
 256  
     private Collection<String> elements() {
 257  2
         final Collection<String> elements = new LinkedList<String>();
 258  
         try {
 259  2
             if (this.scopes.contains(TEST_SCOPE)) {
 260  2
                 elements.addAll(
 261  
                     this.session.getCurrentProject().getTestClasspathElements()
 262  
                 );
 263  
             }
 264  2
             if (this.scopes.contains(RUNTIME_SCOPE)) {
 265  0
                 elements.addAll(
 266  
                     this.session.getCurrentProject()
 267  
                         .getRuntimeClasspathElements()
 268  
                 );
 269  
             }
 270  2
             if (this.scopes.contains(SYSTEM_SCOPE)) {
 271  0
                 elements.addAll(
 272  
                     this.session.getCurrentProject()
 273  
                         .getSystemClasspathElements()
 274  
                 );
 275  
             }
 276  2
             if (this.scopes.contains(COMPILE_SCOPE)
 277  
                 || this.scopes.contains(PROVIDED_SCOPE)) {
 278  0
                 elements.addAll(
 279  
                     this.session.getCurrentProject()
 280  
                         .getCompileClasspathElements()
 281  
                 );
 282  
             }
 283  0
         } catch (final DependencyResolutionRequiredException ex) {
 284  0
             throw new IllegalStateException("Failed to read classpath", ex);
 285  2
         }
 286  2
         return elements;
 287  
     }
 288  
 
 289  
     /**
 290  
      * Retrieve dependencies for from given node and scope.
 291  
      * @param node Node to traverse.
 292  
      * @param scps Scopes to use.
 293  
      * @return Collection of dependency files.
 294  
      */
 295  
     private Collection<File> dependencies(final DependencyNode node,
 296  
         final Collection<String> scps) {
 297  2
         final Artifact artifact = node.getArtifact();
 298  2
         final Collection<File> files = new LinkedList<File>();
 299  2
         if ((artifact.getScope() == null)
 300  
             || scps.contains(artifact.getScope())) {
 301  2
             if (artifact.getScope() == null) {
 302  2
                 files.add(artifact.getFile());
 303  
             } else {
 304  0
                 files.add(
 305  
                     this.session.getLocalRepository().find(artifact).getFile()
 306  
                 );
 307  
             }
 308  2
             for (final DependencyNode child : node.getChildren()) {
 309  0
                 if (child.getArtifact().compareTo(node.getArtifact()) != 0) {
 310  0
                     files.addAll(this.dependencies(child, scps));
 311  
                 }
 312  0
             }
 313  
         }
 314  2
         return files;
 315  
     }
 316  
 }
 317