View Javadoc
1   package org.apache.maven.graph;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.Comparator;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Objects;
31  import java.util.Set;
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 inter-dependencies between projects in the reactor.
41   *
42   * @author Benjamin Bentmann
43   */
44  public class DefaultProjectDependencyGraph
45      implements ProjectDependencyGraph
46  {
47  
48      private final ProjectSorter sorter;
49  
50      private final List<MavenProject> allProjects;
51  
52      private final Map<MavenProject, Integer> order;
53  
54      private final Map<String, MavenProject> projects;
55  
56      /**
57       * Creates a new project dependency graph based on the specified projects.
58       *
59       * @param projects The projects to create the dependency graph with
60       * @throws DuplicateProjectException
61       * @throws CycleDetectedException
62       */
63      public DefaultProjectDependencyGraph( Collection<MavenProject> projects )
64          throws CycleDetectedException, DuplicateProjectException
65      {
66          super();
67          this.allProjects = Collections.unmodifiableList( new ArrayList<>( projects ) );
68          this.sorter = new ProjectSorter( projects );
69          List<MavenProject> sorted = this.sorter.getSortedProjects();
70          this.order = new HashMap<>( sorted.size() );
71          this.projects = new HashMap<>( sorted.size() );
72          int index = 0;
73          for ( MavenProject project : sorted )
74          {
75              String id = ProjectSorter.getId( project );
76              this.projects.put( id, project );
77              this.order.put( project, index++ );
78          }
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       *
87       * @throws DuplicateProjectException
88       * @throws CycleDetectedException
89       * @since 3.5.0
90       */
91      public DefaultProjectDependencyGraph( final List<MavenProject> allProjects,
92                                            final Collection<MavenProject> projects )
93          throws CycleDetectedException, DuplicateProjectException
94      {
95          super();
96          this.allProjects = Collections.unmodifiableList( new ArrayList<>( allProjects ) );
97          this.sorter = new ProjectSorter( projects );
98          List<MavenProject> sorted = this.sorter.getSortedProjects();
99          this.order = new HashMap<>( sorted.size() );
100         this.projects = new HashMap<>( sorted.size() );
101         int index = 0;
102         for ( MavenProject project : sorted )
103         {
104             String id = ProjectSorter.getId( project );
105             this.projects.put( id, project );
106             this.order.put( project, index++ );
107         }
108     }
109 
110     /**
111      * @since 3.5.0
112      */
113     public List<MavenProject> getAllProjects()
114     {
115         return this.allProjects;
116     }
117 
118     public List<MavenProject> getSortedProjects()
119     {
120         return new ArrayList<>( sorter.getSortedProjects() );
121     }
122 
123     public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive )
124     {
125         Objects.requireNonNull( project, "project cannot be null" );
126 
127         Set<String> projectIds = new HashSet<>();
128 
129         getDownstreamProjects( ProjectSorter.getId( project ), projectIds, transitive );
130 
131         return getSortedProjects( projectIds );
132     }
133 
134     private void getDownstreamProjects( String projectId, Set<String> projectIds, boolean transitive )
135     {
136         for ( String id : sorter.getDependents( projectId ) )
137         {
138             if ( projectIds.add( id ) && transitive )
139             {
140                 getDownstreamProjects( id, projectIds, transitive );
141             }
142         }
143     }
144 
145     public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive )
146     {
147         Objects.requireNonNull( project, "project cannot be null" );
148 
149         Set<String> projectIds = new HashSet<>();
150 
151         getUpstreamProjects( ProjectSorter.getId( project ), projectIds, transitive );
152 
153         return getSortedProjects( projectIds );
154     }
155 
156     private void getUpstreamProjects( String projectId, Collection<String> projectIds, boolean transitive )
157     {
158         for ( String id : sorter.getDependencies( projectId ) )
159         {
160             if ( projectIds.add( id ) && transitive )
161             {
162                 getUpstreamProjects( id, projectIds, transitive );
163             }
164         }
165     }
166 
167     private List<MavenProject> getSortedProjects( Set<String> projectIds )
168     {
169         List<MavenProject> result = new ArrayList<>( projectIds.size() );
170         for ( String projectId : projectIds )
171         {
172             result.add( projects.get( projectId ) );
173         }
174 
175         Collections.sort( result, new MavenProjectComparator() );
176 
177         return result;
178     }
179 
180     @Override
181     public String toString()
182     {
183         return sorter.getSortedProjects().toString();
184     }
185 
186     private class MavenProjectComparator implements Comparator<MavenProject>
187     {
188         @Override
189         public int compare( MavenProject o1, MavenProject o2 )
190         {
191             return order.get( o1 ) - order.get( o2 );
192         }
193     }
194 }