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