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