1 package org.apache.maven.extension;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static org.apache.maven.container.ContainerUtils.findChildComponentHints;
23
24 import org.apache.maven.MavenArtifactFilterManager;
25 import org.apache.maven.artifact.Artifact;
26 import org.apache.maven.artifact.ArtifactUtils;
27 import org.apache.maven.artifact.factory.ArtifactFactory;
28 import org.apache.maven.artifact.handler.ArtifactHandler;
29 import org.apache.maven.artifact.manager.WagonManager;
30 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
31 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
32 import org.apache.maven.artifact.metadata.ResolutionGroup;
33 import org.apache.maven.artifact.repository.ArtifactRepository;
34 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
35 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
36 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
37 import org.apache.maven.artifact.resolver.ArtifactResolver;
38 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
39 import org.apache.maven.model.Extension;
40 import org.apache.maven.plugin.DefaultPluginManager;
41 import org.apache.maven.project.MavenProject;
42 import org.apache.maven.wagon.Wagon;
43 import org.codehaus.classworlds.ClassRealm;
44 import org.codehaus.classworlds.ClassWorld;
45 import org.codehaus.classworlds.DuplicateRealmException;
46 import org.codehaus.classworlds.NoSuchRealmException;
47 import org.codehaus.plexus.DefaultPlexusContainer;
48 import org.codehaus.plexus.PlexusConstants;
49 import org.codehaus.plexus.PlexusContainer;
50 import org.codehaus.plexus.PlexusContainerException;
51 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
52 import org.codehaus.plexus.context.Context;
53 import org.codehaus.plexus.context.ContextException;
54 import org.codehaus.plexus.logging.AbstractLogEnabled;
55 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
56 import org.codehaus.plexus.util.xml.Xpp3Dom;
57 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
58
59 import java.io.File;
60 import java.io.InputStream;
61 import java.io.InputStreamReader;
62 import java.util.Collections;
63 import java.util.HashMap;
64 import java.util.Iterator;
65 import java.util.LinkedHashSet;
66 import java.util.Map;
67 import java.util.Set;
68 import java.util.jar.JarFile;
69
70
71
72
73
74
75
76
77 public class DefaultExtensionManager
78 extends AbstractLogEnabled
79 implements ExtensionManager, Contextualizable
80 {
81 private ArtifactResolver artifactResolver;
82
83 private ArtifactFactory artifactFactory;
84
85 private ArtifactMetadataSource artifactMetadataSource;
86
87 private DefaultPlexusContainer container;
88
89 private ArtifactFilter artifactFilter = MavenArtifactFilterManager.createExtensionFilter();
90
91 private WagonManager wagonManager;
92
93 private PlexusContainer extensionContainer;
94
95 private static final String CONTAINER_NAME = "extensions";
96
97 public void addExtension( Extension extension,
98 MavenProject project,
99 ArtifactRepository localRepository )
100 throws ArtifactResolutionException, PlexusContainerException, ArtifactNotFoundException
101 {
102 String extensionId = ArtifactUtils.versionlessKey( extension.getGroupId(), extension.getArtifactId() );
103
104 getLogger().debug( "Initialising extension: " + extensionId );
105
106 Artifact artifact = (Artifact) project.getExtensionArtifactMap().get( extensionId );
107
108 if ( artifact != null )
109 {
110 ArtifactFilter filter = new ProjectArtifactExceptionFilter( artifactFilter, project.getArtifact() );
111
112 ResolutionGroup resolutionGroup;
113 try
114 {
115 resolutionGroup = artifactMetadataSource.retrieve( artifact, localRepository,
116 project.getRemoteArtifactRepositories() );
117 }
118 catch ( ArtifactMetadataRetrievalException e )
119 {
120 throw new ArtifactResolutionException( "Unable to download metadata from repository for plugin '" +
121 artifact.getId() + "': " + e.getMessage(), artifact, e );
122 }
123
124
125
126 Set rgArtifacts = resolutionGroup.getArtifacts();
127 rgArtifacts = DefaultPluginManager.checkPlexusUtils( rgArtifacts, artifactFactory );
128
129 Set dependencies = new LinkedHashSet();
130 dependencies.add( artifact );
131 dependencies.addAll( rgArtifacts );
132
133
134
135
136 ArtifactResolutionResult result = artifactResolver.resolveTransitively( dependencies, project.getArtifact(),
137 Collections.EMPTY_MAP,
138
139 localRepository,
140 project.getRemoteArtifactRepositories(),
141 artifactMetadataSource, filter );
142
143
144
145
146
147
148 Set artifacts = result.getArtifacts();
149
150
151
152
153
154 if ( extensionContainsLifeycle( artifact.getFile() ) )
155 {
156 for ( Iterator i = artifacts.iterator(); i.hasNext(); )
157 {
158 Artifact a = (Artifact) i.next();
159
160 if ( artifactFilter.include( a ) )
161 {
162 getLogger().debug( "Adding extension to core container: " + a.getFile() );
163
164 container.addJarResource( a.getFile() );
165 }
166 }
167 }
168 else if ( artifacts.size() == 2 )
169 {
170 for ( Iterator i = artifacts.iterator(); i.hasNext(); )
171 {
172 Artifact a = (Artifact) i.next();
173
174 if ( !a.getArtifactId().equals( "plexus-utils" ) )
175 {
176 a = project.replaceWithActiveArtifact( a );
177
178 getLogger().debug( "Adding extension to core container: " + a.getFile() );
179
180 container.addJarResource( a.getFile() );
181 }
182 }
183 }
184 else
185 {
186
187
188
189 if ( extensionContainer == null )
190 {
191 extensionContainer = createContainer();
192 }
193
194 for ( Iterator i = result.getArtifacts().iterator(); i.hasNext(); )
195 {
196 Artifact a = (Artifact) i.next();
197
198 a = project.replaceWithActiveArtifact( a );
199
200 getLogger().debug( "Adding to extension classpath: " + a.getFile() );
201
202 extensionContainer.addJarResource( a.getFile() );
203 }
204
205 if ( getLogger().isDebugEnabled() )
206 {
207 getLogger().debug( "Extension container contents:" );
208 extensionContainer.getContainerRealm().display();
209 }
210 }
211 }
212 }
213
214 private PlexusContainer createContainer()
215 throws PlexusContainerException
216 {
217 DefaultPlexusContainer child = new DefaultPlexusContainer();
218
219 ClassWorld classWorld = container.getClassWorld();
220 child.setClassWorld( classWorld );
221
222 ClassRealm childRealm = null;
223
224
225
226 String childRealmId = "plexus.core.child-container[" + CONTAINER_NAME + "]";
227 try
228 {
229 childRealm = classWorld.getRealm( childRealmId );
230 }
231 catch ( NoSuchRealmException e )
232 {
233 try
234 {
235 childRealm = classWorld.newRealm( childRealmId );
236 }
237 catch ( DuplicateRealmException impossibleError )
238 {
239 getLogger().error( "An impossible error has occurred. After getRealm() failed, newRealm() " +
240 "produced duplication error on same id!", impossibleError );
241 }
242 }
243
244 childRealm.setParent( container.getContainerRealm() );
245
246 child.setCoreRealm( childRealm );
247
248 child.setName( CONTAINER_NAME );
249
250
251
252
253
254
255
256
257
258
259 child.setLoggerManager( container.getLoggerManager() );
260
261 child.initialize();
262
263 child.start();
264
265 return child;
266 }
267
268 public void registerWagons()
269 {
270 if ( extensionContainer != null )
271 {
272 Set<String> wagons = findChildComponentHints( Wagon.ROLE, container, extensionContainer );
273 if ( wagons != null && !wagons.isEmpty() )
274 {
275 getLogger().debug( "Wagons to register: " + wagons );
276 wagonManager.registerWagons( wagons, extensionContainer );
277 }
278 }
279 else
280 {
281 getLogger().debug( "Wagons could not be registered as the extension container was never created" );
282 }
283 }
284
285 @SuppressWarnings( "unchecked" )
286 public Map<String, ArtifactHandler> getArtifactTypeHandlers()
287 {
288 Map<String, ArtifactHandler> result = new HashMap<String, ArtifactHandler>();
289
290 if ( extensionContainer != null )
291 {
292 try
293 {
294 result.putAll( extensionContainer.lookupMap( ArtifactHandler.ROLE ) );
295 }
296 catch ( ComponentLookupException e )
297 {
298 getLogger().debug( "ArtifactHandler extensions could not be loaded: " + e.getMessage(), e );
299 }
300 }
301 else
302 {
303 try
304 {
305 result.putAll( container.lookupMap( ArtifactHandler.ROLE ) );
306 }
307 catch ( ComponentLookupException e )
308 {
309 getLogger().debug( "ArtifactHandler extensions could not be loaded: " + e.getMessage(), e );
310 }
311 }
312
313 return result;
314 }
315
316 public void contextualize( Context context )
317 throws ContextException
318 {
319 container = (DefaultPlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
320 }
321
322 private static final class ProjectArtifactExceptionFilter
323 implements ArtifactFilter
324 {
325 private ArtifactFilter passThroughFilter;
326
327 private String projectDependencyConflictId;
328
329 ProjectArtifactExceptionFilter( ArtifactFilter passThroughFilter,
330 Artifact projectArtifact )
331 {
332 this.passThroughFilter = passThroughFilter;
333 projectDependencyConflictId = projectArtifact.getDependencyConflictId();
334 }
335
336 public boolean include( Artifact artifact )
337 {
338 String depConflictId = artifact.getDependencyConflictId();
339
340 return projectDependencyConflictId.equals( depConflictId ) || passThroughFilter.include( artifact );
341 }
342 }
343
344 private boolean extensionContainsLifeycle( File extension )
345 {
346 JarFile f;
347
348 try
349 {
350 f = new JarFile( extension );
351
352 InputStream is = f.getInputStream( f.getEntry( "META-INF/plexus/components.xml" ) );
353
354 if ( is == null )
355 {
356 return false;
357 }
358
359 Xpp3Dom dom = Xpp3DomBuilder.build( new InputStreamReader( is ) );
360
361 Xpp3Dom[] components = dom.getChild( "components" ).getChildren( "component" );
362
363 for ( int i = 0; i < components.length; i++ )
364 {
365 if ( components[i].getChild( "role" ).getValue().equals( "org.apache.maven.lifecycle.mapping.LifecycleMapping" ) )
366 {
367 return true;
368 }
369 }
370 }
371 catch( Exception e )
372 {
373
374 }
375
376 return false;
377 }
378 }