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          return new ArrayList<>(result);
73      }
74  
75      /**
76       * Marks the provided project as finished. Returns a list of
77       *
78       * @param mavenProject The project
79       * @return The list of builds that are eligible for starting now that the provided project is done
80       */
81      public List<MavenProject> markAsFinished(MavenProject mavenProject) {
82          finishedProjects.add(mavenProject);
83          return getSchedulableNewProcesses(mavenProject);
84      }
85  
86      private List<MavenProject> getSchedulableNewProcesses(MavenProject finishedProject) {
87          List<MavenProject> result = new ArrayList<>();
88          // schedule dependent projects, if all of their requirements are met
89          for (MavenProject dependentProject : projectDependencyGraph.getDownstreamProjects(finishedProject, false)) {
90              final List<MavenProject> upstreamProjects =
91                      projectDependencyGraph.getUpstreamProjects(dependentProject, false);
92              if (finishedProjects.containsAll(upstreamProjects)) {
93                  result.add(dependentProject);
94              }
95          }
96          return result;
97      }
98  
99      /**
100      * @return set of projects that have yet to be processed successfully by the build.
101      */
102     public Set<MavenProject> getUnfinishedProjects() {
103         Set<MavenProject> unfinished = new HashSet<>(projectBuilds.getProjects());
104         unfinished.removeAll(finishedProjects);
105         return unfinished;
106     }
107 
108     /**
109      * @return set of projects that have been successfully processed by the build.
110      */
111     protected Set<MavenProject> getFinishedProjects() {
112         return finishedProjects;
113     }
114 
115     protected ProjectBuildList getProjectBuilds() {
116         return projectBuilds;
117     }
118 
119     /**
120      * For the given {@link MavenProject} {@code p}, return all of {@code p}'s dependencies.
121      *
122      * @param p
123      * @return List of prerequisite projects
124      */
125     protected List<MavenProject> getDependencies(MavenProject p) {
126         return projectDependencyGraph.getUpstreamProjects(p, false);
127     }
128 
129     /**
130      * For the given {@link MavenProject} {@code p} return {@code p}'s uncompleted dependencies.
131      *
132      * @param p
133      * @return List of uncompleted prerequisite projects
134      */
135     public List<MavenProject> getActiveDependencies(MavenProject p) {
136         List<MavenProject> activeDependencies = projectDependencyGraph.getUpstreamProjects(p, false);
137         activeDependencies.removeAll(finishedProjects);
138         return activeDependencies;
139     }
140 }