001 package org.apache.maven.lifecycle.internal; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import org.apache.maven.execution.ExecutionEvent; 023 import org.apache.maven.execution.MavenExecutionRequest; 024 import org.apache.maven.execution.MavenExecutionResult; 025 import org.apache.maven.execution.MavenSession; 026 import org.apache.maven.lifecycle.DefaultLifecycles; 027 import org.apache.maven.lifecycle.MissingProjectException; 028 import org.apache.maven.lifecycle.NoGoalSpecifiedException; 029 import org.codehaus.plexus.component.annotations.Component; 030 import org.codehaus.plexus.component.annotations.Requirement; 031 import org.codehaus.plexus.logging.Logger; 032 033 import java.util.List; 034 import java.util.concurrent.CompletionService; 035 import java.util.concurrent.ExecutorCompletionService; 036 import java.util.concurrent.ExecutorService; 037 import java.util.concurrent.TimeUnit; 038 039 /** 040 * Starts the build life cycle 041 * @author Jason van Zyl 042 * @author Benjamin Bentmann 043 * @author Kristian Rosenvold 044 */ 045 @Component( role = LifecycleStarter.class ) 046 public class LifecycleStarter 047 { 048 049 @Requirement 050 private ExecutionEventCatapult eventCatapult; 051 052 @Requirement 053 private DefaultLifecycles defaultLifeCycles; 054 055 @Requirement 056 private Logger logger; 057 058 @Requirement 059 private LifecycleModuleBuilder lifecycleModuleBuilder; 060 061 @Requirement 062 private LifecycleWeaveBuilder lifeCycleWeaveBuilder; 063 064 @Requirement 065 private LifecycleThreadedBuilder lifecycleThreadedBuilder; 066 067 @Requirement 068 private BuildListCalculator buildListCalculator; 069 070 @Requirement 071 private LifecycleDebugLogger lifecycleDebugLogger; 072 073 @Requirement 074 private LifecycleTaskSegmentCalculator lifecycleTaskSegmentCalculator; 075 076 @Requirement 077 private ThreadConfigurationService threadConfigService; 078 079 public void execute( MavenSession session ) 080 { 081 eventCatapult.fire( ExecutionEvent.Type.SessionStarted, session, null ); 082 083 MavenExecutionResult result = session.getResult(); 084 085 try 086 { 087 if ( !session.isUsingPOMsFromFilesystem() && lifecycleTaskSegmentCalculator.requiresProject( session ) ) 088 { 089 throw new MissingProjectException( "The goal you specified requires a project to execute" 090 + " but there is no POM in this directory (" + session.getExecutionRootDirectory() + ")." 091 + " Please verify you invoked Maven from the correct directory." ); 092 } 093 094 final MavenExecutionRequest executionRequest = session.getRequest(); 095 boolean isThreaded = executionRequest.isThreadConfigurationPresent(); 096 session.setParallel( isThreaded ); 097 098 List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments( session ); 099 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 }