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.DuplicateProjectException;
35  import org.apache.maven.project.MavenProject;
36  import org.apache.maven.project.ProjectSorter;
37  import org.codehaus.plexus.util.dag.CycleDetectedException;
38  
39  /**
40   * Describes the interdependencies between projects in the reactor.
41   *
42   * @author Benjamin Bentmann
43   */
44  public class DefaultProjectDependencyGraph implements ProjectDependencyGraph {
45  
46      private final ProjectSorter sorter;
47  
48      private final List<MavenProject> allProjects;
49  
50      private final Map<MavenProject, Integer> order;
51  
52      private final Map<String, MavenProject> projects;
53  
54      /**
55       * Creates a new project dependency graph based on the specified projects.
56       *
57       * @param projects The projects to create the dependency graph with
58       * @throws DuplicateProjectException
59       * @throws CycleDetectedException
60       */
61      public DefaultProjectDependencyGraph(Collection<MavenProject> projects)
62              throws CycleDetectedException, DuplicateProjectException {
63          this(projects, projects);
64      }
65  
66      /**
67       * Creates a new project dependency graph based on the specified projects.
68       *
69       * @param allProjects All collected projects.
70       * @param projects    The projects to create the dependency graph with.
71       * @throws DuplicateProjectException
72       * @throws CycleDetectedException
73       * @since 3.5.0
74       * @deprecated Use {@link #DefaultProjectDependencyGraph(Collection, Collection)} instead.
75       */
76      @Deprecated
77      public DefaultProjectDependencyGraph(List<MavenProject> allProjects, Collection<MavenProject> projects)
78              throws CycleDetectedException, DuplicateProjectException {
79          this((Collection<MavenProject>) allProjects, projects);
80      }
81  
82      /**
83       * Creates a new project dependency graph based on the specified projects.
84       *
85       * @param allProjects All collected projects.
86       * @param projects    The projects to create the dependency graph with.
87       * @throws DuplicateProjectException
88       * @throws CycleDetectedException
89       * @since 4.0.0
90       */
91      public DefaultProjectDependencyGraph(Collection<MavenProject> allProjects, Collection<MavenProject> projects)
92              throws CycleDetectedException, DuplicateProjectException {
93          this.allProjects = Collections.unmodifiableList(new ArrayList<>(allProjects));
94          this.sorter = new ProjectSorter(projects);
95          this.order = new HashMap<>();
96          this.projects = new HashMap<>();
97          List<MavenProject> sorted = this.sorter.getSortedProjects();
98          for (int index = 0; index < sorted.size(); index++) {
99              MavenProject project = sorted.get(index);
100             String id = ProjectSorter.getId(project);
101             this.projects.put(id, project);
102             this.order.put(project, index);
103         }
104     }
105 
106     /**
107      * @since 3.5.0
108      */
109     public List<MavenProject> getAllProjects() {
110         return this.allProjects;
111     }
112 
113     public List<MavenProject> getSortedProjects() {
114         return new ArrayList<>(sorter.getSortedProjects());
115     }
116 
117     public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
118         Objects.requireNonNull(project, "project cannot be null");
119 
120         Set<String> projectIds = new HashSet<>();
121 
122         getDownstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
123 
124         return getSortedProjects(projectIds);
125     }
126 
127     private void getDownstreamProjects(String projectId, Set<String> projectIds, boolean transitive) {
128         for (String id : sorter.getDependents(projectId)) {
129             if (projectIds.add(id) && transitive) {
130                 getDownstreamProjects(id, projectIds, transitive);
131             }
132         }
133     }
134 
135     public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
136         Objects.requireNonNull(project, "project cannot be null");
137 
138         Set<String> projectIds = new HashSet<>();
139 
140         getUpstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
141 
142         return getSortedProjects(projectIds);
143     }
144 
145     private void getUpstreamProjects(String projectId, Collection<String> projectIds, boolean transitive) {
146         for (String id : sorter.getDependencies(projectId)) {
147             if (projectIds.add(id) && transitive) {
148                 getUpstreamProjects(id, projectIds, transitive);
149             }
150         }
151     }
152 
153     private List<MavenProject> getSortedProjects(Set<String> projectIds) {
154         return projectIds.stream()
155                 .map(projects::get)
156                 .sorted(Comparator.comparingInt(order::get))
157                 .collect(Collectors.toList());
158     }
159 
160     @Override
161     public String toString() {
162         return sorter.getSortedProjects().toString();
163     }
164 }