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