View Javadoc

1   package org.apache.maven.lifecycle.internal;
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.ExecutionEvent;
23  import org.apache.maven.execution.MavenExecutionRequest;
24  import org.apache.maven.execution.MavenExecutionResult;
25  import org.apache.maven.execution.MavenSession;
26  import org.apache.maven.lifecycle.DefaultLifecycles;
27  import org.apache.maven.lifecycle.MissingProjectException;
28  import org.apache.maven.lifecycle.NoGoalSpecifiedException;
29  import org.codehaus.plexus.component.annotations.Component;
30  import org.codehaus.plexus.component.annotations.Requirement;
31  import org.codehaus.plexus.logging.Logger;
32  
33  import java.util.List;
34  import java.util.concurrent.CompletionService;
35  import java.util.concurrent.ExecutorCompletionService;
36  import java.util.concurrent.ExecutorService;
37  import java.util.concurrent.TimeUnit;
38  
39  /**
40   * Starts the build life cycle
41   * @author Jason van Zyl
42   * @author Benjamin Bentmann
43   * @author Kristian Rosenvold
44   */
45  @Component( role = LifecycleStarter.class )
46  public class LifecycleStarter
47  {
48  
49      @Requirement
50      private ExecutionEventCatapult eventCatapult;
51  
52      @Requirement
53      private DefaultLifecycles defaultLifeCycles;
54  
55      @Requirement
56      private Logger logger;
57  
58      @Requirement
59      private LifecycleModuleBuilder lifecycleModuleBuilder;
60  
61      @Requirement
62      private LifecycleWeaveBuilder lifeCycleWeaveBuilder;
63  
64      @Requirement
65      private LifecycleThreadedBuilder lifecycleThreadedBuilder;
66  
67      @Requirement
68      private BuildListCalculator buildListCalculator;
69  
70      @Requirement
71      private LifecycleDebugLogger lifecycleDebugLogger;
72  
73      @Requirement
74      private LifecycleTaskSegmentCalculator lifecycleTaskSegmentCalculator;
75  
76      @Requirement
77      private ThreadConfigurationService threadConfigService;
78  
79      public void execute( MavenSession session )
80      {
81          eventCatapult.fire( ExecutionEvent.Type.SessionStarted, session, null );
82  
83          MavenExecutionResult result = session.getResult();
84  
85          try
86          {
87              if ( !session.isUsingPOMsFromFilesystem() && lifecycleTaskSegmentCalculator.requiresProject( session ) )
88              {
89                  throw new MissingProjectException( "The goal you specified requires a project to execute"
90                      + " but there is no POM in this directory (" + session.getExecutionRootDirectory() + ")."
91                      + " Please verify you invoked Maven from the correct directory." );
92              }
93  
94              final MavenExecutionRequest executionRequest = session.getRequest();
95              boolean isThreaded = executionRequest.isThreadConfigurationPresent();
96              session.setParallel( isThreaded );
97  
98              List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments( session );
99  
100             ProjectBuildList projectBuilds = buildListCalculator.calculateProjectBuilds( session, taskSegments );
101 
102             if ( projectBuilds.isEmpty() )
103             {
104                 throw new NoGoalSpecifiedException( "No goals have been specified for this build."
105                     + " You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or"
106                     + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>."
107                     + " Available lifecycle phases are: " + defaultLifeCycles.getLifecyclePhaseList() + "." );
108             }
109 
110             ProjectIndex projectIndex = new ProjectIndex( session.getProjects() );
111 
112             if ( logger.isDebugEnabled() )
113             {
114                 lifecycleDebugLogger.debugReactorPlan( projectBuilds );
115             }
116 
117             ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
118 
119             ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() );
120             ReactorContext callableContext =
121                 new ReactorContext( result, projectIndex, oldContextClassLoader, reactorBuildStatus );
122 
123             if ( isThreaded )
124             {
125                 ExecutorService executor =
126                     threadConfigService.getExecutorService( executionRequest.getThreadCount(),
127                                                             executionRequest.isPerCoreThreadCount(),
128                                                             session.getProjects().size() );
129                 try
130                 {
131 
132                     final boolean isWeaveMode = LifecycleWeaveBuilder.isWeaveMode( executionRequest );
133                     if ( isWeaveMode )
134                     {
135                         lifecycleDebugLogger.logWeavePlan( session );
136                         lifeCycleWeaveBuilder.build( projectBuilds, callableContext, taskSegments, session, executor,
137                                                      reactorBuildStatus );
138                     }
139                     else
140                     {
141                         ConcurrencyDependencyGraph analyzer =
142                             new ConcurrencyDependencyGraph( projectBuilds, session.getProjectDependencyGraph() );
143 
144                         CompletionService<ProjectSegment> service =
145                             new ExecutorCompletionService<ProjectSegment>( executor );
146 
147                         lifecycleThreadedBuilder.build( session, callableContext, projectBuilds, taskSegments, analyzer,
148                                                         service );
149                     }
150                 }
151                 finally
152                 {
153                     executor.shutdown();
154                     // If the builder has terminated with an exception we want to catch any stray threads before going
155                     // to System.exit in the mavencli.
156                     executor.awaitTermination( 5, TimeUnit.SECONDS ) ;
157                 }
158             }
159             else
160             {
161                 singleThreadedBuild( session, callableContext, projectBuilds, taskSegments, reactorBuildStatus );
162             }
163 
164         }
165         catch ( Exception e )
166         {
167             result.addException( e );
168         }
169 
170         eventCatapult.fire( ExecutionEvent.Type.SessionEnded, session, null );
171     }
172 
173     private void singleThreadedBuild( MavenSession session, ReactorContext callableContext,
174                                       ProjectBuildList projectBuilds, List<TaskSegment> taskSegments,
175                                       ReactorBuildStatus reactorBuildStatus )
176     {
177         for ( TaskSegment taskSegment : taskSegments )
178         {
179             for ( ProjectSegment projectBuild : projectBuilds.getByTaskSegment( taskSegment ) )
180             {
181                 try
182                 {
183                     lifecycleModuleBuilder.buildProject( session, callableContext, projectBuild.getProject(),
184                                                          taskSegment );
185                     if ( reactorBuildStatus.isHalted() )
186                     {
187                         break;
188                     }
189                 }
190                 catch ( Exception e )
191                 {
192                     break;  // Why are we just ignoring this exception? Are exceptions are being used for flow control
193                 }
194 
195             }
196         }
197     }
198 }