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.lifecycle.internal.builder.multithreaded;
20  
21  import java.util.ArrayList;
22  import java.util.HashSet;
23  import java.util.LinkedHashSet;
24  import java.util.List;
25  import java.util.Set;
26  
27  import org.apache.maven.execution.ProjectDependencyGraph;
28  import org.apache.maven.lifecycle.internal.ProjectBuildList;
29  import org.apache.maven.lifecycle.internal.ProjectSegment;
30  import org.apache.maven.project.MavenProject;
31  
32  /**
33   * <p>
34   * Presents a view of the Dependency Graph that is suited for concurrent building.
35   * </p>
36   * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
37   *
38   * @since 3.0
39   * @author Kristian Rosenvold
40   */
41  public class ConcurrencyDependencyGraph {
42  
43      private final ProjectBuildList projectBuilds;
44  
45      private final ProjectDependencyGraph projectDependencyGraph;
46  
47      private final Set<MavenProject> finishedProjects = new HashSet<>();
48  
49      public ConcurrencyDependencyGraph(ProjectBuildList projectBuilds, ProjectDependencyGraph projectDependencyGraph) {
50          this.projectDependencyGraph = projectDependencyGraph;
51          this.projectBuilds = projectBuilds;
52      }
53  
54      public int getNumberOfBuilds() {
55          return projectBuilds.size();
56      }
57  
58      /**
59       * Gets all the builds that have no reactor-dependencies
60       *
61       * @return A set of all the initial builds
62       */
63      public List<MavenProject> getRootSchedulableBuilds() {
64          Set<MavenProject> result = new LinkedHashSet<>();
65          for (ProjectSegment projectBuild : projectBuilds) {
66              if (projectDependencyGraph
67                      .getUpstreamProjects(projectBuild.getProject(), false)
68                      .isEmpty()) {
69                  result.add(projectBuild.getProject());
70              }
71          }
72          if (result.isEmpty() && projectBuilds.size() > 0) {
73              // Must return at least one project
74              result.add(projectBuilds.get(0).getProject());
75          }
76          return new ArrayList<>(result);
77      }
78  
79      /**
80       * Marks the provided project as finished. Returns a list of
81       *
82       * @param mavenProject The project
83       * @return The list of builds that are eligible for starting now that the provided project is done
84       */
85      public List<MavenProject> markAsFinished(MavenProject mavenProject) {
86          finishedProjects.add(mavenProject);
87          return getSchedulableNewProcesses(mavenProject);
88      }
89  
90      private List<MavenProject> getSchedulableNewProcesses(MavenProject finishedProject) {
91          List<MavenProject> result = new ArrayList<>();
92          // schedule dependent projects, if all of their requirements are met
93          for (MavenProject dependentProject : projectDependencyGraph.getDownstreamProjects(finishedProject, false)) {
94              final List<MavenProject> upstreamProjects =
95                      projectDependencyGraph.getUpstreamProjects(dependentProject, false);
96              if (finishedProjects.containsAll(upstreamProjects)) {
97                  result.add(dependentProject);
98              }
99          }
100         return result;
101     }
102 
103     /**
104      * @return set of projects that have yet to be processed successfully by the build.
105      */
106     public Set<MavenProject> getUnfinishedProjects() {
107         Set<MavenProject> unfinished = new HashSet<>(projectBuilds.getProjects());
108         unfinished.removeAll(finishedProjects);
109         return unfinished;
110     }
111 
112     /**
113      * @return set of projects that have been successfully processed by the build.
114      */
115     protected Set<MavenProject> getFinishedProjects() {
116         return finishedProjects;
117     }
118 
119     protected ProjectBuildList getProjectBuilds() {
120         return projectBuilds;
121     }
122 
123     /**
124      * For the given {@link MavenProject} {@code p}, return all of {@code p}'s dependencies.
125      *
126      * @param p
127      * @return List of prerequisite projects
128      */
129     protected List<MavenProject> getDependencies(MavenProject p) {
130         return projectDependencyGraph.getUpstreamProjects(p, false);
131     }
132 
133     /**
134      * For the given {@link MavenProject} {@code p} return {@code p}'s uncompleted dependencies.
135      *
136      * @param p
137      * @return List of uncompleted prerequisite projects
138      */
139     public List<MavenProject> getActiveDependencies(MavenProject p) {
140         List<MavenProject> activeDependencies = projectDependencyGraph.getUpstreamProjects(p, false);
141         activeDependencies.removeAll(finishedProjects);
142         return activeDependencies;
143     }
144 }