1 package org.codehaus.classworlds;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 import java.io.File;
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.net.URL;
54 import java.util.Enumeration;
55 import java.util.Iterator;
56 import java.util.TreeSet;
57 import java.util.Vector;
58
59
60 /***
61 * Implementation of <code>ClassRealm</code>. The realm is the class loading gateway.
62 * The search is proceded as follows:
63 * <ol>
64 * <li>Search the parent class loader (passed via the constructor) if there
65 * is one.</li>
66 * <li>Search the imports.</li>
67 * <li>Search this realm's constituents.</li>
68 * <li>Search the parent realm.</li>
69 * </ol>
70 *
71 * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
72 * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
73 * @version $Id: DefaultClassRealm.java,v 1.8 2004/08/09 22:00:16 jvanzyl Exp $
74 * @todo allow inheritance to be turn on/off at runtime.
75 * @todo allow direction of search
76 */
77 public class DefaultClassRealm
78 implements ClassRealm
79 {
80 private ClassWorld world;
81
82 private String id;
83
84 private TreeSet imports;
85
86 private ClassLoader foreignClassLoader;
87
88 private RealmClassLoader classLoader;
89
90 private ClassRealm parent;
91
92 public DefaultClassRealm( ClassWorld world, String id )
93 {
94 this( world, id, null );
95 }
96
97 public DefaultClassRealm( ClassWorld world, String id, ClassLoader foreignClassLoader )
98 {
99 this.world = world;
100
101 this.id = id;
102
103 imports = new TreeSet();
104
105 if ( foreignClassLoader != null )
106 {
107 this.foreignClassLoader = foreignClassLoader;
108 }
109
110 if ( "true".equals( System.getProperty( "classworlds.bootstrapped" ) ) )
111 {
112 classLoader = new UberJarRealmClassLoader( this );
113 }
114 else
115 {
116 classLoader = new RealmClassLoader( this );
117 }
118 }
119
120 public URL[] getConstituents()
121 {
122 return classLoader.getURLs();
123 }
124
125 public ClassRealm getParent()
126 {
127 return parent;
128 }
129
130 public void setParent( ClassRealm parent )
131 {
132 this.parent = parent;
133 }
134
135 public String getId()
136 {
137 return this.id;
138 }
139
140 public ClassWorld getWorld()
141 {
142 return this.world;
143 }
144
145 public void importFrom( String realmId, String packageName )/package-summary.html">ong> void importFrom( String realmId, String packageName )
146 throws NoSuchRealmException
147 {
148 imports.add( new Entry( getWorld().getRealm( realmId ), packageName ) );
149 imports.add( new Entry( getWorld().getRealm( realmId ), packageName.replace('.', '/') ) );
150 }
151
152 public void addConstituent( URL constituent )
153 {
154 classLoader.addConstituent( constituent );
155 }
156
157 /***
158 * Adds a byte[] class definition as a constituent for locating classes.
159 * Currently uses BytesURLStreamHandler to hold a reference of the byte[] in memory.
160 * This ensures we have a unifed URL resource model for all constituents.
161 * The code to cache to disk is commented out - maybe a property to choose which method?
162 *
163 * @param constituent class name
164 * @param b the class definition as a byte[]
165 */
166 public void addConstituent(String constituent,
167 byte[] b) throws ClassNotFoundException
168 {
169 try
170 {
171 File path, file;
172 if (constituent.lastIndexOf('.') != -1)
173 {
174 path = new File("byteclass/" + constituent.substring(0, constituent.lastIndexOf('.') + 1).replace('.', File.separatorChar));
175
176 file = new File(path, constituent.substring(constituent.lastIndexOf('.') + 1) + ".class");
177 }
178 else
179 {
180 path = new File("byteclass/");
181
182 file = new File(path, constituent + ".class");
183 }
184
185 addConstituent( new URL( null,
186 file.toURL().toExternalForm(),
187 new BytesURLStreamHandler(b) ) );
188 }
189 catch (java.io.IOException e)
190 {
191 throw new ClassNotFoundException( "Couldn't load byte stream.", e );
192 }
193 }
194
195 public ClassRealm locateSourceRealm( String classname )
196 {
197 for ( Iterator iterator = imports.iterator(); iterator.hasNext(); )
198 {
199 Entry entry = (Entry) iterator.next();
200
201 if ( entry.matches( classname ) )
202 {
203 return entry.getRealm();
204 }
205 }
206
207 return this;
208 }
209
210 public ClassLoader getClassLoader()
211 {
212 return classLoader;
213 }
214
215 public ClassRealm createChildRealm( String id )
216 throws DuplicateRealmException
217 {
218 ClassRealm childRealm = getWorld().newRealm( id );
219
220 childRealm.setParent( this );
221
222 return childRealm;
223 }
224
225
226
227
228
229 public Class loadClass( String name )
230 throws ClassNotFoundException
231 {
232 if ( name.startsWith( "org.codehaus.classworlds." ) )
233 {
234 return getWorld().loadClass( name );
235 }
236
237 try
238 {
239 if ( foreignClassLoader != null )
240 {
241 try
242 {
243 return foreignClassLoader.loadClass( name );
244 }
245 catch ( ClassNotFoundException e )
246 {
247
248 }
249 }
250
251 ClassRealm sourceRealm = locateSourceRealm( name );
252
253 if ( sourceRealm == this )
254 {
255 return classLoader.loadClassDirect( name );
256 }
257 else
258 {
259 try
260 {
261 return sourceRealm.loadClass( name );
262 }
263 catch ( ClassNotFoundException cnfe )
264 {
265
266 return classLoader.loadClassDirect( name );
267 }
268 }
269 }
270 catch ( ClassNotFoundException e )
271 {
272 if ( getParent() != null )
273 {
274 return getParent().loadClass( name );
275 }
276
277 throw e;
278 }
279 }
280
281 public URL getResource( String name )
282 {
283 URL resource = null;
284 name = UrlUtils.normalizeUrlPath( name );
285
286 if ( foreignClassLoader != null )
287 {
288 resource = foreignClassLoader.getResource( name );
289
290 if ( resource != null )
291 {
292 return resource;
293 }
294 }
295
296 ClassRealm sourceRealm = locateSourceRealm( name );
297
298 if ( sourceRealm == this )
299 {
300 resource = classLoader.getResourceDirect( name );
301 }
302 else
303 {
304 resource = sourceRealm.getResource( name );
305
306 if ( resource == null )
307 {
308 resource = classLoader.getResourceDirect( name );
309 }
310 }
311
312 if ( resource == null && getParent() != null )
313 {
314 resource = getParent().getResource( name );
315 }
316
317 return resource;
318 }
319
320 public InputStream getResourceAsStream( String name )
321 {
322 URL url = getResource( name );
323
324 InputStream is = null;
325
326 if ( url != null )
327 {
328 try
329 {
330 is = url.openStream();
331 }
332 catch ( IOException e )
333 {
334
335 }
336 }
337
338 return is;
339 }
340
341 public Enumeration findResources(String name)
342 throws IOException
343 {
344 name = UrlUtils.normalizeUrlPath(name);
345
346 Vector resources = new Vector();
347
348
349 if ( foreignClassLoader != null )
350 {
351 for ( Enumeration res = foreignClassLoader.getResources(name); res.hasMoreElements(); )
352 {
353 resources.addElement(res.nextElement());
354 }
355 }
356
357
358 ClassRealm sourceRealm = locateSourceRealm( name );
359
360 if ( sourceRealm != this )
361 {
362
363 for ( Enumeration res = sourceRealm.findResources(name); res.hasMoreElements(); )
364 {
365 resources.addElement(res.nextElement());
366 }
367 }
368
369
370 for ( Enumeration direct = classLoader.findResourcesDirect(name); direct.hasMoreElements(); )
371 {
372 resources.addElement(direct.nextElement());
373 }
374
375
376 if (parent != null)
377 {
378 for ( Enumeration parent = getParent().findResources(name); parent.hasMoreElements(); )
379 {
380 resources.addElement(parent.nextElement());
381 }
382 }
383
384 return resources.elements();
385 }
386
387 public void display()
388 {
389 ClassRealm cr = this;
390
391 System.out.println( "-----------------------------------------------------" );
392
393
394 showUrls( cr );
395
396 while( cr.getParent() != null )
397 {
398 System.out.println( "\n" );
399
400 cr = cr.getParent();
401
402 showUrls( cr );
403 }
404
405 System.out.println( "-----------------------------------------------------" );
406 }
407
408 private void showUrls( ClassRealm classRealm )
409 {
410 System.out.println( "this realm = " + classRealm.getId() );
411
412 URL[] urls = classRealm.getConstituents();
413
414 for ( int i = 0; i < urls.length; i++ )
415 {
416 System.out.println( "urls[" + i + "] = " + urls[i] );
417 }
418
419 System.out.println( "Number of imports: " + imports.size() );
420
421 for ( Iterator i = imports.iterator(); i.hasNext(); )
422 {
423 System.out.println( "import: " + i.next() );
424 }
425 }
426 }