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