1 package org.apache.maven.classrealm;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.net.MalformedURLException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Random;
29 import java.util.Set;
30
31 import org.apache.maven.artifact.ArtifactUtils;
32 import org.apache.maven.classrealm.ClassRealmRequest.RealmType;
33 import org.apache.maven.model.Model;
34 import org.apache.maven.model.Plugin;
35 import org.codehaus.plexus.MutablePlexusContainer;
36 import org.codehaus.plexus.PlexusContainer;
37 import org.codehaus.plexus.classworlds.ClassWorld;
38 import org.codehaus.plexus.classworlds.realm.ClassRealm;
39 import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
40 import org.codehaus.plexus.component.annotations.Component;
41 import org.codehaus.plexus.component.annotations.Requirement;
42 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
43 import org.codehaus.plexus.logging.Logger;
44 import org.codehaus.plexus.util.StringUtils;
45 import org.sonatype.aether.artifact.Artifact;
46
47
48
49
50
51
52
53
54 @Component( role = ClassRealmManager.class )
55 public class DefaultClassRealmManager
56 implements ClassRealmManager
57 {
58
59 @Requirement
60 private Logger logger;
61
62 @Requirement
63 protected PlexusContainer container;
64
65 private ClassRealm mavenRealm;
66
67 private ClassWorld getClassWorld()
68 {
69 return ( (MutablePlexusContainer) container ).getClassWorld();
70 }
71
72 private ClassRealm newRealm( String id )
73 {
74 ClassWorld world = getClassWorld();
75
76 synchronized ( world )
77 {
78 String realmId = id;
79
80 Random random = new Random();
81
82 while ( true )
83 {
84 try
85 {
86 ClassRealm classRealm = world.newRealm( realmId, null );
87
88 if ( logger.isDebugEnabled() )
89 {
90 logger.debug( "Created new class realm " + realmId );
91 }
92
93 return classRealm;
94 }
95 catch ( DuplicateRealmException e )
96 {
97 realmId = id + '-' + random.nextInt();
98 }
99 }
100 }
101 }
102
103 private synchronized ClassRealm getMavenRealm()
104 {
105 if ( mavenRealm == null )
106 {
107 mavenRealm = newRealm( "maven.api" );
108
109 importMavenApi( mavenRealm );
110
111 mavenRealm.setParentClassLoader( ClassLoader.getSystemClassLoader() );
112
113 List<ClassRealmManagerDelegate> delegates = getDelegates();
114 if ( !delegates.isEmpty() )
115 {
116 List<ClassRealmConstituent> constituents = new ArrayList<ClassRealmConstituent>();
117
118 ClassRealmRequest request =
119 new DefaultClassRealmRequest( RealmType.Core, null, new ArrayList<String>(), constituents );
120
121 for ( ClassRealmManagerDelegate delegate : delegates )
122 {
123 delegate.setupRealm( mavenRealm, request );
124 }
125
126 populateRealm( mavenRealm, constituents );
127 }
128 }
129 return mavenRealm;
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143 private ClassRealm createRealm( String baseRealmId, RealmType type, ClassLoader parent, List<String> imports,
144 boolean importXpp3Dom, List<Artifact> artifacts )
145 {
146 Set<String> artifactIds = new LinkedHashSet<String>();
147
148 List<ClassRealmConstituent> constituents = new ArrayList<ClassRealmConstituent>();
149
150 if ( artifacts != null )
151 {
152 for ( Artifact artifact : artifacts )
153 {
154 artifactIds.add( getId( artifact ) );
155 if ( artifact.getFile() != null )
156 {
157 constituents.add( new ArtifactClassRealmConstituent( artifact ) );
158 }
159 }
160 }
161
162 if ( imports != null )
163 {
164 imports = new ArrayList<String>( imports );
165 }
166 else
167 {
168 imports = new ArrayList<String>();
169 }
170
171 ClassRealm classRealm = newRealm( baseRealmId );
172
173 if ( parent != null )
174 {
175 classRealm.setParentClassLoader( parent );
176 }
177 else
178 {
179 classRealm.setParentRealm( getMavenRealm() );
180 }
181
182 List<ClassRealmManagerDelegate> delegates = getDelegates();
183 if ( !delegates.isEmpty() )
184 {
185 ClassRealmRequest request = new DefaultClassRealmRequest( type, parent, imports, constituents );
186
187 for ( ClassRealmManagerDelegate delegate : delegates )
188 {
189 delegate.setupRealm( classRealm, request );
190 }
191 }
192
193 if ( importXpp3Dom )
194 {
195 importXpp3Dom( classRealm );
196 }
197
198 if ( !imports.isEmpty() )
199 {
200 ClassLoader importedRealm = classRealm.getParentClassLoader();
201
202 if ( logger.isDebugEnabled() )
203 {
204 logger.debug( "Importing packages into class realm " + classRealm.getId() );
205 }
206
207 for ( String imp : imports )
208 {
209 if ( logger.isDebugEnabled() )
210 {
211 logger.debug( " Imported: " + imp );
212 }
213
214 classRealm.importFrom( importedRealm, imp );
215 }
216 }
217
218 Set<String> includedIds = populateRealm( classRealm, constituents );
219
220 if ( logger.isDebugEnabled() )
221 {
222 artifactIds.removeAll( includedIds );
223
224 for ( String id : artifactIds )
225 {
226 logger.debug( " Excluded: " + id );
227 }
228 }
229
230 return classRealm;
231 }
232
233
234
235
236
237
238
239
240 private void importXpp3Dom( ClassRealm importingRealm )
241 {
242 ClassRealm coreRealm = getCoreRealm();
243
244 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.util.xml.Xpp3Dom" );
245 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.util.xml.pull.XmlPullParser" );
246 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.util.xml.pull.XmlPullParserException" );
247 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.util.xml.pull.XmlSerializer" );
248 }
249
250
251
252
253
254
255 private void importMavenApi( ClassRealm importingRealm )
256 {
257 ClassRealm coreRealm = getCoreRealm();
258
259
260 importingRealm.importFrom( coreRealm, "org.apache.maven" );
261
262
263 importingRealm.importFrom( coreRealm, "org.sonatype.aether" );
264
265
266 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.classworlds" );
267
268
269 importingRealm.importFrom( coreRealm, "org.codehaus.classworlds" );
270
271
272 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.component" );
273 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.configuration" );
274 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.container" );
275 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.context" );
276 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.lifecycle" );
277 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.logging" );
278 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.personality" );
279 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.ComponentRegistry" );
280 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.ContainerConfiguration" );
281 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.DefaultComponentRegistry" );
282 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.DefaultContainerConfiguration" );
283 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.DefaultPlexusContainer" );
284 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.DuplicateChildContainerException" );
285 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.MutablePlexusContainer" );
286 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.PlexusConstants" );
287 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.PlexusContainer" );
288 importingRealm.importFrom( coreRealm, "org.codehaus.plexus.PlexusContainerException" );
289 }
290
291 public ClassRealm getCoreRealm()
292 {
293 return container.getContainerRealm();
294 }
295
296 public ClassRealm createProjectRealm( Model model, List<Artifact> artifacts )
297 {
298 if ( model == null )
299 {
300 throw new IllegalArgumentException( "model missing" );
301 }
302
303 return createRealm( getKey( model ), RealmType.Project, null, null, false, artifacts );
304 }
305
306 private static String getKey( Model model )
307 {
308 return "project>" + model.getGroupId() + ":" + model.getArtifactId() + ":" + model.getVersion();
309 }
310
311 public ClassRealm createExtensionRealm( Plugin plugin, List<Artifact> artifacts )
312 {
313 if ( plugin == null )
314 {
315 throw new IllegalArgumentException( "extension plugin missing" );
316 }
317
318 return createRealm( getKey( plugin, true ), RealmType.Extension, null, null, true, artifacts );
319 }
320
321 public ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports,
322 List<Artifact> artifacts )
323 {
324 if ( plugin == null )
325 {
326 throw new IllegalArgumentException( "plugin missing" );
327 }
328
329 return createRealm( getKey( plugin, false ), RealmType.Plugin, parent, imports, true, artifacts );
330 }
331
332 private static String getKey( Plugin plugin, boolean extension )
333 {
334 String version = ArtifactUtils.toSnapshotVersion( plugin.getVersion() );
335 return ( extension ? "extension>" : "plugin>" ) + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":"
336 + version;
337 }
338
339 private static String getId( Artifact artifact )
340 {
341 return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getExtension(), artifact.getClassifier(),
342 artifact.getBaseVersion() );
343 }
344
345 private static String getId( ClassRealmConstituent constituent )
346 {
347 return getId( constituent.getGroupId(), constituent.getArtifactId(), constituent.getType(),
348 constituent.getClassifier(), constituent.getVersion() );
349 }
350
351 private static String getId( String gid, String aid, String type, String cls, String ver )
352 {
353 return gid + ':' + aid + ':' + type + ( StringUtils.isNotEmpty( cls ) ? ':' + cls : "" ) + ':' + ver;
354 }
355
356 private List<ClassRealmManagerDelegate> getDelegates()
357 {
358 try
359 {
360 return container.lookupList( ClassRealmManagerDelegate.class );
361 }
362 catch ( ComponentLookupException e )
363 {
364 logger.error( "Failed to lookup class realm delegates: " + e.getMessage(), e );
365
366 return Collections.emptyList();
367 }
368 }
369
370 private Set<String> populateRealm( ClassRealm classRealm, List<ClassRealmConstituent> constituents )
371 {
372 Set<String> includedIds = new LinkedHashSet<String>();
373
374 if ( logger.isDebugEnabled() )
375 {
376 logger.debug( "Populating class realm " + classRealm.getId() );
377 }
378
379 for ( ClassRealmConstituent constituent : constituents )
380 {
381 File file = constituent.getFile();
382
383 String id = getId( constituent );
384 includedIds.add( id );
385
386 if ( logger.isDebugEnabled() )
387 {
388 logger.debug( " Included: " + id );
389 }
390
391 try
392 {
393 classRealm.addURL( file.toURI().toURL() );
394 }
395 catch ( MalformedURLException e )
396 {
397
398 logger.error( e.getMessage(), e );
399 }
400 }
401
402 return includedIds;
403 }
404
405 }