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,
79                                          RepositorySystemSession session )
80          throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
81          InvalidPluginDescriptorException
82      {
83          return mavenPluginManager.getPluginDescriptor( plugin, repositories, session );
84      }
85  
86      // ----------------------------------------------------------------------
87      // Mojo execution
88      // ----------------------------------------------------------------------
89  
90      public void executeMojo( MavenSession session, MojoExecution mojoExecution )
91          throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException
92      {
93          MavenProject project = session.getCurrentProject();
94  
95          MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
96  
97          Mojo mojo = null;
98  
99          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 }