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 javax.inject.Inject;
27  import javax.inject.Named;
28  import javax.inject.Singleton;
29  
30  import org.apache.maven.api.Project;
31  import org.apache.maven.api.plugin.MojoException;
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.execution.MojoExecutionEvent;
34  import org.apache.maven.execution.MojoExecutionListener;
35  import org.apache.maven.execution.scope.internal.MojoExecutionScope;
36  import org.apache.maven.internal.impl.DefaultLog;
37  import org.apache.maven.internal.impl.DefaultMojoExecution;
38  import org.apache.maven.internal.impl.DefaultSession;
39  import org.apache.maven.model.Plugin;
40  import org.apache.maven.plugin.descriptor.MojoDescriptor;
41  import org.apache.maven.plugin.descriptor.PluginDescriptor;
42  import org.apache.maven.plugin.logging.Log;
43  import org.apache.maven.project.MavenProject;
44  import org.codehaus.plexus.classworlds.realm.ClassRealm;
45  import org.eclipse.aether.RepositorySystemSession;
46  import org.eclipse.aether.repository.RemoteRepository;
47  import org.slf4j.LoggerFactory;
48  
49  // TODO the antrun plugin has its own configurator, the only plugin that does. might need to think about how that works
50  // TODO remove the coreArtifactFilterManager
51  
52  /**
53   * DefaultBuildPluginManager
54   */
55  @Named
56  @Singleton
57  public class DefaultBuildPluginManager
58      implements BuildPluginManager
59  {
60  
61      private final MavenPluginManager mavenPluginManager;
62      private final LegacySupport legacySupport;
63      private final MojoExecutionScope scope;
64      private final MojoExecutionListener mojoExecutionListener;
65  
66      @Inject
67      public DefaultBuildPluginManager(
68              MavenPluginManager mavenPluginManager,
69              LegacySupport legacySupport,
70              MojoExecutionScope scope,
71              List<MojoExecutionListener> mojoExecutionListeners )
72      {
73          this.mavenPluginManager = mavenPluginManager;
74          this.legacySupport = legacySupport;
75          this.scope = scope;
76          this.mojoExecutionListener = new CompoundMojoExecutionListener( mojoExecutionListeners );
77      }
78  
79      /**
80       * @param plugin
81       * @param repositories
82       * @param session
83       * @return PluginDescriptor The component descriptor for the Maven plugin.
84       * @throws PluginNotFoundException The plugin could not be found in any repositories.
85       * @throws PluginResolutionException The plugin could be found but could not be resolved.
86       * @throws InvalidPluginDescriptorException
87       */
88      public PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories,
89                                          RepositorySystemSession session )
90          throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
91          InvalidPluginDescriptorException
92      {
93          return mavenPluginManager.getPluginDescriptor( plugin, repositories, session );
94      }
95  
96      // ----------------------------------------------------------------------
97      // Mojo execution
98      // ----------------------------------------------------------------------
99  
100     public void executeMojo( MavenSession session, MojoExecution mojoExecution )
101         throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException
102     {
103         MavenProject project = session.getCurrentProject();
104 
105         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
106 
107         Mojo mojo = null;
108 
109         ClassRealm pluginRealm;
110         try
111         {
112             pluginRealm = getPluginRealm( session, mojoDescriptor.getPluginDescriptor() );
113         }
114         catch ( PluginResolutionException e )
115         {
116             throw new PluginExecutionException( mojoExecution, project, e );
117         }
118 
119         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
120         Thread.currentThread().setContextClassLoader( pluginRealm );
121 
122         MavenSession oldSession = legacySupport.getSession();
123 
124         scope.enter();
125 
126         try
127         {
128             scope.seed( MavenProject.class, project );
129             scope.seed( MojoExecution.class, mojoExecution );
130             scope.seed( org.apache.maven.api.plugin.Log.class, new DefaultLog(
131                     LoggerFactory.getLogger( mojoExecution.getMojoDescriptor().getFullGoalName() ) ) );
132             scope.seed( Project.class, ( ( DefaultSession) session.getSession() ).getProject( project ) );
133             scope.seed( org.apache.maven.api.MojoExecution.class, new DefaultMojoExecution( mojoExecution ) );
134 
135             if ( mojoDescriptor.isV4Api() )
136             {
137                 org.apache.maven.api.plugin.Mojo mojoV4 = mavenPluginManager.getConfiguredMojo(
138                         org.apache.maven.api.plugin.Mojo.class, session, mojoExecution );
139                 mojo = new MojoWrapper( mojoV4 );
140             }
141             else
142             {
143                 mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution );
144             }
145 
146             legacySupport.setSession( session );
147 
148             // NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch!
149             // This is necessary to avoid creating compatibility problems for existing plugins that use
150             // MavenProjectHelper.attachArtifact(..).
151             try
152             {
153                 MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent( session, project, mojoExecution, mojo );
154                 mojoExecutionListener.beforeMojoExecution( mojoExecutionEvent );
155                 mojo.execute();
156                 mojoExecutionListener.afterMojoExecutionSuccess( mojoExecutionEvent );
157             }
158             catch ( ClassCastException e )
159             {
160                 // to be processed in the outer catch block
161                 throw e;
162             }
163             catch ( RuntimeException e )
164             {
165                 throw new PluginExecutionException( mojoExecution, project, e );
166             }
167         }
168         catch ( PluginContainerException e )
169         {
170             mojoExecutionListener.afterExecutionFailure(
171                     new MojoExecutionEvent( session, project, mojoExecution, mojo, e ) );
172             throw new PluginExecutionException( mojoExecution, project, e );
173         }
174         catch ( NoClassDefFoundError e )
175         {
176             mojoExecutionListener.afterExecutionFailure(
177                     new MojoExecutionEvent( session, project, mojoExecution, mojo, e ) );
178             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
179             PrintStream ps = new PrintStream( os );
180             ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": "
181                 + e.getMessage() );
182             pluginRealm.display( ps );
183             Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
184             throw new PluginExecutionException( mojoExecution, project, wrapper );
185         }
186         catch ( LinkageError e )
187         {
188             mojoExecutionListener.afterExecutionFailure(
189                     new MojoExecutionEvent( session, project, mojoExecution, mojo, e ) );
190             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
191             PrintStream ps = new PrintStream( os );
192             ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
193                 + e.getClass().getName() + ": " + e.getMessage() );
194             pluginRealm.display( ps );
195             Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
196             throw new PluginExecutionException( mojoExecution, project, wrapper );
197         }
198         catch ( ClassCastException e )
199         {
200             mojoExecutionListener.afterExecutionFailure(
201                     new MojoExecutionEvent( session, project, mojoExecution, mojo, e ) );
202             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
203             PrintStream ps = new PrintStream( os );
204             ps.println( "A type incompatibility occurred while executing " + mojoDescriptor.getId() + ": "
205                 + e.getMessage() );
206             pluginRealm.display( ps );
207             throw new PluginExecutionException( mojoExecution, project, os.toString(), e );
208         }
209         catch ( RuntimeException e )
210         {
211             mojoExecutionListener.afterExecutionFailure(
212                     new MojoExecutionEvent( session, project, mojoExecution, mojo, e ) );
213             throw e;
214         }
215         finally
216         {
217             mavenPluginManager.releaseMojo( mojo, mojoExecution );
218             scope.exit();
219             Thread.currentThread().setContextClassLoader( oldClassLoader );
220             legacySupport.setSession( oldSession );
221         }
222     }
223 
224     /**
225      * TODO pluginDescriptor classRealm and artifacts are set as a side effect of this
226      *      call, which is not nice.
227      * @throws PluginResolutionException
228      */
229     public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor )
230         throws PluginResolutionException, PluginManagerException
231     {
232         ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
233         if ( pluginRealm != null )
234         {
235             return pluginRealm;
236         }
237 
238         mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
239 
240         return pluginDescriptor.getClassRealm();
241     }
242 
243     public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
244                                              RepositorySystemSession session )
245         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
246         MojoNotFoundException, InvalidPluginDescriptorException
247     {
248         return mavenPluginManager.getMojoDescriptor( plugin, goal, repositories, session );
249     }
250 
251     private static class MojoWrapper implements Mojo
252     {
253         private final org.apache.maven.api.plugin.Mojo mojoV4;
254 
255         MojoWrapper( org.apache.maven.api.plugin.Mojo mojoV4 )
256         {
257             this.mojoV4 = mojoV4;
258         }
259 
260         @Override
261         public void execute() throws MojoExecutionException, MojoFailureException
262         {
263             try
264             {
265                 mojoV4.execute();
266             }
267             catch ( MojoException e )
268             {
269                 throw new MojoExecutionException( e.getMessage(), e );
270             }
271         }
272 
273         @Override
274         public void setLog( Log log )
275         {
276         }
277 
278         @Override
279         public Log getLog()
280         {
281             return null;
282         }
283     }
284 }