001package org.apache.maven.plugin; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.ByteArrayOutputStream; 023import java.io.PrintStream; 024import java.util.List; 025 026import org.apache.maven.execution.MavenSession; 027import org.apache.maven.execution.MojoExecutionEvent; 028import org.apache.maven.execution.MojoExecutionListener; 029import org.apache.maven.execution.scope.internal.MojoExecutionScope; 030import org.apache.maven.model.Plugin; 031import org.apache.maven.plugin.descriptor.MojoDescriptor; 032import org.apache.maven.plugin.descriptor.PluginDescriptor; 033import org.apache.maven.project.MavenProject; 034import org.codehaus.plexus.classworlds.realm.ClassRealm; 035import org.codehaus.plexus.component.annotations.Component; 036import org.codehaus.plexus.component.annotations.Requirement; 037import org.eclipse.aether.RepositorySystemSession; 038import org.eclipse.aether.repository.RemoteRepository; 039 040// TODO: the antrun plugin has its own configurator, the only plugin that does. might need to think about how that works 041// TODO: remove the coreArtifactFilterManager 042 043@Component( role = BuildPluginManager.class ) 044public class DefaultBuildPluginManager 045 implements BuildPluginManager 046{ 047 048 @Requirement 049 private MavenPluginManager mavenPluginManager; 050 051 @Requirement 052 private LegacySupport legacySupport; 053 054 @Requirement 055 private MojoExecutionScope scope; 056 057 private MojoExecutionListener mojoExecutionListener; 058 059 // this tricks plexus-component-metadata generate required metadata 060 @Requirement( role = MojoExecutionListener.class ) 061 private List<MojoExecutionListener> mojoExecutionListeners; 062 063 public void setMojoExecutionListeners( final List<MojoExecutionListener> listeners ) 064 { 065 this.mojoExecutionListeners = listeners; 066 this.mojoExecutionListener = new CompoundMojoExecutionListener( listeners ); 067 } 068 069 /** 070 * @param plugin 071 * @param repositories 072 * @param session 073 * @return PluginDescriptor The component descriptor for the Maven plugin. 074 * @throws PluginNotFoundException The plugin could not be found in any repositories. 075 * @throws PluginResolutionException The plugin could be found but could not be resolved. 076 * @throws InvalidPluginDescriptorException 077 */ 078 public PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session ) 079 throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException 080 { 081 return mavenPluginManager.getPluginDescriptor( plugin, repositories, session ); 082 } 083 084 // ---------------------------------------------------------------------- 085 // Mojo execution 086 // ---------------------------------------------------------------------- 087 088 public void executeMojo( MavenSession session, MojoExecution mojoExecution ) 089 throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException 090 { 091 MavenProject project = session.getCurrentProject(); 092 093 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); 094 095 Mojo mojo = null; 096 097 ClassRealm pluginRealm; 098 try 099 { 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( MavenSession.class, session ); 117 scope.seed( MavenProject.class, project ); 118 scope.seed( MojoExecution.class, mojoExecution ); 119 120 mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution ); 121 122 legacySupport.setSession( session ); 123 124 // NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch! 125 // This is necessary to avoid creating compatibility problems for existing plugins that use 126 // MavenProjectHelper.attachArtifact(..). 127 try 128 { 129 MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent( session, project, mojoExecution, mojo ); 130 131 mojoExecutionListener.beforeMojoExecution( mojoExecutionEvent ); 132 133 mojo.execute(); 134 135 mojoExecutionListener.afterMojoExecutionSuccess( mojoExecutionEvent ); 136 } 137 catch ( ClassCastException e ) 138 { 139 // to be processed in the outer catch block 140 throw e; 141 } 142 catch ( RuntimeException e ) 143 { 144 throw new PluginExecutionException( mojoExecution, project, e ); 145 } 146 } 147 catch ( PluginContainerException e ) 148 { 149 mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo, 150 e ) ); 151 152 throw new PluginExecutionException( mojoExecution, project, e ); 153 } 154 catch ( NoClassDefFoundError e ) 155 { 156 mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo, 157 e ) ); 158 159 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); 160 PrintStream ps = new PrintStream( os ); 161 ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": " 162 + e.getMessage() ); 163 pluginRealm.display( ps ); 164 165 Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e ); 166 167 throw new PluginExecutionException( mojoExecution, project, wrapper ); 168 } 169 catch ( LinkageError e ) 170 { 171 mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo, 172 e ) ); 173 174 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); 175 PrintStream ps = new PrintStream( os ); 176 ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": " 177 + e.getClass().getName() + ": " + e.getMessage() ); 178 pluginRealm.display( ps ); 179 180 Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e ); 181 182 throw new PluginExecutionException( mojoExecution, project, wrapper ); 183 } 184 catch ( ClassCastException e ) 185 { 186 mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo, 187 e ) ); 188 189 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); 190 PrintStream ps = new PrintStream( os ); 191 ps.println( "A type incompatibility occured while executing " + mojoDescriptor.getId() + ": " 192 + e.getMessage() ); 193 pluginRealm.display( ps ); 194 195 throw new PluginExecutionException( mojoExecution, project, os.toString(), e ); 196 } 197 catch ( RuntimeException e ) 198 { 199 mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo, 200 e ) ); 201 202 throw e; 203 } 204 finally 205 { 206 mavenPluginManager.releaseMojo( mojo, mojoExecution ); 207 208 scope.exit(); 209 210 Thread.currentThread().setContextClassLoader( oldClassLoader ); 211 212 legacySupport.setSession( oldSession ); 213 } 214 } 215 216 /** 217 * TODO pluginDescriptor classRealm and artifacts are set as a side effect of this 218 * call, which is not nice. 219 * @throws PluginResolutionException 220 */ 221 public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor ) 222 throws PluginResolutionException, PluginManagerException 223 { 224 ClassRealm pluginRealm = pluginDescriptor.getClassRealm(); 225 if ( pluginRealm != null ) 226 { 227 return pluginRealm; 228 } 229 230 mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null ); 231 232 return pluginDescriptor.getClassRealm(); 233 } 234 235 public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories, 236 RepositorySystemSession session ) 237 throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, 238 MojoNotFoundException, InvalidPluginDescriptorException 239 { 240 return mavenPluginManager.getMojoDescriptor( plugin, goal, repositories, session ); 241 } 242 243}