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.MavenSession;
023    import org.apache.maven.project.MavenProject;
024    import org.codehaus.plexus.component.annotations.Component;
025    import org.codehaus.plexus.component.annotations.Requirement;
026    import org.codehaus.plexus.logging.Logger;
027    
028    import java.util.List;
029    import java.util.Map;
030    import java.util.concurrent.Callable;
031    import java.util.concurrent.CompletionService;
032    import java.util.concurrent.ExecutionException;
033    import java.util.concurrent.Future;
034    
035    /**
036     * Builds the full lifecycle in weave-mode (phase by phase as opposed to project-by-project)
037     * 
038     * @since 3.0
039     * @author Kristian Rosenvold
040     *         Builds one or more lifecycles for a full module
041     *         <p/>
042     *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
043     */
044    @Component( role = LifecycleThreadedBuilder.class )
045    public class LifecycleThreadedBuilder
046    {
047    
048        @Requirement
049        private Logger logger;
050    
051        @Requirement
052        private LifecycleModuleBuilder lifecycleModuleBuilder;
053    
054    
055        public LifecycleThreadedBuilder()
056        {
057        }
058    
059        public void build( MavenSession session, ReactorContext reactorContext, ProjectBuildList projectBuilds,
060                           List<TaskSegment> currentTaskSegment, ConcurrencyDependencyGraph analyzer,
061                           CompletionService<ProjectSegment> service )
062        {
063    
064            // Currently disabled
065            ThreadOutputMuxer muxer = null; // new ThreadOutputMuxer( analyzer.getProjectBuilds(), System.out );
066    
067            for ( TaskSegment taskSegment : currentTaskSegment )
068            {
069                Map<MavenProject, ProjectSegment> projectBuildMap = projectBuilds.selectSegment( taskSegment );
070                try
071                {
072                    multiThreadedProjectTaskSegmentBuild( analyzer, reactorContext, session, service, taskSegment,
073                                                          projectBuildMap, muxer );
074                    if ( reactorContext.getReactorBuildStatus().isHalted() )
075                    {
076                        break;
077                    }
078                }
079                catch ( Exception e )
080                {
081                    session.getResult().addException( e );
082                    break;
083                }
084    
085            }
086        }
087    
088        private void multiThreadedProjectTaskSegmentBuild( ConcurrencyDependencyGraph analyzer,
089                                                           ReactorContext reactorContext, MavenSession rootSession,
090                                                           CompletionService<ProjectSegment> service,
091                                                           TaskSegment taskSegment,
092                                                           Map<MavenProject, ProjectSegment> projectBuildList,
093                                                           ThreadOutputMuxer muxer )
094        {
095    
096            // schedule independent projects
097            for ( MavenProject mavenProject : analyzer.getRootSchedulableBuilds() )
098            {
099                ProjectSegment projectSegment = projectBuildList.get( mavenProject );
100                logger.debug( "Scheduling: " + projectSegment.getProject() );
101                Callable<ProjectSegment> cb =
102                    createBuildCallable( rootSession, projectSegment, reactorContext, taskSegment, muxer );
103                service.submit( cb );
104            }
105    
106            // for each finished project
107            for ( int i = 0; i < analyzer.getNumberOfBuilds(); i++ )
108            {
109                try
110                {
111                    ProjectSegment projectBuild = service.take().get();
112                    if ( reactorContext.getReactorBuildStatus().isHalted() )
113                    {
114                        break;
115                    }
116                    final List<MavenProject> newItemsThatCanBeBuilt =
117                        analyzer.markAsFinished( projectBuild.getProject() );
118                    for ( MavenProject mavenProject : newItemsThatCanBeBuilt )
119                    {
120                        ProjectSegment scheduledDependent = projectBuildList.get( mavenProject );
121                        logger.debug( "Scheduling: " + scheduledDependent );
122                        Callable<ProjectSegment> cb =
123                            createBuildCallable( rootSession, scheduledDependent, reactorContext, taskSegment, muxer );
124                        service.submit( cb );
125                    }
126                }
127                catch ( InterruptedException e )
128                {
129                    rootSession.getResult().addException( e );
130                    break;
131                }
132                catch ( ExecutionException e )
133                {
134                    rootSession.getResult().addException( e );
135                    break;
136                }
137            }
138    
139            // cancel outstanding builds (if any)  - this can happen if an exception is thrown in above block
140    
141            Future<ProjectSegment> unprocessed;
142            while ( ( unprocessed = service.poll() ) != null )
143            {
144                try
145                {
146                    unprocessed.get();
147                }
148                catch ( InterruptedException e )
149                {
150                    throw new RuntimeException( e );
151                }
152                catch ( ExecutionException e )
153                {
154                    throw new RuntimeException( e );
155                }
156            }
157        }
158    
159        private Callable<ProjectSegment> createBuildCallable( final MavenSession rootSession,
160                                                              final ProjectSegment projectBuild,
161                                                              final ReactorContext reactorContext,
162                                                              final TaskSegment taskSegment, final ThreadOutputMuxer muxer )
163        {
164            return new Callable<ProjectSegment>()
165            {
166                public ProjectSegment call()
167                {
168                    // muxer.associateThreadWithProjectSegment( projectBuild );
169                    lifecycleModuleBuilder.buildProject( projectBuild.getSession(), rootSession, reactorContext,
170                                                         projectBuild.getProject(), taskSegment );
171                    // muxer.setThisModuleComplete( projectBuild );
172    
173                    return projectBuild;
174                }
175            };
176        }
177    }