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   */
40  public class ConcurrencyDependencyGraph {
41  
42      private final ProjectBuildList projectBuilds;
43  
44      private final ProjectDependencyGraph projectDependencyGraph;
45  
46      private final Set<MavenProject> finishedProjects = new HashSet<>();
47  
48      public ConcurrencyDependencyGraph(ProjectBuildList projectBuilds, ProjectDependencyGraph projectDependencyGraph) {
49          this.projectDependencyGraph = projectDependencyGraph;
50          this.projectBuilds = projectBuilds;
51      }
52  
53      public int getNumberOfBuilds() {
54          return projectBuilds.size();
55      }
56  
57      /**
58       * Gets all the builds that have no reactor-dependencies
59       *
60       * @return A set of all the initial builds
61       */
62      public List<MavenProject> getRootSchedulableBuilds() {
63          Set<MavenProject> result = new LinkedHashSet<>();
64          for (ProjectSegment projectBuild : projectBuilds) {
65              if (projectDependencyGraph
66                      .getUpstreamProjects(projectBuild.getProject(), false)
67                      .isEmpty()) {
68                  result.add(projectBuild.getProject());
69              }
70          }
71          if (result.isEmpty() && projectBuilds.size() > 0) {
72              // Must return at least one project
73              result.add(projectBuilds.get(0).getProject());
74          }
75          return new ArrayList<>(result);
76      }
77  
78      /**
79       * Marks the provided project as finished. Returns a list of
80       *
81       * @param mavenProject The project
82       * @return The list of builds that are eligible for starting now that the provided project is done
83       */
84      public List<MavenProject> markAsFinished(MavenProject mavenProject) {
85          finishedProjects.add(mavenProject);
86          return getSchedulableNewProcesses(mavenProject);
87      }
88  
89      private List<MavenProject> getSchedulableNewProcesses(MavenProject finishedProject) {
90          List<MavenProject> result = new ArrayList<>();
91          // schedule dependent projects, if all of their requirements are met
92          for (MavenProject dependentProject : projectDependencyGraph.getDownstreamProjects(finishedProject, false)) {
93              final List<MavenProject> upstreamProjects =
94                      projectDependencyGraph.getUpstreamProjects(dependentProject, false);
95              if (finishedProjects.containsAll(upstreamProjects)) {
96                  result.add(dependentProject);
97              }
98          }
99          return result;
100     }
101 
102     /**
103      * @return set of projects that have yet to be processed successfully by the build.
104      */
105     public Set<MavenProject> getUnfinishedProjects() {
106         Set<MavenProject> unfinished = new HashSet<>(projectBuilds.getProjects());
107         unfinished.removeAll(finishedProjects);
108         return unfinished;
109     }
110 
111     /**
112      * @return set of projects that have been successfully processed by the build.
113      */
114     protected Set<MavenProject> getFinishedProjects() {
115         return finishedProjects;
116     }
117 
118     protected ProjectBuildList getProjectBuilds() {
119         return projectBuilds;
120     }
121 
122     /**
123      * For the given {@link MavenProject} {@code p}, return all of {@code p}'s dependencies.
124      *
125      * @param p
126      * @return List of prerequisite projects
127      */
128     protected List<MavenProject> getDependencies(MavenProject p) {
129         return projectDependencyGraph.getUpstreamProjects(p, false);
130     }
131 
132     /**
133      * For the given {@link MavenProject} {@code p} return {@code p}'s uncompleted dependencies.
134      *
135      * @param p
136      * @return List of uncompleted prerequisite projects
137      */
138     public List<MavenProject> getActiveDependencies(MavenProject p) {
139         List<MavenProject> activeDependencies = projectDependencyGraph.getUpstreamProjects(p, false);
140         activeDependencies.removeAll(finishedProjects);
141         return activeDependencies;
142     }
143 }