View Javadoc
1   package org.apache.maven.plugin;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.ByteArrayOutputStream;
23  import java.io.PrintStream;
24  import java.util.List;
25  
26  import org.apache.maven.execution.MavenSession;
27  import org.apache.maven.execution.MojoExecutionEvent;
28  import org.apache.maven.execution.MojoExecutionListener;
29  import org.apache.maven.execution.scope.internal.MojoExecutionScope;
30  import org.apache.maven.model.Plugin;
31  import org.apache.maven.plugin.descriptor.MojoDescriptor;
32  import org.apache.maven.plugin.descriptor.PluginDescriptor;
33  import org.apache.maven.project.MavenProject;
34  import org.codehaus.plexus.classworlds.realm.ClassRealm;
35  import org.codehaus.plexus.component.annotations.Component;
36  import org.codehaus.plexus.component.annotations.Requirement;
37  import org.eclipse.aether.RepositorySystemSession;
38  import org.eclipse.aether.repository.RemoteRepository;
39  
40  // TODO: the antrun plugin has its own configurator, the only plugin that does. might need to think about how that works
41  // TODO: remove the coreArtifactFilterManager
42  
43  @Component( role = BuildPluginManager.class )
44  public class DefaultBuildPluginManager
45      implements BuildPluginManager
46  {
47  
48      @Requirement
49      private MavenPluginManager mavenPluginManager;
50  
51      @Requirement
52      private LegacySupport legacySupport;
53  
54      @Requirement
55      private MojoExecutionScope scope;
56  
57      private MojoExecutionListener mojoExecutionListener;
58  
59      // this tricks plexus-component-metadata generate required metadata
60      @Requirement( role = MojoExecutionListener.class )
61      private List<MojoExecutionListener> mojoExecutionListeners;
62  
63      public void setMojoExecutionListeners( final List<MojoExecutionListener> listeners )
64      {
65          this.mojoExecutionListeners = listeners;
66          this.mojoExecutionListener = new CompoundMojoExecutionListener( listeners );
67      }
68  
69      /**
70       * @param plugin
71       * @param repositories
72       * @param session
73       * @return PluginDescriptor The component descriptor for the Maven plugin.
74       * @throws PluginNotFoundException The plugin could not be found in any repositories.
75       * @throws PluginResolutionException The plugin could be found but could not be resolved.
76       * @throws InvalidPluginDescriptorException 
77       */
78      public PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
79          throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException
80      {
81          return mavenPluginManager.getPluginDescriptor( plugin, repositories, session );
82      }
83  
84      // ----------------------------------------------------------------------
85      // Mojo execution
86      // ----------------------------------------------------------------------
87  
88      public void executeMojo( MavenSession session, MojoExecution mojoExecution )
89          throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException
90      {
91          MavenProject project = session.getCurrentProject();
92  
93          MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
94  
95          Mojo mojo = null;
96  
97          ClassRealm pluginRealm;
98          try
99          {
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( MavenSession.class, session );
117             scope.seed( MavenProject.class, project );
118             scope.seed( MojoExecution.class, mojoExecution );
119             
120             mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution );
121 
122             legacySupport.setSession( session );
123 
124             // NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch!
125             // This is necessary to avoid creating compatibility problems for existing plugins that use
126             // MavenProjectHelper.attachArtifact(..).
127             try
128             {
129                 MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent( session, project, mojoExecution, mojo );
130 
131                 mojoExecutionListener.beforeMojoExecution( mojoExecutionEvent );
132 
133                 mojo.execute();
134 
135                 mojoExecutionListener.afterMojoExecutionSuccess( mojoExecutionEvent );
136             }
137             catch ( ClassCastException e )
138             {
139                 // to be processed in the outer catch block
140                 throw e;
141             }
142             catch ( RuntimeException e )
143             {
144                 throw new PluginExecutionException( mojoExecution, project, e );
145             }
146         }
147         catch ( PluginContainerException e )
148         {
149             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
150                                                                                  e ) );
151 
152             throw new PluginExecutionException( mojoExecution, project, e );
153         }
154         catch ( NoClassDefFoundError e )
155         {
156             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
157                                                                                  e ) );
158 
159             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
160             PrintStream ps = new PrintStream( os );
161             ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": "
162                 + e.getMessage() );
163             pluginRealm.display( ps );
164 
165             Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
166 
167             throw new PluginExecutionException( mojoExecution, project, wrapper );
168         }
169         catch ( LinkageError e )
170         {
171             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
172                                                                                  e ) );
173 
174             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
175             PrintStream ps = new PrintStream( os );
176             ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
177                 + e.getClass().getName() + ": " + e.getMessage() );
178             pluginRealm.display( ps );
179 
180             Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
181 
182             throw new PluginExecutionException( mojoExecution, project, wrapper );
183         }
184         catch ( ClassCastException e )
185         {
186             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
187                                                                                  e ) );
188 
189             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
190             PrintStream ps = new PrintStream( os );
191             ps.println( "A type incompatibility occured while executing " + mojoDescriptor.getId() + ": "
192                 + e.getMessage() );
193             pluginRealm.display( ps );
194 
195             throw new PluginExecutionException( mojoExecution, project, os.toString(), e );
196         }
197         catch ( RuntimeException e )
198         {
199             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
200                                                                                  e ) );
201 
202             throw e;
203         }
204         finally
205         {
206             mavenPluginManager.releaseMojo( mojo, mojoExecution );
207 
208             scope.exit();
209 
210             Thread.currentThread().setContextClassLoader( oldClassLoader );
211 
212             legacySupport.setSession( oldSession );
213         }
214     }
215 
216     /**
217      * TODO pluginDescriptor classRealm and artifacts are set as a side effect of this
218      *      call, which is not nice.
219      * @throws PluginResolutionException 
220      */
221     public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor ) 
222         throws PluginResolutionException, PluginManagerException
223     {
224         ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
225         if ( pluginRealm != null )
226         {
227             return pluginRealm;
228         }
229 
230         mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
231 
232         return pluginDescriptor.getClassRealm();
233     }
234 
235     public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
236                                              RepositorySystemSession session )
237         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
238         MojoNotFoundException, InvalidPluginDescriptorException
239     {
240         return mavenPluginManager.getMojoDescriptor( plugin, goal, repositories, session );
241     }
242 
243 }