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  
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 inter-dependencies 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          super();
63          this.allProjects = Collections.unmodifiableList(new ArrayList<>(projects));
64          this.sorter = new ProjectSorter(projects);
65          List<MavenProject> sorted = this.sorter.getSortedProjects();
66          this.order = new HashMap<>(sorted.size());
67          this.projects = new HashMap<>(sorted.size());
68          int index = 0;
69          for (MavenProject project : sorted) {
70              String id = ProjectSorter.getId(project);
71              this.projects.put(id, project);
72              this.order.put(project, index++);
73          }
74      }
75  
76      /**
77       * Creates a new project dependency graph based on the specified projects.
78       *
79       * @param allProjects All collected projects.
80       * @param projects The projects to create the dependency graph with.
81       *
82       * @throws DuplicateProjectException
83       * @throws CycleDetectedException
84       * @since 3.5.0
85       */
86      public DefaultProjectDependencyGraph(final List<MavenProject> allProjects, final Collection<MavenProject> projects)
87              throws CycleDetectedException, DuplicateProjectException {
88          super();
89          this.allProjects = Collections.unmodifiableList(new ArrayList<>(allProjects));
90          this.sorter = new ProjectSorter(projects);
91          List<MavenProject> sorted = this.sorter.getSortedProjects();
92          this.order = new HashMap<>(sorted.size());
93          this.projects = new HashMap<>(sorted.size());
94          int index = 0;
95          for (MavenProject project : sorted) {
96              String id = ProjectSorter.getId(project);
97              this.projects.put(id, project);
98              this.order.put(project, index++);
99          }
100     }
101 
102     /**
103      * @since 3.5.0
104      */
105     public List<MavenProject> getAllProjects() {
106         return this.allProjects;
107     }
108 
109     public List<MavenProject> getSortedProjects() {
110         return new ArrayList<>(sorter.getSortedProjects());
111     }
112 
113     public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
114         Objects.requireNonNull(project, "project cannot be null");
115 
116         Set<String> projectIds = new HashSet<>();
117 
118         getDownstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
119 
120         return getSortedProjects(projectIds);
121     }
122 
123     private void getDownstreamProjects(String projectId, Set<String> projectIds, boolean transitive) {
124         for (String id : sorter.getDependents(projectId)) {
125             if (projectIds.add(id) && transitive) {
126                 getDownstreamProjects(id, projectIds, transitive);
127             }
128         }
129     }
130 
131     public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
132         Objects.requireNonNull(project, "project cannot be null");
133 
134         Set<String> projectIds = new HashSet<>();
135 
136         getUpstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
137 
138         return getSortedProjects(projectIds);
139     }
140 
141     private void getUpstreamProjects(String projectId, Collection<String> projectIds, boolean transitive) {
142         for (String id : sorter.getDependencies(projectId)) {
143             if (projectIds.add(id) && transitive) {
144                 getUpstreamProjects(id, projectIds, transitive);
145             }
146         }
147     }
148 
149     private List<MavenProject> getSortedProjects(Set<String> projectIds) {
150         List<MavenProject> result = new ArrayList<>(projectIds.size());
151         for (String projectId : projectIds) {
152             result.add(projects.get(projectId));
153         }
154 
155         Collections.sort(result, new MavenProjectComparator());
156 
157         return result;
158     }
159 
160     @Override
161     public String toString() {
162         return sorter.getSortedProjects().toString();
163     }
164 
165     private class MavenProjectComparator implements Comparator<MavenProject> {
166         @Override
167         public int compare(MavenProject o1, MavenProject o2) {
168             return order.get(o1) - order.get(o2);
169         }
170     }
171 }