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, recordArtifacts );
248
249 throw e;
250 }
251 }
252
253 pluginArtifactsCache.register( project, recordArtifacts );
254
255 ClassRealm extensionRealm;
256 ExtensionDescriptor extensionDescriptor = null;
257
258 ExtensionRealmCache.CacheRecord recordRealm = extensionRealmCache.get( artifacts );
259
260 if ( recordRealm != null )
261 {
262 extensionRealm = recordRealm.realm;
263 extensionDescriptor = recordRealm.desciptor;
264 }
265 else
266 {
267 extensionRealm = classRealmManager.createExtensionRealm( plugin, artifacts );
268
269 try
270 {
271 ( (DefaultPlexusContainer) container ).discoverComponents( extensionRealm,
272 MojoExecutionScope.getScopeModule( container ) );
273 }
274 catch ( Exception e )
275 {
276 throw new IllegalStateException( "Failed to discover components in extension realm "
277 + extensionRealm.getId(), e );
278 }
279
280 Artifact extensionArtifact = artifacts.get( 0 );
281 try
282 {
283 extensionDescriptor = extensionDescriptorBuilder.build( extensionArtifact.getFile() );
284 }
285 catch ( IOException e )
286 {
287 String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
288 if ( logger.isDebugEnabled() )
289 {
290 logger.error( message, e );
291 }
292 else
293 {
294 logger.error( message );
295 }
296 }
297
298 recordRealm = extensionRealmCache.put( artifacts, extensionRealm, extensionDescriptor );
299 }
300
301 extensionRealmCache.register( project, recordRealm );
302
303 extensionRealms.add( extensionRealm );
304 if ( extensionDescriptor != null )
305 {
306 exportedPackages.put( extensionRealm, extensionDescriptor.getExportedPackages() );
307 exportedArtifacts.put( extensionRealm, extensionDescriptor.getExportedArtifacts() );
308 }
309
310 if ( !plugin.isExtensions() && artifacts.size() == 2 && artifacts.get( 0 ).getFile() != null
311 && "plexus-utils".equals( artifacts.get( 1 ).getArtifactId() ) )
312 {
313
314
315
316
317
318 publicArtifacts.add( artifacts.get( 0 ) );
319 }
320 }
321
322 if ( logger.isDebugEnabled() )
323 {
324 logger.debug( "Extension realms for project " + model.getId() + ": " + extensionRealms );
325 }
326
327 ProjectRealmCache.CacheRecord record = projectRealmCache.get( extensionRealms );
328
329 if ( record == null )
330 {
331 projectRealm = classRealmManager.createProjectRealm( model, publicArtifacts );
332
333 Set<String> exclusions = new LinkedHashSet<String>();
334
335 for ( ClassRealm extensionRealm : extensionRealms )
336 {
337 List<String> excludes = exportedArtifacts.get( extensionRealm );
338
339 if ( excludes != null )
340 {
341 exclusions.addAll( excludes );
342 }
343
344 List<String> exports = exportedPackages.get( extensionRealm );
345
346 if ( exports == null || exports.isEmpty() )
347 {
348
349
350
351
352
353 exports = Arrays.asList( extensionRealm.getId() );
354 }
355
356 for ( String export : exports )
357 {
358 projectRealm.importFrom( extensionRealm, export );
359 }
360 }
361
362 DependencyFilter extensionArtifactFilter = null;
363 if ( !exclusions.isEmpty() )
364 {
365 extensionArtifactFilter = new ExclusionsDependencyFilter( exclusions );
366 }
367
368 record = projectRealmCache.put( extensionRealms, projectRealm, extensionArtifactFilter );
369 }
370
371 projectRealmCache.register( project, record );
372
373 return record;
374 }
375
376 private List<Artifact> resolveExtensionArtifacts( Plugin extensionPlugin, List<RemoteRepository> repositories,
377 ProjectBuildingRequest request )
378 throws PluginResolutionException
379 {
380 DependencyNode root =
381 pluginDependenciesResolver.resolve( extensionPlugin, null, null, repositories,
382 request.getRepositorySession() );
383
384 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
385 root.accept( nlg );
386 return nlg.getArtifacts( false );
387 }
388
389 public void selectProjectRealm( MavenProject project )
390 {
391 ClassLoader projectRealm = project.getClassRealm();
392
393 if ( projectRealm == null )
394 {
395 projectRealm = classRealmManager.getCoreRealm();
396 }
397
398 Thread.currentThread().setContextClassLoader( projectRealm );
399 }
400
401 }