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 * @see PreorderDependencyNodeConsumerVisitor
040 * @see PostorderDependencyNodeConsumerVisitor
041 * @see LevelOrderDependencyNodeConsumerVisitor
042 * @since 2.0.0
043 */
044public final class NodeListGenerator implements Consumer<DependencyNode> {
045
046    private final ArrayList<DependencyNode> nodes;
047
048    public NodeListGenerator() {
049        nodes = new ArrayList<>(128);
050    }
051
052    @Override
053    public void accept(DependencyNode dependencyNode) {
054        nodes.add(dependencyNode);
055    }
056
057    /**
058     * Gets the list of dependency nodes that was generated during the graph traversal.
059     *
060     * @return the list of dependency nodes, never {@code null}
061     */
062    public List<DependencyNode> getNodes() {
063        return nodes;
064    }
065
066    /**
067     * Gets the list of dependency nodes that was generated during the graph traversal and have {@code non-null}
068     * {@link DependencyNode#getDependency()}.
069     *
070     * @return the list of dependency nodes having dependency, never {@code null}
071     */
072    public List<DependencyNode> getNodesWithDependencies() {
073        return getNodesWithDependencies(getNodes());
074    }
075
076    /**
077     * Gets the dependencies seen during the graph traversal.
078     *
079     * @param includeUnresolved whether unresolved dependencies shall be included in the result or not
080     * @return the list of dependencies, never {@code null}
081     */
082    public List<Dependency> getDependencies(boolean includeUnresolved) {
083        return getDependencies(getNodes(), includeUnresolved);
084    }
085
086    /**
087     * Gets the artifacts associated with the list of dependency nodes generated during the graph traversal.
088     *
089     * @param includeUnresolved whether unresolved artifacts shall be included in the result or not
090     * @return the list of artifacts, never {@code null}
091     */
092    public List<Artifact> getArtifacts(boolean includeUnresolved) {
093        return getArtifacts(getNodes(), includeUnresolved);
094    }
095
096    /**
097     * Gets the files of resolved artifacts seen during the graph traversal.
098     *
099     * @return the list of artifact files, never {@code null}
100     * @deprecated use {@link #getPaths()} instead
101     */
102    @Deprecated
103    public List<File> getFiles() {
104        return getFiles(getNodes());
105    }
106
107    /**
108     * Gets the files of resolved artifacts seen during the graph traversal.
109     *
110     * @return the list of artifact files, never {@code null}
111     * @since 2.0.0
112     */
113    public List<Path> getPaths() {
114        return getPaths(getNodes());
115    }
116
117    /**
118     * Gets a class path by concatenating the artifact files of the visited dependency nodes. Nodes with unresolved
119     * artifacts are automatically skipped.
120     *
121     * @return the class path, using the platform-specific path separator, never {@code null}
122     */
123    public String getClassPath() {
124        return getClassPath(getNodes());
125    }
126
127    static List<DependencyNode> getNodesWithDependencies(List<DependencyNode> nodes) {
128        return nodes.stream().filter(d -> d.getDependency() != null).collect(toList());
129    }
130
131    static List<Dependency> getDependencies(List<DependencyNode> nodes, boolean includeUnresolved) {
132        return getNodesWithDependencies(nodes).stream()
133                .map(DependencyNode::getDependency)
134                .filter(d -> includeUnresolved || d.getArtifact().getPath() != null)
135                .collect(toList());
136    }
137
138    static List<Artifact> getArtifacts(List<DependencyNode> nodes, boolean includeUnresolved) {
139        return getNodesWithDependencies(nodes).stream()
140                .map(d -> d.getDependency().getArtifact())
141                .filter(artifact -> includeUnresolved || artifact.getPath() != null)
142                .collect(toList());
143    }
144
145    @Deprecated
146    static List<File> getFiles(List<DependencyNode> nodes) {
147        return getNodesWithDependencies(nodes).stream()
148                .map(d -> d.getDependency().getArtifact().getFile())
149                .filter(Objects::nonNull)
150                .collect(toList());
151    }
152
153    static List<Path> getPaths(List<DependencyNode> nodes) {
154        return getNodesWithDependencies(nodes).stream()
155                .map(d -> d.getDependency().getArtifact().getPath())
156                .filter(Objects::nonNull)
157                .collect(toList());
158    }
159
160    static String getClassPath(List<DependencyNode> nodes) {
161        return getPaths(nodes).stream()
162                .map(Path::toAbsolutePath)
163                .map(Path::toString)
164                .collect(joining(File.pathSeparator));
165    }
166}