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.InternalErrorException;
023    import org.apache.maven.artifact.Artifact;
024    import org.apache.maven.execution.BuildFailure;
025    import org.apache.maven.execution.ExecutionEvent;
026    import org.apache.maven.execution.MavenExecutionRequest;
027    import org.apache.maven.execution.MavenSession;
028    import org.apache.maven.lifecycle.LifecycleExecutionException;
029    import org.apache.maven.lifecycle.LifecycleNotFoundException;
030    import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
031    import org.apache.maven.lifecycle.MavenExecutionPlan;
032    import org.apache.maven.model.Plugin;
033    import org.apache.maven.plugin.InvalidPluginDescriptorException;
034    import org.apache.maven.plugin.MojoNotFoundException;
035    import org.apache.maven.plugin.PluginDescriptorParsingException;
036    import org.apache.maven.plugin.PluginNotFoundException;
037    import org.apache.maven.plugin.PluginResolutionException;
038    import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
039    import org.apache.maven.plugin.version.PluginVersionResolutionException;
040    import org.apache.maven.project.MavenProject;
041    import org.codehaus.plexus.classworlds.realm.ClassRealm;
042    import org.codehaus.plexus.component.annotations.Component;
043    import org.codehaus.plexus.component.annotations.Requirement;
044    import org.codehaus.plexus.logging.Logger;
045    
046    import java.util.Set;
047    
048    /**
049     * Common code that is shared by the LifecycleModuleBuilder and the LifeCycleWeaveBuilder
050     * 
051     * @since 3.0
052     * @author Kristian Rosenvold
053     *         Builds one or more lifecycles for a full module
054     *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
055     */
056    @Component( role = BuilderCommon.class )
057    public class BuilderCommon
058    {
059        @Requirement
060        private LifecycleDebugLogger lifecycleDebugLogger;
061    
062        @Requirement
063        private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
064    
065        @Requirement
066        private ExecutionEventCatapult eventCatapult;
067    
068        @Requirement
069        private Logger logger;
070    
071    
072        @SuppressWarnings( { "UnusedDeclaration" } )
073        public BuilderCommon()
074        {
075        }
076    
077        public BuilderCommon( LifecycleDebugLogger lifecycleDebugLogger,
078                              LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator, Logger logger )
079        {
080            this.lifecycleDebugLogger = lifecycleDebugLogger;
081            this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator;
082            this.logger = logger;
083        }
084    
085        public MavenExecutionPlan resolveBuildPlan( MavenSession session, MavenProject project, TaskSegment taskSegment,
086                                                    Set<Artifact> projectArtifacts )
087            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
088            PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
089            NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException,
090            LifecycleExecutionException
091        {
092            MavenExecutionPlan executionPlan =
093                lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, project, taskSegment.getTasks() );
094    
095            lifecycleDebugLogger.debugProjectPlan( project, executionPlan );
096    
097            if ( session.getRequest().isThreadConfigurationPresent() )
098            {
099                final Set<Plugin> unsafePlugins = executionPlan.getNonThreadSafePlugins();
100                if ( !unsafePlugins.isEmpty() )
101                {
102                    logger.warn( "*****************************************************************" );
103                    logger.warn( "* Your build is requesting parallel execution, but project      *" );
104                    logger.warn( "* contains the following plugin(s) that are not marked as       *" );
105                    logger.warn( "* @threadSafe to support parallel building.                     *" );
106                    logger.warn( "* While this /may/ work fine, please look for plugin updates    *" );
107                    logger.warn( "* and/or request plugins be made thread-safe.                   *" );
108                    logger.warn( "* If reporting an issue, report it against the plugin in        *" );
109                    logger.warn( "* question, not against maven-core                              *" );
110                    logger.warn( "*****************************************************************" );
111                    logger.warn( "The following plugins are not marked @threadSafe in " + project.getName() + ":" );
112                    for ( Plugin unsafePlugin : unsafePlugins )
113                    {
114                        logger.warn( unsafePlugin.getId() );
115                    }
116                    logger.warn( "*****************************************************************" );
117                }
118            }
119    
120            return executionPlan;
121        }
122    
123        public void handleBuildError( final ReactorContext buildContext, final MavenSession rootSession,
124                                      final MavenProject mavenProject, Exception e, final long buildStartTime )
125        {
126            if ( e instanceof RuntimeException )
127            {
128                e = new InternalErrorException( "Internal error: " + e, e );
129            }
130    
131            buildContext.getResult().addException( e );
132    
133            long buildEndTime = System.currentTimeMillis();
134    
135            buildContext.getResult().addBuildSummary( new BuildFailure( mavenProject, buildEndTime - buildStartTime, e ) );
136    
137            eventCatapult.fire( ExecutionEvent.Type.ProjectFailed, rootSession, null, e );
138    
139            if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( rootSession.getReactorFailureBehavior() ) )
140            {
141                // continue the build
142            }
143            else if ( MavenExecutionRequest.REACTOR_FAIL_AT_END.equals( rootSession.getReactorFailureBehavior() ) )
144            {
145                // continue the build but ban all projects that depend on the failed one
146                buildContext.getReactorBuildStatus().blackList( mavenProject );
147            }
148            else if ( MavenExecutionRequest.REACTOR_FAIL_FAST.equals( rootSession.getReactorFailureBehavior() ) )
149            {
150                buildContext.getReactorBuildStatus().halt();
151            }
152            else
153            {
154                throw new IllegalArgumentException(
155                    "invalid reactor failure behavior " + rootSession.getReactorFailureBehavior() );
156            }
157        }
158    
159        public static void attachToThread( MavenProject currentProject )
160        {
161            ClassRealm projectRealm = currentProject.getClassRealm();
162            if ( projectRealm != null )
163            {
164                Thread.currentThread().setContextClassLoader( projectRealm );
165            }
166        }
167    
168        // Todo: I'm really wondering where this method belongs; smells like it should be on MavenProject, but for some reason
169        // it isn't ? This localization is kind-of a code smell.
170    
171        public static String getKey( MavenProject project )
172        {
173            return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
174        }
175    
176    
177    }