1 package org.codehaus.plexus.classworlds.realm;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.io.Closeable;
20 import java.io.IOException;
21 import java.io.PrintStream;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.net.URLClassLoader;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.HashSet;
29 import java.util.LinkedHashSet;
30 import java.util.SortedSet;
31 import java.util.TreeSet;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34
35 import org.codehaus.plexus.classworlds.ClassWorld;
36 import org.codehaus.plexus.classworlds.strategy.Strategy;
37 import org.codehaus.plexus.classworlds.strategy.StrategyFactory;
38
39
40
41
42
43
44
45
46
47
48
49 public class ClassRealm extends URLClassLoader {
50
51 private ClassWorld world;
52
53 private String id;
54
55 private SortedSet<Entry> foreignImports;
56
57 private SortedSet<Entry> parentImports;
58
59 private Strategy strategy;
60
61 private ClassLoader parentClassLoader;
62
63 private static final boolean isParallelCapable = Closeable.class.isAssignableFrom(URLClassLoader.class);
64
65 private final ConcurrentMap<String, Object> lockMap;
66
67
68
69
70
71
72
73
74
75 public ClassRealm(ClassWorld world, String id, ClassLoader baseClassLoader) {
76 super(new URL[0], baseClassLoader);
77
78 this.world = world;
79
80 this.id = id;
81
82 foreignImports = new TreeSet<>();
83
84 strategy = StrategyFactory.getStrategy(this);
85
86 lockMap = isParallelCapable ? new ConcurrentHashMap<>() : null;
87
88 if (isParallelCapable) {
89
90
91 super.getClassLoadingLock(getClass().getName());
92 }
93 }
94
95 public String getId() {
96 return this.id;
97 }
98
99 public ClassWorld getWorld() {
100 return this.world;
101 }
102
103 public void importFromParent(String packageName) {
104 if (parentImports == null) {
105 parentImports = new TreeSet<>();
106 }
107
108 parentImports.add(new Entry(null, packageName));
109 }
110
111 boolean isImportedFromParent(String name) {
112 if (parentImports != null && !parentImports.isEmpty()) {
113 for (Entry entry : parentImports) {
114 if (entry.matches(name)) {
115 return true;
116 }
117 }
118
119 return false;
120 }
121
122 return true;
123 }
124
125 public void importFrom(String realmId, String packageName) throws NoSuchRealmException {
126 importFrom(getWorld().getRealm(realmId), packageName);
127 }
128
129 public void importFrom(ClassLoader classLoader, String packageName) {
130 foreignImports.add(new Entry(classLoader, packageName));
131 }
132
133 public ClassLoader getImportClassLoader(String name) {
134 for (Entry entry : foreignImports) {
135 if (entry.matches(name)) {
136 return entry.getClassLoader();
137 }
138 }
139
140 return null;
141 }
142
143 public Collection<ClassRealm> getImportRealms() {
144 Collection<ClassRealm> importRealms = new HashSet<>();
145
146 for (Entry entry : foreignImports) {
147 if (entry.getClassLoader() instanceof ClassRealm) {
148 importRealms.add((ClassRealm) entry.getClassLoader());
149 }
150 }
151
152 return importRealms;
153 }
154
155 public Strategy getStrategy() {
156 return strategy;
157 }
158
159 public void setParentClassLoader(ClassLoader parentClassLoader) {
160 this.parentClassLoader = parentClassLoader;
161 }
162
163 public ClassLoader getParentClassLoader() {
164 return parentClassLoader;
165 }
166
167 public void setParentRealm(ClassRealm realm) {
168 this.parentClassLoader = realm;
169 }
170
171 public ClassRealm getParentRealm() {
172 return (parentClassLoader instanceof ClassRealm) ? (ClassRealm) parentClassLoader : null;
173 }
174
175 public ClassRealm createChildRealm(String id) throws DuplicateRealmException {
176 ClassRealm childRealm = getWorld().newRealm(id, (ClassLoader) null);
177
178 childRealm.setParentRealm(this);
179
180 return childRealm;
181 }
182
183 public void addURL(URL url) {
184 String urlStr = url.toExternalForm();
185
186 if (urlStr.startsWith("jar:") && urlStr.endsWith("!/")) {
187 urlStr = urlStr.substring(4, urlStr.length() - 2);
188
189 try {
190 url = new URL(urlStr);
191 } catch (MalformedURLException e) {
192 e.printStackTrace();
193 }
194 }
195
196 super.addURL(url);
197 }
198
199
200
201
202
203
204 public Class<?> loadClass(String name) throws ClassNotFoundException {
205 return loadClass(name, false);
206 }
207
208 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
209 if (isParallelCapable) {
210 return unsynchronizedLoadClass(name, resolve);
211
212 } else {
213 synchronized (this) {
214 return unsynchronizedLoadClass(name, resolve);
215 }
216 }
217 }
218
219 private Class<?> unsynchronizedLoadClass(String name, boolean resolve) throws ClassNotFoundException {
220 try {
221
222 return super.loadClass(name, resolve);
223 } catch (ClassNotFoundException e) {
224
225 return strategy.loadClass(name);
226 }
227 }
228
229
230
231
232 protected Class<?> findClass(String moduleName, String name) {
233 if (moduleName != null) {
234 return null;
235 }
236 try {
237 return findClassInternal(name);
238 } catch (ClassNotFoundException e) {
239 try {
240 return strategy.getRealm().findClass(name);
241 } catch (ClassNotFoundException nestedException) {
242 return null;
243 }
244 }
245 }
246
247 protected Class<?> findClass(String name) throws ClassNotFoundException {
248
249
250
251
252 throw new ClassNotFoundException(name);
253 }
254
255 protected Class<?> findClassInternal(String name) throws ClassNotFoundException {
256 return super.findClass(name);
257 }
258
259 public URL getResource(String name) {
260 URL resource = super.getResource(name);
261 return resource != null ? resource : strategy.getResource(name);
262 }
263
264 public URL findResource(String name) {
265 return super.findResource(name);
266 }
267
268 public Enumeration<URL> getResources(String name) throws IOException {
269 Collection<URL> resources = new LinkedHashSet<>(Collections.list(super.getResources(name)));
270 resources.addAll(Collections.list(strategy.getResources(name)));
271 return Collections.enumeration(resources);
272 }
273
274 public Enumeration<URL> findResources(String name) throws IOException {
275 return super.findResources(name);
276 }
277
278
279
280
281
282 public void display() {
283 display(System.out);
284 }
285
286 public void display(PrintStream out) {
287 out.println("-----------------------------------------------------");
288
289 for (ClassRealm cr = this; cr != null; cr = cr.getParentRealm()) {
290 out.println("realm = " + cr.getId());
291 out.println("strategy = " + cr.getStrategy().getClass().getName());
292
293 showUrls(cr, out);
294
295 out.println();
296 }
297
298 out.println("-----------------------------------------------------");
299 }
300
301 private static void showUrls(ClassRealm classRealm, PrintStream out) {
302 URL[] urls = classRealm.getURLs();
303
304 for (int i = 0; i < urls.length; i++) {
305 out.println("urls[" + i + "] = " + urls[i]);
306 }
307
308 out.println("Number of foreign imports: " + classRealm.foreignImports.size());
309
310 for (Entry entry : classRealm.foreignImports) {
311 out.println("import: " + entry);
312 }
313
314 if (classRealm.parentImports != null) {
315 out.println("Number of parent imports: " + classRealm.parentImports.size());
316
317 for (Entry entry : classRealm.parentImports) {
318 out.println("import: " + entry);
319 }
320 }
321 }
322
323 public String toString() {
324 return "ClassRealm[" + getId() + ", parent: " + getParentClassLoader() + "]";
325 }
326
327
328
329
330
331 public Class<?> loadClassFromImport(String name) {
332 ClassLoader importClassLoader = getImportClassLoader(name);
333
334 if (importClassLoader != null) {
335 try {
336 return importClassLoader.loadClass(name);
337 } catch (ClassNotFoundException e) {
338 return null;
339 }
340 }
341
342 return null;
343 }
344
345 public Class<?> loadClassFromSelf(String name) {
346 synchronized (getClassRealmLoadingLock(name)) {
347 try {
348 Class<?> clazz = findLoadedClass(name);
349
350 if (clazz == null) {
351 clazz = findClassInternal(name);
352 }
353
354 return clazz;
355 } catch (ClassNotFoundException e) {
356 return null;
357 }
358 }
359 }
360
361 private Object getClassRealmLoadingLock(String name) {
362 if (isParallelCapable) {
363 return getClassLoadingLock(name);
364 } else {
365 return this;
366 }
367 }
368
369 @Override
370 protected Object getClassLoadingLock(String name) {
371 if (isParallelCapable) {
372 Object newLock = new Object();
373 Object lock = lockMap.putIfAbsent(name, newLock);
374 return (lock == null) ? newLock : lock;
375 }
376 return this;
377 }
378
379 public Class<?> loadClassFromParent(String name) {
380 ClassLoader parent = getParentClassLoader();
381
382 if (parent != null && isImportedFromParent(name)) {
383 try {
384 return parent.loadClass(name);
385 } catch (ClassNotFoundException e) {
386 return null;
387 }
388 }
389
390 return null;
391 }
392
393
394
395
396
397 public URL loadResourceFromImport(String name) {
398 ClassLoader importClassLoader = getImportClassLoader(name);
399
400 if (importClassLoader != null) {
401 return importClassLoader.getResource(name);
402 }
403
404 return null;
405 }
406
407 public URL loadResourceFromSelf(String name) {
408 return findResource(name);
409 }
410
411 public URL loadResourceFromParent(String name) {
412 ClassLoader parent = getParentClassLoader();
413
414 if (parent != null && isImportedFromParent(name)) {
415 return parent.getResource(name);
416 } else {
417 return null;
418 }
419 }
420
421
422
423
424
425 public Enumeration<URL> loadResourcesFromImport(String name) {
426 ClassLoader importClassLoader = getImportClassLoader(name);
427
428 if (importClassLoader != null) {
429 try {
430 return importClassLoader.getResources(name);
431 } catch (IOException e) {
432 return null;
433 }
434 }
435
436 return null;
437 }
438
439 public Enumeration<URL> loadResourcesFromSelf(String name) {
440 try {
441 return findResources(name);
442 } catch (IOException e) {
443 return null;
444 }
445 }
446
447 public Enumeration<URL> loadResourcesFromParent(String name) {
448 ClassLoader parent = getParentClassLoader();
449
450 if (parent != null && isImportedFromParent(name)) {
451 try {
452 return parent.getResources(name);
453 } catch (IOException e) {
454
455 }
456 }
457
458 return null;
459 }
460
461 static {
462 if (isParallelCapable)
463 {
464 registerAsParallelCapable();
465 }
466 }
467 }