KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > util > MemoryClassLoader


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: MemoryClassLoader.java 1096 2004-03-26 21:41:16Z dblevins $
44  */

45 package org.openejb.util;
46
47 import java.io.BufferedInputStream JavaDoc;
48 import java.io.ByteArrayInputStream JavaDoc;
49 import java.io.ByteArrayOutputStream JavaDoc;
50 import java.io.IOException JavaDoc;
51 import java.io.InputStream JavaDoc;
52 import java.net.URL JavaDoc;
53 import java.util.Enumeration JavaDoc;
54 import java.util.HashMap JavaDoc;
55 import java.util.jar.JarEntry JavaDoc;
56 import java.util.jar.JarFile JavaDoc;
57 import java.util.jar.JarInputStream JavaDoc;
58
59 /**
60  * Works around deficencies in Sun's URLClassLoader implementation.
61  * Unfortunately, the URLClassLoader doesn't like it when the original
62  * JAR file changes, and reportedly on Windows it keeps the JAR file
63  * locked too. As well, it seems that you can't make a URLClassLoader
64  * using URLs from Resources in a previous URLClassLoader. So this
65  * ClassLoader loads the contents of the JAR(s) into memory immediately
66  * and then releases the files. The classes are flushed as they are used,
67  * but other files stay in memory permanently. Note that you cannot
68  * acquire a class file as a resource (URL or stream).
69  *
70  * <p><font color="red"><b>Warning:</b></font> URLs for this are not
71  * yet implemented! You cannot call getResource() or getResources()!</p>
72  *
73  * @author Aaron Mulder (ammulder@alumni.princeton.edu)
74  * @version $Revision: 1096 $
75  */

76 public class MemoryClassLoader extends ClassLoader JavaDoc {
77     private final static int BUFFER_SIZE = 1024;
78     private HashMap JavaDoc classes = new HashMap JavaDoc();
79     private HashMap JavaDoc others = new HashMap JavaDoc();
80
81     public MemoryClassLoader(ClassLoader JavaDoc parent, JarFile JavaDoc file) {
82         this(parent, new JarFile JavaDoc[]{file});
83     }
84
85     public MemoryClassLoader(ClassLoader JavaDoc parent, JarFile JavaDoc[] file) {
86         super(parent);
87         for(int i=0; i<file.length; i++) {
88             addJar(file[i]);
89             try {
90                 file[i].close();
91             } catch(IOException JavaDoc e) {}
92         }
93     }
94
95     /**
96      * Note that you must close the stream after the constructor
97      * returns, in case it is itself a JarInputStream or something.
98      */

99     public MemoryClassLoader(ClassLoader JavaDoc parent, JarInputStream JavaDoc stream) {
100         this(parent, new JarInputStream JavaDoc[]{stream});
101     }
102     /**
103      * Note that you must close the streams after the constructor
104      * returns, in case they are also from a JarInputStream or something.
105      */

106     public MemoryClassLoader(ClassLoader JavaDoc parent, JarInputStream JavaDoc[] stream) {
107         super(parent);
108         for(int i=0; i<stream.length; i++) {
109             addJar(stream[i]);
110         }
111     }
112
113 /* ********** ClassLoader Overrides ********** */
114     public InputStream JavaDoc getResourceAsStream(String JavaDoc name) {
115         InputStream JavaDoc stream = getParent().getResourceAsStream(name);
116         if(stream == null) {
117             byte[] buf = (byte[])others.get(name);
118             if(buf != null) {
119                 stream = new ByteArrayInputStream JavaDoc(buf);
120             }
121         }
122         return stream;
123     }
124
125     public URL JavaDoc getResource(String JavaDoc name) {
126         throw new Error JavaDoc("Not Yet Implemented!");
127         // AMM - FIXME
128
// Must write a new URL protocol handler, and
129
// register the package prefix with the correct
130
// system property (see java.net.URL)
131
}
132
133     protected Enumeration JavaDoc findResources(String JavaDoc name) throws IOException JavaDoc {
134         throw new Error JavaDoc("Not Yet Implemented!");
135         // AMM - FIXME
136
}
137
138     public boolean equals(Object JavaDoc o) {
139         if(o instanceof MemoryClassLoader) {
140             return ((MemoryClassLoader)o).getParent() == getParent();
141         }
142         return false;
143     }
144
145     public int hashCode() {
146         return getParent().hashCode();
147     }
148
149     public Class JavaDoc findClass(String JavaDoc name) throws ClassNotFoundException JavaDoc {
150         byte[] data = findClassData(name);
151         if(data != null) {
152             return defineClass(name, data, 0, data.length);
153         } else {
154             throw new ClassNotFoundException JavaDoc();
155         }
156     }
157
158 /* ******** End ClassLoader Overrides ******** */
159
160     /**
161      * Adds a new JAR to this ClassLoader. This may be called at any time.
162      */

163     public void addJar(JarFile JavaDoc jar) {
164         Enumeration JavaDoc entries = jar.entries();
165         while(entries.hasMoreElements()) {
166             JarEntry JavaDoc entry = (JarEntry JavaDoc)entries.nextElement();
167             if(entry.getName().endsWith(".class")) {
168                 try {
169                     addClassFile(jar, entry);
170                 } catch(IOException JavaDoc e) {e.printStackTrace();}
171             } else {
172                 try {
173                     addOtherFile(jar, entry);
174                 } catch(IOException JavaDoc e) {e.printStackTrace();}
175             }
176         }
177     }
178
179     /**
180      * Adds a new JAR to this ClassLoader. This may be called at any time.
181      */

182     public void addJar(JarInputStream JavaDoc stream) {
183         byte[] buf = new byte[BUFFER_SIZE];
184         int count;
185         try {
186             while(true) {
187                 JarEntry JavaDoc entry = stream.getNextJarEntry();
188                 if(entry == null)
189                     break;
190                 String JavaDoc name = entry.getName();
191                 int size = (int)entry.getSize();
192                 ByteArrayOutputStream JavaDoc out =
193                     size >= 0 ? new ByteArrayOutputStream JavaDoc(size)
194                               : new ByteArrayOutputStream JavaDoc(BUFFER_SIZE);
195                 while((count = stream.read(buf)) > -1)
196                     out.write(buf, 0, count);
197                 out.close();
198                 if(name.endsWith(".class")) {
199                     classes.put(getClassName(name), out.toByteArray());
200                 } else {
201                     others.put(name, out.toByteArray());
202                 }
203             }
204         } catch(IOException JavaDoc e) {
205             e.printStackTrace();
206         }
207     }
208
209     private byte[] findClassData(String JavaDoc name) {
210         return (byte[])classes.remove(name);
211     }
212
213     private void addClassFile(JarFile JavaDoc jar, JarEntry JavaDoc entry) throws IOException JavaDoc {
214         classes.put(getClassName(entry.getName()), getFileBytes(jar, entry));
215     }
216
217     private void addOtherFile(JarFile JavaDoc jar, JarEntry JavaDoc entry) throws IOException JavaDoc {
218        others.put(entry.getName(), getFileBytes(jar, entry));
219     }
220
221     private static String JavaDoc getClassName(String JavaDoc fileName) {
222         return fileName.substring(0, fileName.length()-6).replace('/','.');
223     }
224
225     private static byte[] getFileBytes(JarFile JavaDoc jar, JarEntry JavaDoc entry) throws IOException JavaDoc {
226         ByteArrayOutputStream JavaDoc stream = new ByteArrayOutputStream JavaDoc((int)entry.getSize());
227         byte[] buf = new byte[BUFFER_SIZE];
228         BufferedInputStream JavaDoc in = new BufferedInputStream JavaDoc(jar.getInputStream(entry));
229         int count;
230         while((count = in.read(buf)) > -1)
231             stream.write(buf, 0, count);
232         in.close();
233         stream.close();
234
235         return stream.toByteArray();
236     }
237 }
Popular Tags