KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > connection > DriverClassLoader


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Marc Wick.
22  * Contributor(s): ______________________.
23  */

24
25 package org.objectweb.cjdbc.controller.connection;
26
27 import java.io.BufferedInputStream JavaDoc;
28 import java.io.File JavaDoc;
29 import java.io.FileInputStream JavaDoc;
30 import java.io.FilenameFilter JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.net.MalformedURLException JavaDoc;
33 import java.net.URL JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.Hashtable JavaDoc;
36 import java.util.jar.JarFile JavaDoc;
37 import java.util.zip.ZipEntry JavaDoc;
38 import java.util.zip.ZipFile JavaDoc;
39 import java.util.zip.ZipInputStream JavaDoc;
40
41 /**
42  * This class defines a DriverClassLoader
43  *
44  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
45  * @version 1.0
46  */

47 /**
48  * This class defines a DriverClassLoader used to load drivers with their own
49  * classloder to be able to handle different implementations of drivers sharing
50  * the same class name. For example if you want to connect to two backends of
51  * the same vendor, but running with different releases and requiring a driver
52  * compatible with the respective database release
53  *
54  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
55  * @version 1.0
56  */

57 public class DriverClassLoader extends ClassLoader JavaDoc
58 {
59
60   /** path on filesystem where the driver is located */
61   private File JavaDoc path = null;
62
63   /**
64    * Creates a new <code>DriverClassLoader.java</code> object
65    *
66    * @param parent classloader, null if no parent classloader should be used
67    * @param pPath path where the driver classfiles of jar files are located
68    */

69   DriverClassLoader(ClassLoader JavaDoc parent, File JavaDoc pPath)
70   {
71     super(parent);
72     path = pPath;
73     if (path == null)
74       path = new File JavaDoc("");
75
76   }
77
78   /**
79    * finds the specified class
80    *
81    * @see java.lang.ClassLoader#findClass(java.lang.String)
82    */

83   protected Class JavaDoc findClass(String JavaDoc className) throws ClassNotFoundException JavaDoc
84   {
85
86     FileInputStream JavaDoc fis = null;
87
88     try
89     {
90       byte[] classBytes = null;
91
92       // first we try to locate a class file.
93
String JavaDoc pathName = className.replace('.', File.separatorChar);
94       File JavaDoc file = new File JavaDoc(path.getAbsolutePath(), pathName + ".class");
95       if (file.exists())
96       {
97         // we have found a class file and read it
98
fis = new FileInputStream JavaDoc(file);
99         classBytes = new byte[fis.available()];
100         fis.read(classBytes);
101       }
102       else
103       {
104         // no class file exists we have to check jar files
105
classBytes = findClassInJarFile(path, className);
106       }
107
108       // we convert the bytes into the specified class
109
Class JavaDoc clazz = defineClass(null, classBytes, 0, classBytes.length);
110       return clazz;
111     }
112     catch (Exception JavaDoc e)
113     {
114       // We could not find the class, so indicate the problem with an exception
115
throw new ClassNotFoundException JavaDoc(className, e);
116     }
117     finally
118     {
119       if (null != fis)
120       {
121         try
122         {
123           fis.close();
124         }
125         catch (Exception JavaDoc e)
126         {
127         }
128       }
129     }
130   }
131
132   /**
133    * we cache the contents of the jar files, as we don't want to have to read
134    * the file for every single class we are going to need
135    */

136   private Hashtable JavaDoc htJarContents = new Hashtable JavaDoc();
137
138   /**
139    * Find the first jar file containing the className and load it
140    *
141    * @param dir directory where we are looking for jar files
142    * @param className name of the class we are looking for
143    * @return the class as byte[]
144    * @throws IOException if an error occurs
145    */

146   private byte[] findClassInJarFile(File JavaDoc dir, String JavaDoc className)
147       throws IOException JavaDoc
148   {
149     // is the class already cached ?
150
String JavaDoc resourceName = convertClassNameToResourceName(className);
151     byte[] classBytes = (byte[]) htJarContents.get(resourceName);
152     if (classBytes != null)
153     {
154       // it has been cached, we return
155
return classBytes;
156     }
157
158     if (!dir.canRead())
159       throw new IOException JavaDoc(dir + " is not readable.");
160
161     if (dir.isFile())
162     {
163       // driverPath specified a jar file
164
loadJarFile(dir.getAbsolutePath());
165       // after loading the jar file the class bytes are in the cache
166
return (byte[]) htJarContents.get(resourceName);
167     }
168
169     // the class is not yet cached we have to find the right jar file
170

171     // find all jar files in the directory
172
String JavaDoc[] jarFiles = dir.list(new FilenameFilter JavaDoc()
173     {
174       public boolean accept(File JavaDoc dir, String JavaDoc name)
175       {
176         return name.endsWith(".jar");
177       }
178     });
179
180     if (jarFiles == null)
181       throw new IOException JavaDoc("Invalid path " + dir);
182
183     // loop over jar files
184
for (int i = 0; i < jarFiles.length; i++)
185     {
186       File JavaDoc file = new File JavaDoc(dir, jarFiles[i]);
187       JarFile JavaDoc jarFile = new JarFile JavaDoc(file);
188
189       // we see whether the jar file contains the class we are looking for
190
// no need in loading jar files as long as we don't really need the
191
// content.
192
if (jarFile.getEntry(resourceName) != null)
193       {
194         // we have found the right jar file and are loading it now
195
loadJarFile(jarFile.getName());
196
197         // after loading the jar file the class bytes are in the cache
198
classBytes = (byte[]) htJarContents.get(resourceName);
199       }
200     }
201     return classBytes;
202   }
203
204   /**
205    * @see java.lang.ClassLoader#findResource(java.lang.String)
206    */

207   protected URL JavaDoc findResource(String JavaDoc name)
208   {
209
210     // we try to locate the resource unjarred
211
if (path.isDirectory())
212     {
213       File JavaDoc searchResource = new File JavaDoc(path, name);
214       if (searchResource.exists())
215       {
216         try
217         {
218           return searchResource.toURL();
219         }
220         catch (MalformedURLException JavaDoc mfe)
221         {
222         }
223       }
224     }
225     else if (path.isFile())
226     {
227       // try getting the resource from the file
228
try
229       {
230         new JarFile JavaDoc(path);
231         // convert the jar entry into URL format
232
return new URL JavaDoc("jar:" + path.toURL() + "!/" + name);
233       }
234       catch (Exception JavaDoc e)
235       {
236         // we couldn't find resource in file
237
return null;
238       }
239     }
240
241     //now we are checking the jar files
242
try
243     {
244       // find all jar files in the directory
245
String JavaDoc[] jarFiles = path.list(new FilenameFilter JavaDoc()
246       {
247         public boolean accept(File JavaDoc dir, String JavaDoc name)
248         {
249           return name.endsWith(".jar");
250         }
251       });
252       // loop over jar files
253
for (int i = 0; i < jarFiles.length; i++)
254       {
255         File JavaDoc file = new File JavaDoc(path, jarFiles[i]);
256         JarFile JavaDoc jarFile = new JarFile JavaDoc(file);
257
258         // we see whether the jar file contains the resource we are looking for
259
if (jarFile.getJarEntry(name) != null)
260         {
261           // convert the jar entry into URL format
262
return new URL JavaDoc("jar:" + file.toURL() + "!/" + name);
263         }
264       }
265     }
266     catch (Exception JavaDoc e)
267     {
268       e.printStackTrace();
269     }
270     return null;
271   }
272
273   /**
274    * convert the class name into the rescource name. This method is just
275    * replacing the '.' in the name with a '/' and adding the suffix '.class'
276    *
277    * @param className
278    * @return resource name
279    */

280   private String JavaDoc convertClassNameToResourceName(String JavaDoc className)
281   {
282     String JavaDoc resourceName = className;
283     resourceName = resourceName.replace('.', '/');
284     resourceName = resourceName + ".class";
285     return resourceName;
286   }
287
288   /**
289    * Load the contents of jar file in the cache
290    *
291    * @param jarFileName name of the jar file we want to load
292    * @throws IOException
293    */

294   private void loadJarFile(String JavaDoc jarFileName) throws IOException JavaDoc
295   {
296     Hashtable JavaDoc htSizes = new Hashtable JavaDoc();
297     // extracts just sizes only.
298
// For a reason I dont' understand not all files return the size in the loop
299
// below (using ZipInputStream). So we cache the sizes here in case the loop
300
// below does not give us the file size
301
ZipFile JavaDoc zf = new ZipFile JavaDoc(jarFileName);
302     Enumeration JavaDoc e = zf.entries();
303     while (e.hasMoreElements())
304     {
305       ZipEntry JavaDoc ze = (ZipEntry JavaDoc) e.nextElement();
306
307       htSizes.put(ze.getName(), new Integer JavaDoc((int) ze.getSize()));
308     }
309     zf.close();
310
311     // extract resources and put them into the hashtable.
312
FileInputStream JavaDoc fis = new FileInputStream JavaDoc(jarFileName);
313     BufferedInputStream JavaDoc bis = new BufferedInputStream JavaDoc(fis);
314     ZipInputStream JavaDoc zis = new ZipInputStream JavaDoc(bis);
315     ZipEntry JavaDoc ze = null;
316     while ((ze = zis.getNextEntry()) != null)
317     {
318       if (ze.isDirectory())
319       {
320         continue;
321       }
322
323       int size = (int) ze.getSize();
324       // -1 means unknown size.
325
if (size == -1)
326       {
327         // that is the reason we have cached the file size above.
328
size = ((Integer JavaDoc) htSizes.get(ze.getName())).intValue();
329       }
330
331       byte[] b = new byte[size];
332       int rb = 0;
333       int chunk = 0;
334       while ((size - rb) > 0)
335       {
336         chunk = zis.read(b, rb, size - rb);
337         if (chunk == -1)
338         {
339           break;
340         }
341         rb += chunk;
342       }
343
344       // add to internal resource hashtable
345
htJarContents.put(ze.getName(), b);
346     }
347
348   }
349 }
Popular Tags