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        @SuppressWarnings( { "UnusedDeclaration" } )
056        public LifecycleThreadedBuilder()
057        {
058        }
059    
060        public void build( MavenSession session, ReactorContext reactorContext, ProjectBuildList projectBuilds,
061                           List<TaskSegment> currentTaskSegment, ConcurrencyDependencyGraph analyzer,
062                           CompletionService<ProjectSegment> service )
063        {
064    
065            // Currently disabled
066            ThreadOutputMuxer muxer = null; // new ThreadOutputMuxer( analyzer.getProjectBuilds(), System.out );
067    
068            for ( TaskSegment taskSegment : currentTaskSegment )
069            {
070                Map<MavenProject, ProjectSegment> projectBuildMap = projectBuilds.selectSegment( taskSegment );
071                    try
072                    {
073                    multiThreadedProjectTaskSegmentBuild( analyzer, reactorContext, session, service, taskSegment,
074                                                          projectBuildMap, muxer );
075                        if ( reactorContext.getReactorBuildStatus().isHalted( ) )
076                        {
077                            break;
078                        }
079                    }
080                    catch ( Exception e )
081                    {
082                        break;  // Why are we just ignoring this exception? Are exceptions are being used for flow control
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                    break;
130                }
131                catch ( ExecutionException e )
132                {
133                    break;
134                }
135            }
136    
137            // cancel outstanding builds (if any)  - this can happen if an exception is thrown in above block
138    
139            Future<ProjectSegment> unprocessed;
140            while ( ( unprocessed = service.poll() ) != null )
141            {
142                try
143                {
144                    unprocessed.get();
145                }
146                catch ( InterruptedException e )
147                {
148                    throw new RuntimeException( e );
149                }
150                catch ( ExecutionException e )
151                {
152                    throw new RuntimeException( e );
153                }
154            }
155        }
156    
157        private Callable<ProjectSegment> createBuildCallable( final MavenSession rootSession,
158                                                              final ProjectSegment projectBuild,
159                                                              final ReactorContext reactorContext,
160                                                              final TaskSegment taskSegment, final ThreadOutputMuxer muxer )
161        {
162            return new Callable<ProjectSegment>()
163            {
164                public ProjectSegment call()
165                {
166                    // muxer.associateThreadWithProjectSegment( projectBuild );
167                    lifecycleModuleBuilder.buildProject( projectBuild.getSession(), rootSession, reactorContext,
168                                                         projectBuild.getProject(), taskSegment );
169                    // muxer.setThisModuleComplete( projectBuild );
170    
171                    return projectBuild;
172                }
173            };
174        }
175    }