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