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