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  /**
44   * DefaultBuildPluginManager
45   */
46  @Component( role = BuildPluginManager.class )
47  public class DefaultBuildPluginManager
48      implements BuildPluginManager
49  {
50  
51      @Requirement
52      private MavenPluginManager mavenPluginManager;
53  
54      @Requirement
55      private LegacySupport legacySupport;
56  
57      @Requirement
58      private MojoExecutionScope scope;
59  
60      private MojoExecutionListener mojoExecutionListener;
61  
62      // this tricks plexus-component-metadata generate required metadata
63      @Requirement( role = MojoExecutionListener.class )
64      private List<MojoExecutionListener> mojoExecutionListeners;
65  
66      public void setMojoExecutionListeners( final List<MojoExecutionListener> listeners )
67      {
68          this.mojoExecutionListeners = listeners;
69          this.mojoExecutionListener = new CompoundMojoExecutionListener( listeners );
70      }
71  
72      /**
73       * @param plugin
74       * @param repositories
75       * @param session
76       * @return PluginDescriptor The component descriptor for the Maven plugin.
77       * @throws PluginNotFoundException The plugin could not be found in any repositories.
78       * @throws PluginResolutionException The plugin could be found but could not be resolved.
79       * @throws InvalidPluginDescriptorException
80       */
81      public PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories,
82                                          RepositorySystemSession session )
83          throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
84          InvalidPluginDescriptorException
85      {
86          return mavenPluginManager.getPluginDescriptor( plugin, repositories, session );
87      }
88  
89      // ----------------------------------------------------------------------
90      // Mojo execution
91      // ----------------------------------------------------------------------
92  
93      public void executeMojo( MavenSession session, MojoExecution mojoExecution )
94          throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException
95      {
96          MavenProject project = session.getCurrentProject();
97  
98          MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
99  
100         Mojo mojo = null;
101 
102         ClassRealm pluginRealm;
103         try
104         {
105             pluginRealm = getPluginRealm( session, mojoDescriptor.getPluginDescriptor() );
106         }
107         catch ( PluginResolutionException e )
108         {
109             throw new PluginExecutionException( mojoExecution, project, e );
110         }
111 
112         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
113         Thread.currentThread().setContextClassLoader( pluginRealm );
114 
115         MavenSession oldSession = legacySupport.getSession();
116 
117         scope.enter();
118 
119         try
120         {
121             scope.seed( MavenProject.class, project );
122             scope.seed( MojoExecution.class, mojoExecution );
123 
124             mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution );
125 
126             legacySupport.setSession( session );
127 
128             // NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch!
129             // This is necessary to avoid creating compatibility problems for existing plugins that use
130             // MavenProjectHelper.attachArtifact(..).
131             try
132             {
133                 MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent( session, project, mojoExecution, mojo );
134 
135                 mojoExecutionListener.beforeMojoExecution( mojoExecutionEvent );
136 
137                 mojo.execute();
138 
139                 mojoExecutionListener.afterMojoExecutionSuccess( mojoExecutionEvent );
140             }
141             catch ( ClassCastException e )
142             {
143                 // to be processed in the outer catch block
144                 throw e;
145             }
146             catch ( RuntimeException e )
147             {
148                 throw new PluginExecutionException( mojoExecution, project, e );
149             }
150         }
151         catch ( PluginContainerException e )
152         {
153             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
154                                                                                  e ) );
155 
156             throw new PluginExecutionException( mojoExecution, project, e );
157         }
158         catch ( NoClassDefFoundError e )
159         {
160             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
161                                                                                  e ) );
162 
163             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
164             PrintStream ps = new PrintStream( os );
165             ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": "
166                 + e.getMessage() );
167             pluginRealm.display( ps );
168 
169             Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
170 
171             throw new PluginExecutionException( mojoExecution, project, wrapper );
172         }
173         catch ( LinkageError e )
174         {
175             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
176                                                                                  e ) );
177 
178             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
179             PrintStream ps = new PrintStream( os );
180             ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
181                 + e.getClass().getName() + ": " + e.getMessage() );
182             pluginRealm.display( ps );
183 
184             Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
185 
186             throw new PluginExecutionException( mojoExecution, project, wrapper );
187         }
188         catch ( ClassCastException e )
189         {
190             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
191                                                                                  e ) );
192 
193             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
194             PrintStream ps = new PrintStream( os );
195             ps.println( "A type incompatibility occurred while executing " + mojoDescriptor.getId() + ": "
196                 + e.getMessage() );
197             pluginRealm.display( ps );
198 
199             throw new PluginExecutionException( mojoExecution, project, os.toString(), e );
200         }
201         catch ( RuntimeException e )
202         {
203             mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
204                                                                                  e ) );
205 
206             throw e;
207         }
208         finally
209         {
210             mavenPluginManager.releaseMojo( mojo, mojoExecution );
211 
212             scope.exit();
213 
214             Thread.currentThread().setContextClassLoader( oldClassLoader );
215 
216             legacySupport.setSession( oldSession );
217         }
218     }
219 
220     /**
221      * TODO pluginDescriptor classRealm and artifacts are set as a side effect of this
222      *      call, which is not nice.
223      * @throws PluginResolutionException
224      */
225     public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor )
226         throws PluginResolutionException, PluginManagerException
227     {
228         ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
229         if ( pluginRealm != null )
230         {
231             return pluginRealm;
232         }
233 
234         mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
235 
236         return pluginDescriptor.getClassRealm();
237     }
238 
239     public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
240                                              RepositorySystemSession session )
241         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
242         MojoNotFoundException, InvalidPluginDescriptorException
243     {
244         return mavenPluginManager.getMojoDescriptor( plugin, goal, repositories, session );
245     }
246 
247 }