1 package org.apache.maven.project;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.LinkedHashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 import org.apache.maven.artifact.InvalidRepositoryException;
34 import org.apache.maven.artifact.repository.ArtifactRepository;
35 import org.apache.maven.classrealm.ClassRealmManager;
36 import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
37 import org.apache.maven.model.Build;
38 import org.apache.maven.model.Extension;
39 import org.apache.maven.model.Model;
40 import org.apache.maven.model.Plugin;
41 import org.apache.maven.model.Repository;
42 import org.apache.maven.plugin.ExtensionRealmCache;
43 import org.apache.maven.plugin.PluginArtifactsCache;
44 import org.apache.maven.plugin.PluginResolutionException;
45 import org.apache.maven.plugin.internal.PluginDependenciesResolver;
46 import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
47 import org.apache.maven.plugin.version.PluginVersionRequest;
48 import org.apache.maven.plugin.version.PluginVersionResolutionException;
49 import org.apache.maven.plugin.version.PluginVersionResolver;
50 import org.apache.maven.repository.RepositorySystem;
51 import org.apache.maven.session.scope.internal.SessionScopeModule;
52 import org.codehaus.plexus.DefaultPlexusContainer;
53 import org.codehaus.plexus.PlexusContainer;
54 import org.codehaus.plexus.classworlds.realm.ClassRealm;
55 import org.codehaus.plexus.component.annotations.Component;
56 import org.codehaus.plexus.component.annotations.Requirement;
57 import org.codehaus.plexus.logging.Logger;
58 import org.eclipse.aether.artifact.Artifact;
59 import org.eclipse.aether.graph.DependencyFilter;
60 import org.eclipse.aether.graph.DependencyNode;
61 import org.eclipse.aether.repository.RemoteRepository;
62 import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
63 import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
64
65
66
67
68
69
70
71
72 @Component( role = ProjectBuildingHelper.class )
73 public class DefaultProjectBuildingHelper
74 implements ProjectBuildingHelper
75 {
76
77 @Requirement
78 private Logger logger;
79
80 @Requirement
81 private PlexusContainer container;
82
83 @Requirement
84 private ClassRealmManager classRealmManager;
85
86 @Requirement
87 private PluginArtifactsCache pluginArtifactsCache;
88
89 @Requirement
90 private ExtensionRealmCache extensionRealmCache;
91
92 @Requirement
93 private ProjectRealmCache projectRealmCache;
94
95 @Requirement
96 private RepositorySystem repositorySystem;
97
98 @Requirement
99 private PluginVersionResolver pluginVersionResolver;
100
101 @Requirement
102 private PluginDependenciesResolver pluginDependenciesResolver;
103
104 private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder();
105
106 public List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
107 List<ArtifactRepository> externalRepositories,
108 ProjectBuildingRequest request )
109 throws InvalidRepositoryException
110 {
111 List<ArtifactRepository> internalRepositories = new ArrayList<ArtifactRepository>();
112
113 for ( Repository repository : pomRepositories )
114 {
115 internalRepositories.add( repositorySystem.buildArtifactRepository( repository ) );
116 }
117
118 repositorySystem.injectMirror( request.getRepositorySession(), internalRepositories );
119
120 repositorySystem.injectProxy( request.getRepositorySession(), internalRepositories );
121
122 repositorySystem.injectAuthentication( request.getRepositorySession(), internalRepositories );
123
124 List<ArtifactRepository> dominantRepositories;
125 List<ArtifactRepository> recessiveRepositories;
126
127 if ( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals( request.getRepositoryMerging() ) )
128 {
129 dominantRepositories = externalRepositories;
130 recessiveRepositories = internalRepositories;
131 }
132 else
133 {
134 dominantRepositories = internalRepositories;
135 recessiveRepositories = externalRepositories;
136 }
137
138 List<ArtifactRepository> artifactRepositories = new ArrayList<ArtifactRepository>();
139 Collection<String> repoIds = new HashSet<String>();
140
141 if ( dominantRepositories != null )
142 {
143 for ( ArtifactRepository repository : dominantRepositories )
144 {
145 repoIds.add( repository.getId() );
146 artifactRepositories.add( repository );
147 }
148 }
149
150 if ( recessiveRepositories != null )
151 {
152 for ( ArtifactRepository repository : recessiveRepositories )
153 {
154 if ( repoIds.add( repository.getId() ) )
155 {
156 artifactRepositories.add( repository );
157 }
158 }
159 }
160
161 artifactRepositories = repositorySystem.getEffectiveRepositories( artifactRepositories );
162
163 return artifactRepositories;
164 }
165
166 public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProject project, Model model,
167 ProjectBuildingRequest request )
168 throws PluginResolutionException, PluginVersionResolutionException
169 {
170 ClassRealm projectRealm;
171
172 List<Plugin> extensionPlugins = new ArrayList<Plugin>();
173
174 Build build = model.getBuild();
175
176 if ( build != null )
177 {
178 for ( Extension extension : build.getExtensions() )
179 {
180 Plugin plugin = new Plugin();
181 plugin.setGroupId( extension.getGroupId() );
182 plugin.setArtifactId( extension.getArtifactId() );
183 plugin.setVersion( extension.getVersion() );
184 extensionPlugins.add( plugin );
185 }
186
187 for ( Plugin plugin : build.getPlugins() )
188 {
189 if ( plugin.isExtensions() )
190 {
191 extensionPlugins.add( plugin );
192 }
193 }
194 }
195
196 if ( extensionPlugins.isEmpty() )
197 {
198 if ( logger.isDebugEnabled() )
199 {
200 logger.debug( "Extension realms for project " + model.getId() + ": (none)" );
201 }
202
203 return new ProjectRealmCache.CacheRecord( null, null );
204 }
205
206 List<ClassRealm> extensionRealms = new ArrayList<ClassRealm>();
207
208 Map<ClassRealm, List<String>> exportedPackages = new HashMap<ClassRealm, List<String>>();
209
210 Map<ClassRealm, List<String>> exportedArtifacts = new HashMap<ClassRealm, List<String>>();
211
212 List<Artifact> publicArtifacts = new ArrayList<Artifact>();
213
214 for ( Plugin plugin : extensionPlugins )
215 {
216 if ( plugin.getVersion() == null )
217 {
218 PluginVersionRequest versionRequest =
219 new DefaultPluginVersionRequest( plugin, request.getRepositorySession(),
220 project.getRemotePluginRepositories() );
221 plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
222 }
223
224 List<Artifact> artifacts;
225
226 PluginArtifactsCache.Key cacheKey =
227 pluginArtifactsCache.createKey( plugin, null, project.getRemotePluginRepositories(),
228 request.getRepositorySession() );
229
230 PluginArtifactsCache.CacheRecord recordArtifacts = pluginArtifactsCache.get( cacheKey );
231
232 if ( recordArtifacts != null )
233 {
234 artifacts = recordArtifacts.artifacts;
235 }
236 else
237 {
238 try
239 {
240 artifacts = resolveExtensionArtifacts( plugin, project.getRemotePluginRepositories(), request );
241
242 recordArtifacts = pluginArtifactsCache.put( cacheKey, artifacts );
243 }
244 catch ( PluginResolutionException e )
245 {
246 pluginArtifactsCache.put( cacheKey, e );
247
248 pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
249
250 throw e;
251 }
252 }
253
254 pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
255
256 ClassRealm extensionRealm;
257 ExtensionDescriptor extensionDescriptor = null;
258
259 final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey( artifacts );
260
261 ExtensionRealmCache.CacheRecord recordRealm = extensionRealmCache.get( extensionKey );
262
263 if ( recordRealm != null )
264 {
265 extensionRealm = recordRealm.realm;
266 extensionDescriptor = recordRealm.desciptor;
267 }
268 else
269 {
270 extensionRealm = classRealmManager.createExtensionRealm( plugin, artifacts );
271
272 try
273 {
274 ( (DefaultPlexusContainer) container ).discoverComponents( extensionRealm,
275 new SessionScopeModule( container ),
276 new MojoExecutionScopeModule( container ) );
277 }
278 catch ( Exception e )
279 {
280 throw new IllegalStateException( "Failed to discover components in extension realm "
281 + extensionRealm.getId(), e );
282 }
283
284 Artifact extensionArtifact = artifacts.get( 0 );
285 try
286 {
287 extensionDescriptor = extensionDescriptorBuilder.build( extensionArtifact.getFile() );
288 }
289 catch ( IOException e )
290 {
291 String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
292 if ( logger.isDebugEnabled() )
293 {
294 logger.error( message, e );
295 }
296 else
297 {
298 logger.error( message );
299 }
300 }
301
302 recordRealm = extensionRealmCache.put( extensionKey, extensionRealm, extensionDescriptor );
303 }
304
305 extensionRealmCache.register( project, extensionKey, recordRealm );
306
307 extensionRealms.add( extensionRealm );
308 if ( extensionDescriptor != null )
309 {
310 exportedPackages.put( extensionRealm, extensionDescriptor.getExportedPackages() );
311 exportedArtifacts.put( extensionRealm, extensionDescriptor.getExportedArtifacts() );
312 }
313
314 if ( !plugin.isExtensions() && artifacts.size() == 2 && artifacts.get( 0 ).getFile() != null
315 && "plexus-utils".equals( artifacts.get( 1 ).getArtifactId() ) )
316 {
317
318
319
320
321
322 publicArtifacts.add( artifacts.get( 0 ) );
323 }
324 }
325
326 if ( logger.isDebugEnabled() )
327 {
328 logger.debug( "Extension realms for project " + model.getId() + ": " + extensionRealms );
329 }
330
331 ProjectRealmCache.Key projectRealmKey = projectRealmCache.createKey( extensionRealms );
332
333 ProjectRealmCache.CacheRecord record = projectRealmCache.get( projectRealmKey );
334
335 if ( record == null )
336 {
337 projectRealm = classRealmManager.createProjectRealm( model, publicArtifacts );
338
339 Set<String> exclusions = new LinkedHashSet<String>();
340
341 for ( ClassRealm extensionRealm : extensionRealms )
342 {
343 List<String> excludes = exportedArtifacts.get( extensionRealm );
344
345 if ( excludes != null )
346 {
347 exclusions.addAll( excludes );
348 }
349
350 List<String> exports = exportedPackages.get( extensionRealm );
351
352 if ( exports == null || exports.isEmpty() )
353 {
354
355
356
357
358
359 exports = Arrays.asList( extensionRealm.getId() );
360 }
361
362 for ( String export : exports )
363 {
364 projectRealm.importFrom( extensionRealm, export );
365 }
366 }
367
368 DependencyFilter extensionArtifactFilter = null;
369 if ( !exclusions.isEmpty() )
370 {
371 extensionArtifactFilter = new ExclusionsDependencyFilter( exclusions );
372 }
373
374 record = projectRealmCache.put( projectRealmKey, projectRealm, extensionArtifactFilter );
375 }
376
377 projectRealmCache.register( project, projectRealmKey, record );
378
379 return record;
380 }
381
382 private List<Artifact> resolveExtensionArtifacts( Plugin extensionPlugin, List<RemoteRepository> repositories,
383 ProjectBuildingRequest request )
384 throws PluginResolutionException
385 {
386 DependencyNode root =
387 pluginDependenciesResolver.resolve( extensionPlugin, null, null, repositories,
388 request.getRepositorySession() );
389
390 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
391 root.accept( nlg );
392 return nlg.getArtifacts( false );
393 }
394
395 public void selectProjectRealm( MavenProject project )
396 {
397 ClassLoader projectRealm = project.getClassRealm();
398
399 if ( projectRealm == null )
400 {
401 projectRealm = classRealmManager.getCoreRealm();
402 }
403
404 Thread.currentThread().setContextClassLoader( projectRealm );
405 }
406
407 }