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,
079                                        RepositorySystemSession session )
080        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
081        InvalidPluginDescriptorException
082    {
083        return mavenPluginManager.getPluginDescriptor( plugin, repositories, session );
084    }
085
086    // ----------------------------------------------------------------------
087    // Mojo execution
088    // ----------------------------------------------------------------------
089
090    public void executeMojo( MavenSession session, MojoExecution mojoExecution )
091        throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException
092    {
093        MavenProject project = session.getCurrentProject();
094
095        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
096
097        Mojo mojo = null;
098
099        ClassRealm pluginRealm;
100        try
101        {
102            pluginRealm = getPluginRealm( session, mojoDescriptor.getPluginDescriptor() );
103        }
104        catch ( PluginResolutionException e )
105        {
106            throw new PluginExecutionException( mojoExecution, project, e );
107        }
108
109        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
110        Thread.currentThread().setContextClassLoader( pluginRealm );
111
112        MavenSession oldSession = legacySupport.getSession();
113
114        scope.enter();
115
116        try
117        {
118            scope.seed( MavenProject.class, project );
119            scope.seed( MojoExecution.class, mojoExecution );
120
121            mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution );
122
123            legacySupport.setSession( session );
124
125            // NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch!
126            // This is necessary to avoid creating compatibility problems for existing plugins that use
127            // MavenProjectHelper.attachArtifact(..).
128            try
129            {
130                MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent( session, project, mojoExecution, mojo );
131
132                mojoExecutionListener.beforeMojoExecution( mojoExecutionEvent );
133
134                mojo.execute();
135
136                mojoExecutionListener.afterMojoExecutionSuccess( mojoExecutionEvent );
137            }
138            catch ( ClassCastException e )
139            {
140                // to be processed in the outer catch block
141                throw e;
142            }
143            catch ( RuntimeException e )
144            {
145                throw new PluginExecutionException( mojoExecution, project, e );
146            }
147        }
148        catch ( PluginContainerException e )
149        {
150            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
151                                                                                 e ) );
152
153            throw new PluginExecutionException( mojoExecution, project, e );
154        }
155        catch ( NoClassDefFoundError e )
156        {
157            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
158                                                                                 e ) );
159
160            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
161            PrintStream ps = new PrintStream( os );
162            ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": "
163                + e.getMessage() );
164            pluginRealm.display( ps );
165
166            Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
167
168            throw new PluginExecutionException( mojoExecution, project, wrapper );
169        }
170        catch ( LinkageError e )
171        {
172            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
173                                                                                 e ) );
174
175            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
176            PrintStream ps = new PrintStream( os );
177            ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
178                + e.getClass().getName() + ": " + e.getMessage() );
179            pluginRealm.display( ps );
180
181            Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
182
183            throw new PluginExecutionException( mojoExecution, project, wrapper );
184        }
185        catch ( ClassCastException e )
186        {
187            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
188                                                                                 e ) );
189
190            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
191            PrintStream ps = new PrintStream( os );
192            ps.println( "A type incompatibility occurred while executing " + mojoDescriptor.getId() + ": "
193                + e.getMessage() );
194            pluginRealm.display( ps );
195
196            throw new PluginExecutionException( mojoExecution, project, os.toString(), e );
197        }
198        catch ( RuntimeException e )
199        {
200            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
201                                                                                 e ) );
202
203            throw e;
204        }
205        finally
206        {
207            mavenPluginManager.releaseMojo( mojo, mojoExecution );
208
209            scope.exit();
210
211            Thread.currentThread().setContextClassLoader( oldClassLoader );
212
213            legacySupport.setSession( oldSession );
214        }
215    }
216
217    /**
218     * TODO pluginDescriptor classRealm and artifacts are set as a side effect of this
219     *      call, which is not nice.
220     * @throws PluginResolutionException
221     */
222    public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor )
223        throws PluginResolutionException, PluginManagerException
224    {
225        ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
226        if ( pluginRealm != null )
227        {
228            return pluginRealm;
229        }
230
231        mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
232
233        return pluginDescriptor.getClassRealm();
234    }
235
236    public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
237                                             RepositorySystemSession session )
238        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
239        MojoNotFoundException, InvalidPluginDescriptorException
240    {
241        return mavenPluginManager.getMojoDescriptor( plugin, goal, repositories, session );
242    }
243
244}