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  import org.apache.maven.execution.ProjectDependencyGraph;
27  import org.apache.maven.lifecycle.internal.ProjectBuildList;
28  import org.apache.maven.lifecycle.internal.ProjectSegment;
29  import org.apache.maven.project.MavenProject;
30  
31  /**
32   * <p>
33   * Presents a view of the Dependency Graph that is suited for concurrent building.
34   * </p>
35   * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
36   *
37   * @since 3.0
38   * @author Kristian Rosenvold
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          return new ArrayList<>(result);
72      }
73  
74      /**
75       * Marks the provided project as finished. Returns a list of
76       *
77       * @param mavenProject The project
78       * @return The list of builds that are eligible for starting now that the provided project is done
79       */
80      public List<MavenProject> markAsFinished(MavenProject mavenProject) {
81          finishedProjects.add(mavenProject);
82          return getSchedulableNewProcesses(mavenProject);
83      }
84  
85      private List<MavenProject> getSchedulableNewProcesses(MavenProject finishedProject) {
86          List<MavenProject> result = new ArrayList<>();
87          // schedule dependent projects, if all of their requirements are met
88          for (MavenProject dependentProject : projectDependencyGraph.getDownstreamProjects(finishedProject, false)) {
89              final List<MavenProject> upstreamProjects =
90                      projectDependencyGraph.getUpstreamProjects(dependentProject, false);
91              if (finishedProjects.containsAll(upstreamProjects)) {
92                  result.add(dependentProject);
93              }
94          }
95          return result;
96      }
97  
98      /**
99       * @return set of projects that have yet to be processed successfully by the build.
100      */
101     public Set<MavenProject> getUnfinishedProjects() {
102         Set<MavenProject> unfinished = new HashSet<>(projectBuilds.getProjects());
103         unfinished.removeAll(finishedProjects);
104         return unfinished;
105     }
106 
107     /**
108      * @return set of projects that have been successfully processed by the build.
109      */
110     protected Set<MavenProject> getFinishedProjects() {
111         return finishedProjects;
112     }
113 
114     protected ProjectBuildList getProjectBuilds() {
115         return projectBuilds;
116     }
117 
118     /**
119      * For the given {@link MavenProject} {@code p}, return all of {@code p}'s dependencies.
120      *
121      * @param p
122      * @return List of prerequisite projects
123      */
124     protected List<MavenProject> getDependencies(MavenProject p) {
125         return projectDependencyGraph.getUpstreamProjects(p, false);
126     }
127 
128     /**
129      * For the given {@link MavenProject} {@code p} return {@code p}'s uncompleted dependencies.
130      *
131      * @param p
132      * @return List of uncompleted prerequisite projects
133      */
134     public List<MavenProject> getActiveDependencies(MavenProject p) {
135         List<MavenProject> activeDependencies = projectDependencyGraph.getUpstreamProjects(p, false);
136         activeDependencies.removeAll(finishedProjects);
137         return activeDependencies;
138     }
139 }