001package org.apache.maven.plugin;
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
022import java.io.ByteArrayOutputStream;
023import java.io.PrintStream;
024import java.util.List;
025
026import org.apache.maven.execution.MavenSession;
027import org.apache.maven.execution.MojoExecutionEvent;
028import org.apache.maven.execution.MojoExecutionListener;
029import org.apache.maven.execution.scope.internal.MojoExecutionScope;
030import org.apache.maven.model.Plugin;
031import org.apache.maven.plugin.descriptor.MojoDescriptor;
032import org.apache.maven.plugin.descriptor.PluginDescriptor;
033import org.apache.maven.project.MavenProject;
034import org.codehaus.plexus.classworlds.realm.ClassRealm;
035import org.codehaus.plexus.component.annotations.Component;
036import org.codehaus.plexus.component.annotations.Requirement;
037import org.eclipse.aether.RepositorySystemSession;
038import org.eclipse.aether.repository.RemoteRepository;
039
040// TODO: the antrun plugin has its own configurator, the only plugin that does. might need to think about how that works
041// TODO: remove the coreArtifactFilterManager
042
043@Component( role = BuildPluginManager.class )
044public class DefaultBuildPluginManager
045    implements BuildPluginManager
046{
047
048    @Requirement
049    private MavenPluginManager mavenPluginManager;
050
051    @Requirement
052    private LegacySupport legacySupport;
053
054    @Requirement
055    private MojoExecutionScope scope;
056
057    private MojoExecutionListener mojoExecutionListener;
058
059    // this tricks plexus-component-metadata generate required metadata
060    @Requirement( role = MojoExecutionListener.class )
061    private List<MojoExecutionListener> mojoExecutionListeners;
062
063    public void setMojoExecutionListeners( final List<MojoExecutionListener> listeners )
064    {
065        this.mojoExecutionListeners = listeners;
066        this.mojoExecutionListener = new CompoundMojoExecutionListener( listeners );
067    }
068
069    /**
070     * @param plugin
071     * @param repositories
072     * @param session
073     * @return PluginDescriptor The component descriptor for the Maven plugin.
074     * @throws PluginNotFoundException The plugin could not be found in any repositories.
075     * @throws PluginResolutionException The plugin could be found but could not be resolved.
076     * @throws InvalidPluginDescriptorException 
077     */
078    public PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
079        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException
080    {
081        return mavenPluginManager.getPluginDescriptor( plugin, repositories, session );
082    }
083
084    // ----------------------------------------------------------------------
085    // Mojo execution
086    // ----------------------------------------------------------------------
087
088    public void executeMojo( MavenSession session, MojoExecution mojoExecution )
089        throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException
090    {
091        MavenProject project = session.getCurrentProject();
092
093        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
094
095        Mojo mojo = null;
096
097        ClassRealm pluginRealm;
098        try
099        {
100            pluginRealm = getPluginRealm( session, mojoDescriptor.getPluginDescriptor() );
101        }
102        catch ( PluginResolutionException e )
103        {
104            throw new PluginExecutionException( mojoExecution, project, e );
105        }
106
107        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
108        Thread.currentThread().setContextClassLoader( pluginRealm );
109
110        MavenSession oldSession = legacySupport.getSession();
111
112        scope.enter();
113
114        try
115        {
116            scope.seed( MavenProject.class, project );
117            scope.seed( MojoExecution.class, mojoExecution );
118
119            mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution );
120
121            legacySupport.setSession( session );
122
123            // NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch!
124            // This is necessary to avoid creating compatibility problems for existing plugins that use
125            // MavenProjectHelper.attachArtifact(..).
126            try
127            {
128                MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent( session, project, mojoExecution, mojo );
129
130                mojoExecutionListener.beforeMojoExecution( mojoExecutionEvent );
131
132                mojo.execute();
133
134                mojoExecutionListener.afterMojoExecutionSuccess( mojoExecutionEvent );
135            }
136            catch ( ClassCastException e )
137            {
138                // to be processed in the outer catch block
139                throw e;
140            }
141            catch ( RuntimeException e )
142            {
143                throw new PluginExecutionException( mojoExecution, project, e );
144            }
145        }
146        catch ( PluginContainerException e )
147        {
148            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
149                                                                                 e ) );
150
151            throw new PluginExecutionException( mojoExecution, project, e );
152        }
153        catch ( NoClassDefFoundError e )
154        {
155            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
156                                                                                 e ) );
157
158            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
159            PrintStream ps = new PrintStream( os );
160            ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": "
161                + e.getMessage() );
162            pluginRealm.display( ps );
163
164            Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
165
166            throw new PluginExecutionException( mojoExecution, project, wrapper );
167        }
168        catch ( LinkageError e )
169        {
170            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
171                                                                                 e ) );
172
173            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
174            PrintStream ps = new PrintStream( os );
175            ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
176                + e.getClass().getName() + ": " + e.getMessage() );
177            pluginRealm.display( ps );
178
179            Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
180
181            throw new PluginExecutionException( mojoExecution, project, wrapper );
182        }
183        catch ( ClassCastException e )
184        {
185            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
186                                                                                 e ) );
187
188            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
189            PrintStream ps = new PrintStream( os );
190            ps.println( "A type incompatibility occured while executing " + mojoDescriptor.getId() + ": "
191                + e.getMessage() );
192            pluginRealm.display( ps );
193
194            throw new PluginExecutionException( mojoExecution, project, os.toString(), e );
195        }
196        catch ( RuntimeException e )
197        {
198            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
199                                                                                 e ) );
200
201            throw e;
202        }
203        finally
204        {
205            mavenPluginManager.releaseMojo( mojo, mojoExecution );
206
207            scope.exit();
208
209            Thread.currentThread().setContextClassLoader( oldClassLoader );
210
211            legacySupport.setSession( oldSession );
212        }
213    }
214
215    /**
216     * TODO pluginDescriptor classRealm and artifacts are set as a side effect of this
217     *      call, which is not nice.
218     * @throws PluginResolutionException 
219     */
220    public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor ) 
221        throws PluginResolutionException, PluginManagerException
222    {
223        ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
224        if ( pluginRealm != null )
225        {
226            return pluginRealm;
227        }
228
229        mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
230
231        return pluginDescriptor.getClassRealm();
232    }
233
234    public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
235                                             RepositorySystemSession session )
236        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
237        MojoNotFoundException, InvalidPluginDescriptorException
238    {
239        return mavenPluginManager.getMojoDescriptor( plugin, goal, repositories, session );
240    }
241
242}