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