View Javadoc

1   package org.codehaus.classworlds;
2   
3   /*
4    $Id: UberJarRealmClassLoader.java,v 1.1 2004/07/06 17:37:36 dandiep Exp $
5   
6    Copyright 2002 (C) The Werken Company. All Rights Reserved.
7   
8    Redistribution and use of this software and associated documentation
9    ("Software"), with or without modification, are permitted provided
10   that the following conditions are met:
11  
12   1. Redistributions of source code must retain copyright
13      statements and notices.  Redistributions must also contain a
14      copy of this document.
15  
16   2. Redistributions in binary form must reproduce the
17      above copyright notice, this list of conditions and the
18      following disclaimer in the documentation and/or other
19      materials provided with the distribution.
20  
21   3. The name "classworlds" must not be used to endorse or promote
22      products derived from this Software without prior written
23      permission of The Werken Company.  For written permission,
24      please contact bob@werken.com.
25  
26   4. Products derived from this Software may not be called "classworlds"
27      nor may "classworlds" appear in their names without prior written
28      permission of The Werken Company. "classworlds" is a registered
29      trademark of The Werken Company.
30  
31   5. Due credit should be given to The Werken Company.
32      (http://classworlds.werken.com/).
33  
34   THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS
35   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
36   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
37   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
38   THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
39   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
43   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
45   OF THE POSSIBILITY OF SUCH DAMAGE.
46  
47   */
48  
49  
50  import java.io.ByteArrayOutputStream;
51  import java.io.IOException;
52  import java.io.InputStream;
53  import java.net.URL;
54  import java.util.ArrayList;
55  import java.util.Enumeration;
56  import java.util.HashMap;
57  import java.util.Iterator;
58  import java.util.List;
59  import java.util.Map;
60  import java.util.Vector;
61  import java.util.jar.JarEntry;
62  import java.util.jar.JarInputStream;
63  
64  /***
65   * Classloader for <code>ClassRealm</code>s.
66   * <p/>
67   * Loads classes from an "uberjar".
68   *
69   * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
70   * @version $Id: UberJarRealmClassLoader.java,v 1.1 2004/07/06 17:37:36 dandiep Exp $
71   */
72  public class UberJarRealmClassLoader
73      extends RealmClassLoader
74  {
75      private Map classIndex;
76  
77      private List urls;
78  
79      private Map jarIndexes;
80  
81      public UberJarRealmClassLoader( DefaultClassRealm realm )
82      {
83          super( realm );
84  
85          this.urls = new ArrayList();
86  
87          this.classIndex = new HashMap();
88  
89          this.jarIndexes = new HashMap();
90      }
91  
92      public void addConstituent( URL constituent )
93      {
94          // If the constituent is a jar, build an index for it.
95          if ( "jar".equals( constituent.getProtocol() ) || constituent.toExternalForm().endsWith( ".jar" ) )
96          {
97              buildIndexForJar( constituent );
98          }
99  
100         // Add the constituent to the urls collection
101 
102         this.urls.add( constituent );
103 
104         super.addConstituent( constituent );
105     }
106 
107     private void buildIndexForJar( URL inUrl )
108     {
109         HashMap index = new HashMap();
110 
111         String urlText = null;
112 
113         if ( inUrl.getProtocol().equals( "jar" ) )
114         {
115             urlText = inUrl.toExternalForm();
116         }
117         else
118         {
119             urlText = "jar:" + inUrl.toExternalForm();
120         }
121 
122         String resourceName;
123         URL resourceUrl = null;
124 
125         try
126         {
127             JarInputStream in = new JarInputStream( inUrl.openStream() );
128 
129             try
130             {
131                 JarEntry entry = null;
132 
133                 while ( ( entry = in.getNextJarEntry() ) != null )
134                 {
135                     resourceName = entry.getName();
136 
137                     resourceUrl = new URL( urlText + "!/" + resourceName );
138 
139                     index.put( resourceName, resourceUrl );
140                 }
141             }
142             finally
143             {
144                 in.close();
145             }
146         }
147         catch ( IOException e )
148         {
149             // swallow
150         }
151 
152         jarIndexes.put( inUrl, index );
153     }
154 
155     /***
156      * Load a class directly from this classloader without
157      * defering through any other <code>ClassRealm</code>.
158      *
159      * @param className The name of the class to load.
160      * @return The loaded class.
161      * @throws ClassNotFoundException If the class could not be found.
162      */
163     public Class loadClassDirect( String className )
164         throws ClassNotFoundException
165     {
166         String classPath = className.replace( '.', '/' ) + ".class";
167 
168         if ( this.classIndex.containsKey( classPath ) )
169         {
170             return (Class) this.classIndex.get( classPath );
171         }
172 
173         Iterator urlIter = this.urls.iterator();
174         URL eachUrl = null;
175 
176         byte[] classBytes = null;
177 
178         while ( ( classBytes == null ) && ( urlIter.hasNext() ) )
179         {
180             eachUrl = (URL) urlIter.next();
181 
182             if ( "jar".equals( eachUrl.getProtocol() ) || eachUrl.toExternalForm().endsWith( ".jar" ) )
183             {
184                 classBytes = findClassInJarStream( eachUrl, classPath );
185             }
186             else
187             {
188                 classBytes = findClassInDirectoryUrl( eachUrl, classPath );
189             }
190         }
191 
192         if ( classBytes == null )
193         {
194             //!!!return super.loadClassDirect( className );
195             return null;
196         }
197         else
198         {
199             Class cls = defineClass( className, classBytes, 0, classBytes.length );
200 
201             this.classIndex.put( classPath, cls );
202 
203             return cls;
204         }
205     }
206 
207     public URL findResource( String name )
208     {
209         URL resourceUrl = null;
210 
211         Iterator urlIter = this.urls.iterator();
212 
213         URL eachUrl = null;
214 
215         while ( urlIter.hasNext() )
216         {
217             eachUrl = (URL) urlIter.next();
218 
219             if ( "jar".equals( eachUrl.getProtocol() ) || eachUrl.toExternalForm().endsWith( ".jar" ) )
220             {
221                 resourceUrl = findResourceInJarStream( eachUrl, name );
222             }
223             else
224             {
225                 resourceUrl = findResourceInDirectoryUrl( eachUrl, name );
226             }
227 
228             if ( resourceUrl != null )
229             {
230                 return resourceUrl;
231             }
232         }
233 
234         return null;
235     }
236 
237     public Enumeration findResourcesFromClassLoader( String name )
238     {
239         Vector list = new Vector();
240 
241         URL resourceUrl = null;
242 
243         Iterator urlIter = this.urls.iterator();
244 
245         URL eachUrl = null;
246 
247         while ( urlIter.hasNext() )
248         {
249             eachUrl = (URL) urlIter.next();
250 
251             if ( "jar".equals( eachUrl.getProtocol() ) || eachUrl.toExternalForm().endsWith( ".jar" ) )
252             {
253                 resourceUrl = findResourceInJarStream( eachUrl, name );
254             }
255             else
256             {
257                 resourceUrl = findResourceInDirectoryUrl( eachUrl, name );
258             }
259 
260             if ( resourceUrl != null )
261             {
262                 list.add( resourceUrl );
263             }
264         }
265 
266         return list.elements();
267     }
268 
269     protected URL findResourceInJarStream( URL inUrl, String path )
270     {
271         return (URL) ( (Map) jarIndexes.get( inUrl ) ).get( path );
272     }
273 
274     protected URL findResourceInDirectoryUrl( URL inUrl, String path )
275     {
276         return null;
277     }
278 
279     protected byte[] findClassInJarStream( URL inUrl, String path )
280     {
281         URL classUrl = (URL) ( (Map) jarIndexes.get( inUrl ) ).get( path );
282 
283         if ( classUrl != null )
284         {
285             try
286             {
287                 return readStream( classUrl.openStream() );
288             }
289             catch ( IOException e )
290             {
291                 // Swallow
292             }
293         }
294 
295         return null;
296     }
297 
298     protected byte[] findClassInDirectoryUrl( URL url, String path )
299     {
300         try
301         {
302             URL classUrl = new URL( url, path );
303         }
304         catch ( IOException e )
305         {
306             // swallow
307         }
308 
309         return null;
310     }
311 
312     protected Class loadClass( String name, boolean resolve )
313         throws ClassNotFoundException
314     {
315 
316         //!!!!!
317         return null;
318     }
319 
320     private byte[] readStream( InputStream in ) throws IOException
321     {
322         ByteArrayOutputStream out = new ByteArrayOutputStream();
323 
324         try
325         {
326             byte[] buffer = new byte[2048];
327 
328             int read = 0;
329 
330             while ( in.available() > 0 )
331             {
332                 read = in.read( buffer, 0, buffer.length );
333 
334                 if ( read < 0 )
335                 {
336                     break;
337                 }
338 
339                 out.write( buffer, 0, read );
340             }
341 
342             return out.toByteArray();
343         }
344         finally
345         {
346             out.close();
347         }
348     }
349 }