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