KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > connection > DriverClassLoader


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: sequoia@continuent.org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * Initial developer(s): Marc Wick.
20  * Contributor(s): Emmanuel Cecchet.
21  */

22
23 package org.continuent.sequoia.controller.connection;
24
25 import java.io.BufferedInputStream JavaDoc;
26 import java.io.File JavaDoc;
27 import java.io.FileInputStream JavaDoc;
28 import java.io.FilenameFilter JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.net.MalformedURLException JavaDoc;
31 import java.net.URL JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.Hashtable JavaDoc;
34 import java.util.jar.JarFile JavaDoc;
35 import java.util.zip.ZipEntry JavaDoc;
36 import java.util.zip.ZipFile JavaDoc;
37 import java.util.zip.ZipInputStream JavaDoc;
38
39 /**
40  * This class defines a DriverClassLoader used to load drivers with their own
41  * classloder to be able to handle different implementations of drivers sharing
42  * the same class name. For example if you want to connect to two backends of
43  * the same vendor, but running with different releases and requiring a driver
44  * compatible with the respective database release
45  *
46  * @author <a HREF="mailto:marc.wick@monte-bre.ch">Marc Wick </a>
47  * @author <a HREF="mailto:emmanuel.cecchet@emicnetworks.com">Emmanuel Cecchet</a>
48  * @version 1.0
49  */

50 public class DriverClassLoader extends ClassLoader JavaDoc
51 {
52
53   /** path on filesystem where the driver is located */
54   private File JavaDoc path = null;
55
56   /**
57    * Creates a new <code>DriverClassLoader.java</code> object
58    *
59    * @param parent classloader, null if no parent classloader should be used
60    * @param pPath path where the driver classfiles of jar files are located
61    */

62   public DriverClassLoader(ClassLoader JavaDoc parent, File JavaDoc pPath)
63   {
64     super(parent);
65     path = pPath;
66     if (path == null)
67       path = new File JavaDoc("");
68   }
69
70   /**
71    * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
72    */

73   protected synchronized Class JavaDoc loadClass(String JavaDoc name, boolean resolve)
74       throws ClassNotFoundException JavaDoc
75   {
76     try
77     {
78       return super.loadClass(name, resolve);
79     }
80     catch (ClassNotFoundException JavaDoc e)
81     {
82       Class JavaDoc c = findClass(name);
83       if (resolve)
84         resolveClass(c);
85       return c;
86     }
87   }
88
89   /**
90    * Finds the specified class including in jar files in the classpath
91    *
92    * @see java.lang.ClassLoader#findClass(java.lang.String)
93    */

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

146   private Hashtable JavaDoc htJarContents = new Hashtable JavaDoc();
147
148   /**
149    * Find the first jar file containing the className and load it
150    *
151    * @param dir directory where we are looking for jar files
152    * @param className name of the class we are looking for
153    * @return the class as byte[]
154    * @throws IOException if an error occurs
155    */

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

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

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

290   private String JavaDoc convertClassNameToResourceName(String JavaDoc className)
291   {
292     String JavaDoc resourceName = className;
293     resourceName = resourceName.replace('.', '/');
294     resourceName = resourceName + ".class";
295     return resourceName;
296   }
297
298   /**
299    * Load the contents of jar file in the cache
300    *
301    * @param jarFileName name of the jar file we want to load
302    * @throws IOException
303    */

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