001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.util.graph.visitor;
020
021import java.io.File;
022import java.nio.file.Path;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.Objects;
026import java.util.function.Consumer;
027
028import org.eclipse.aether.artifact.Artifact;
029import org.eclipse.aether.graph.Dependency;
030import org.eclipse.aether.graph.DependencyNode;
031
032import static java.util.stream.Collectors.joining;
033import static java.util.stream.Collectors.toList;
034
035/**
036 * Node list generator usable with different traversing strategies. It is wrapped {@link List}{@code <DependencyNode>} but
037 * offers several transformations, that are handy.
038 *
039 * @since 2.0.0
040 *
041 * @see PreorderDependencyNodeConsumerVisitor
042 * @see PostorderDependencyNodeConsumerVisitor
043 * @see LevelOrderDependencyNodeConsumerVisitor
044 */
045public final class NodeListGenerator implements Consumer<DependencyNode> {
046
047    private final ArrayList<DependencyNode> nodes;
048
049    public NodeListGenerator() {
050        nodes = new ArrayList<>(128);
051    }
052
053    @Override
054    public void accept(DependencyNode dependencyNode) {
055        nodes.add(dependencyNode);
056    }
057
058    /**
059     * Gets the list of dependency nodes that was generated during the graph traversal.
060     *
061     * @return The list of dependency nodes, never {@code null}.
062     */
063    public List<DependencyNode> getNodes() {
064        return nodes;
065    }
066
067    /**
068     * Gets the list of dependency nodes that was generated during the graph traversal and have {@code non-null}
069     * {@link DependencyNode#getDependency()}.
070     *
071     * @return The list of dependency nodes having dependency, never {@code null}.
072     */
073    public List<DependencyNode> getNodesWithDependencies() {
074        return getNodesWithDependencies(getNodes());
075    }
076
077    /**
078     * Gets the dependencies seen during the graph traversal.
079     *
080     * @param includeUnresolved Whether unresolved dependencies shall be included in the result or not.
081     * @return The list of dependencies, never {@code null}.
082     */
083    public List<Dependency> getDependencies(boolean includeUnresolved) {
084        return getDependencies(getNodes(), includeUnresolved);
085    }
086
087    /**
088     * Gets the artifacts associated with the list of dependency nodes generated during the graph traversal.
089     *
090     * @param includeUnresolved Whether unresolved artifacts shall be included in the result or not.
091     * @return The list of artifacts, never {@code null}.
092     */
093    public List<Artifact> getArtifacts(boolean includeUnresolved) {
094        return getArtifacts(getNodes(), includeUnresolved);
095    }
096
097    /**
098     * Gets the files of resolved artifacts seen during the graph traversal.
099     *
100     * @return The list of artifact files, never {@code null}.
101     * @deprecated Use {@link #getPaths()} instead.
102     */
103    @Deprecated
104    public List<File> getFiles() {
105        return getFiles(getNodes());
106    }
107
108    /**
109     * Gets the files of resolved artifacts seen during the graph traversal.
110     *
111     * @return The list of artifact files, never {@code null}.
112     * @since 2.0.0
113     */
114    public List<Path> getPaths() {
115        return getPaths(getNodes());
116    }
117
118    /**
119     * Gets a class path by concatenating the artifact files of the visited dependency nodes. Nodes with unresolved
120     * artifacts are automatically skipped.
121     *
122     * @return The class path, using the platform-specific path separator, never {@code null}.
123     */
124    public String getClassPath() {
125        return getClassPath(getNodes());
126    }
127
128    static List<DependencyNode> getNodesWithDependencies(List<DependencyNode> nodes) {
129        return nodes.stream().filter(d -> d.getDependency() != null).collect(toList());
130    }
131
132    static List<Dependency> getDependencies(List<DependencyNode> nodes, boolean includeUnresolved) {
133        return getNodesWithDependencies(nodes).stream()
134                .map(DependencyNode::getDependency)
135                .filter(d -> includeUnresolved || d.getArtifact().getPath() != null)
136                .collect(toList());
137    }
138
139    static List<Artifact> getArtifacts(List<DependencyNode> nodes, boolean includeUnresolved) {
140        return getNodesWithDependencies(nodes).stream()
141                .map(d -> d.getDependency().getArtifact())
142                .filter(artifact -> includeUnresolved || artifact.getPath() != null)
143                .collect(toList());
144    }
145
146    @Deprecated
147    static List<File> getFiles(List<DependencyNode> nodes) {
148        return getNodesWithDependencies(nodes).stream()
149                .map(d -> d.getDependency().getArtifact().getFile())
150                .filter(Objects::nonNull)
151                .collect(toList());
152    }
153
154    static List<Path> getPaths(List<DependencyNode> nodes) {
155        return getNodesWithDependencies(nodes).stream()
156                .map(d -> d.getDependency().getArtifact().getPath())
157                .filter(Objects::nonNull)
158                .collect(toList());
159    }
160
161    static String getClassPath(List<DependencyNode> nodes) {
162        return getPaths(nodes).stream()
163                .map(Path::toAbsolutePath)
164                .map(Path::toString)
165                .collect(joining(File.pathSeparator));
166    }
167}