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  import org.apache.maven.execution.ProjectDependencyGraph;
33  import org.apache.maven.project.DuplicateProjectException;
34  import org.apache.maven.project.MavenProject;
35  import org.apache.maven.project.ProjectSorter;
36  import org.codehaus.plexus.util.dag.CycleDetectedException;
37  
38  /**
39   * Describes the interdependencies between projects in the reactor.
40   *
41   * @author Benjamin Bentmann
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       */
74      public DefaultProjectDependencyGraph(Collection<MavenProject> allProjects, Collection<MavenProject> projects)
75              throws CycleDetectedException, DuplicateProjectException {
76          this.allProjects = Collections.unmodifiableList(new ArrayList<>(allProjects));
77          this.sorter = new ProjectSorter(projects);
78          this.order = new HashMap<>();
79          this.projects = new HashMap<>();
80          List<MavenProject> sorted = this.sorter.getSortedProjects();
81          for (int index = 0; index < sorted.size(); index++) {
82              MavenProject project = sorted.get(index);
83              String id = ProjectSorter.getId(project);
84              this.projects.put(id, project);
85              this.order.put(project, index);
86          }
87      }
88  
89      /**
90       * @since 3.5.0
91       */
92      public List<MavenProject> getAllProjects() {
93          return this.allProjects;
94      }
95  
96      public List<MavenProject> getSortedProjects() {
97          return new ArrayList<>(sorter.getSortedProjects());
98      }
99  
100     public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
101         Objects.requireNonNull(project, "project cannot be null");
102 
103         Set<String> projectIds = new HashSet<>();
104 
105         getDownstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
106 
107         return getSortedProjects(projectIds);
108     }
109 
110     private void getDownstreamProjects(String projectId, Set<String> projectIds, boolean transitive) {
111         for (String id : sorter.getDependents(projectId)) {
112             if (projectIds.add(id) && transitive) {
113                 getDownstreamProjects(id, projectIds, transitive);
114             }
115         }
116     }
117 
118     public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
119         Objects.requireNonNull(project, "project cannot be null");
120 
121         Set<String> projectIds = new HashSet<>();
122 
123         getUpstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
124 
125         return getSortedProjects(projectIds);
126     }
127 
128     private void getUpstreamProjects(String projectId, Collection<String> projectIds, boolean transitive) {
129         for (String id : sorter.getDependencies(projectId)) {
130             if (projectIds.add(id) && transitive) {
131                 getUpstreamProjects(id, projectIds, transitive);
132             }
133         }
134     }
135 
136     private List<MavenProject> getSortedProjects(Set<String> projectIds) {
137         return projectIds.stream()
138                 .map(projects::get)
139                 .sorted(Comparator.comparingInt(order::get))
140                 .collect(Collectors.toList());
141     }
142 
143     @Override
144     public String toString() {
145         return sorter.getSortedProjects().toString();
146     }
147 }