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