View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.graph;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Comparator;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Objects;
30  import java.util.Set;
31  import java.util.stream.Collectors;
32  
33  import org.apache.maven.execution.ProjectDependencyGraph;
34  import org.apache.maven.project.CycleDetectedException;
35  import org.apache.maven.project.DuplicateProjectException;
36  import org.apache.maven.project.MavenProject;
37  import org.apache.maven.project.ProjectSorter;
38  
39  /**
40   * Describes the interdependencies between projects in the reactor.
41   *
42   */
43  public class DefaultProjectDependencyGraph implements ProjectDependencyGraph {
44  
45      private final ProjectSorter sorter;
46  
47      private final List<MavenProject> allProjects;
48  
49      private final Map<MavenProject, Integer> order;
50  
51      private final Map<String, MavenProject> projects;
52  
53      /**
54       * Creates a new project dependency graph based on the specified projects.
55       *
56       * @param projects The projects to create the dependency graph with
57       * @throws DuplicateProjectException
58       * @throws CycleDetectedException
59       */
60      public DefaultProjectDependencyGraph(Collection<MavenProject> projects)
61              throws CycleDetectedException, DuplicateProjectException {
62          this(projects, projects);
63      }
64  
65      /**
66       * Creates a new project dependency graph based on the specified projects.
67       *
68       * @param allProjects All collected projects.
69       * @param projects    The projects to create the dependency graph with.
70       * @throws DuplicateProjectException
71       * @throws CycleDetectedException
72       * @since 3.5.0
73       * @deprecated Use {@link #DefaultProjectDependencyGraph(Collection, Collection)} instead.
74       */
75      @Deprecated
76      public DefaultProjectDependencyGraph(List<MavenProject> allProjects, Collection<MavenProject> projects)
77              throws CycleDetectedException, DuplicateProjectException {
78          this((Collection<MavenProject>) allProjects, projects);
79      }
80  
81      /**
82       * Creates a new project dependency graph based on the specified projects.
83       *
84       * @param allProjects All collected projects.
85       * @param projects    The projects to create the dependency graph with.
86       * @throws DuplicateProjectException
87       * @throws CycleDetectedException
88       * @since 4.0.0
89       */
90      public DefaultProjectDependencyGraph(Collection<MavenProject> allProjects, Collection<MavenProject> projects)
91              throws CycleDetectedException, DuplicateProjectException {
92          this.allProjects = Collections.unmodifiableList(new ArrayList<>(allProjects));
93          this.sorter = new ProjectSorter(projects);
94          this.order = new HashMap<>();
95          this.projects = new HashMap<>();
96          List<MavenProject> sorted = this.sorter.getSortedProjects();
97          for (int index = 0; index < sorted.size(); index++) {
98              MavenProject project = sorted.get(index);
99              String id = ProjectSorter.getId(project);
100             this.projects.put(id, project);
101             this.order.put(project, index);
102         }
103     }
104 
105     /**
106      * @since 3.5.0
107      */
108     public List<MavenProject> getAllProjects() {
109         return this.allProjects;
110     }
111 
112     public List<MavenProject> getSortedProjects() {
113         return new ArrayList<>(sorter.getSortedProjects());
114     }
115 
116     public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
117         Objects.requireNonNull(project, "project cannot be null");
118 
119         Set<String> projectIds = new HashSet<>();
120 
121         getDownstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
122 
123         return getSortedProjects(projectIds);
124     }
125 
126     private void getDownstreamProjects(String projectId, Set<String> projectIds, boolean transitive) {
127         for (String id : sorter.getDependents(projectId)) {
128             if (projectIds.add(id) && transitive) {
129                 getDownstreamProjects(id, projectIds, transitive);
130             }
131         }
132     }
133 
134     public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
135         Objects.requireNonNull(project, "project cannot be null");
136 
137         Set<String> projectIds = new HashSet<>();
138 
139         getUpstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
140 
141         return getSortedProjects(projectIds);
142     }
143 
144     private void getUpstreamProjects(String projectId, Collection<String> projectIds, boolean transitive) {
145         for (String id : sorter.getDependencies(projectId)) {
146             if (projectIds.add(id) && transitive) {
147                 getUpstreamProjects(id, projectIds, transitive);
148             }
149         }
150     }
151 
152     private List<MavenProject> getSortedProjects(Set<String> projectIds) {
153         return projectIds.stream()
154                 .map(projects::get)
155                 .sorted(Comparator.comparingInt(order::get))
156                 .collect(Collectors.toList());
157     }
158 
159     @Override
160     public String toString() {
161         return sorter.getSortedProjects().toString();
162     }
163 }