2 * DynamicClassLoader.java
3 * Copyright (C) 2001-2004 Javier Lopez (jslopez@forumsys.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 import java.io.FileInputStream;
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.StringTokenizer;
29 import java.util.zip.ZipEntry;
30 import java.util.zip.ZipFile;
34 * The class <code>DynamicClassLoader</code> extends the
35 * abstract class <code>ClassLoader</code>.
36 * This class loads the class binaries from the file system
37 * all the time, it does not catch the class information.
38 * There is caveat to this, classes that come with the JDK
39 * such as java.lang.*, are loaded using the standard class loader.
40 * The rest of the class are always reloaded from the file system.
42 * Created: Sun Jul 01 08:11:12 2001
44 * @author <a href="mailto:jlopez@cellexchange.com"></a>
46 * @since jde2.2.8beta2
48 public class DynamicClassLoader extends ClassLoader {
54 public static final String CLASS_PATH
55 = System.getProperty("java.class.path");
58 * Platform dependent file separator.
61 public static final String FILE_SEPARATOR
62 = System.getProperty("file.separator");
65 * Platform dependent path separator. i.e. in Win32 is ';' in Unix is ':'.
68 public static final String PATH_SEPARATOR
69 = System.getProperty("path.separator");
72 * Char use to separate packages. i.e. '.'
75 public static final char PACKAGE_SEPARATOR = '.';
78 * Classes file type. i.e. class
81 public static final String CLASS_FILE_TYPE = "class";
84 * Loads a class information from the file system,
85 * if it fails it tries Class.forName(argClassName)
87 * @param argClassName name of the class to be loaded.
88 * @return Class of the type argClassName
89 * @exception ClassNotFoundException if the class cannot be found.
91 public Class loadClass(String argClassName) throws ClassNotFoundException {
93 byte[] classBytes = null;
96 //Checking if the class belong to either java.* or javax.*
97 if ((argClassName.startsWith("java.")) ||
98 (argClassName.startsWith("javax."))) {
99 return Class.forName(argClassName);
102 //First convert the class name from java.lang.String to java/lang/String
103 //where '/' is platform dependent.
104 String className = argClassName.replace(PACKAGE_SEPARATOR,
105 FILE_SEPARATOR.charAt(0));
107 //Then add the class file termination i.e. from java/lang/String
108 //to java/lang/String.class
109 className += PACKAGE_SEPARATOR + CLASS_FILE_TYPE;
111 //Look for the class file in the current project classfile or in
112 //the system class path if there is no current classpath
113 ProjectClasses pc = JdeUtilities.getCurrentProjectClass();
114 String classpath = null;
116 classpath = pc.getClassPath();
117 } // end of if (pc != null)
119 if (classpath == null || classpath.equals("")) {
120 classpath = CLASS_PATH;
121 } // end of if (classpath == null )
123 StringTokenizer st = new StringTokenizer(classpath, PATH_SEPARATOR);
125 while (st.hasMoreTokens()) {
126 file = new File(st.nextToken());
128 //Check if the file is a directory if is not
129 //assume it is a jar or zip file
131 if (file.isDirectory()) {
132 //if the file is a directory try to locate the class file
134 file = new File(file, className);
135 classBytes = loadFile(file);
136 if (classBytes != null) {
138 } // end of if (classBytes != null)
140 zf = new ZipFile(file);
141 classBytes = loadFile(zf, className);
142 if (classBytes != null) {
144 } // end of if (classBytes != null)
146 } catch (IOException e) {
148 } // end of try-catch
149 } // end of while (st.hasMoreTokens())
151 if (classBytes != null) {
153 c = defineClass(argClassName, classBytes, 0, classBytes.length);
154 } catch (SecurityException e) {
155 //basic packages such as java.lang.* can't be loaded directly
156 c = Class.forName(argClassName);
157 } catch (ClassFormatError e) {
158 c = Class.forName(argClassName);
159 } catch (NoClassDefFoundError e) {
160 c = Class.forName(argClassName);
165 return Class.forName(argClassName);
166 } catch (ClassNotFoundException e) {
167 throw new ClassNotFoundException(argClassName);
168 } // end of try-catch
172 private byte[] loadFile(File argFile) {
174 InputStream in = null;
175 if (argFile.exists()) {
177 in = new FileInputStream(argFile);
178 b = read(in, (int)argFile.length());
179 } catch (FileNotFoundException e) {
181 } catch (IOException e) {
186 } catch (IOException e) {
187 } // end of try-catch
188 }//end of try-finally
194 private byte[] loadFile(ZipFile argFile, String argClassName) {
195 //zip and jar files seems to always be separated by a '/'
196 argClassName = argClassName.replace(FILE_SEPARATOR.charAt(0), '/');
201 ze = argFile.getEntry(argClassName);
203 in = argFile.getInputStream(ze);
204 b = read(in, (int) ze.getSize());
206 } catch (IOException e) {
211 } catch (IOException e) {
217 private static byte[] read (InputStream is, int size) throws IOException {
219 byte [] b = new byte[size];
222 int n = is.read(b, len, size - len);
223 if (n == -1 || n == 0) {
234 } catch (IOException e) {} // ignore
239 }// DynamicClassLoader
242 * $Log: DynamicClassLoader.java,v $
243 * Revision 1.7 2004/10/15 03:28:09 paulk
244 * Fixed bug caused by assuming that only one read operation is needed to
245 * read a class from the file system. Thanks to Suraj Acharya.
247 * Revision 1.6 2002/02/21 12:26:45 jslopez
248 * Updates the DynamicClassLoader to use the current project
249 * classpath stored in JdeUtilities.
251 * Revision 1.5 2001/07/21 04:01:21 paulk
252 * Now loads classes in java and javax packages instead of waiting for an exception to be thrown The purpose is two-fold, one is performance and the other one is to get rid of a nasty LinkageError. Contributed by Javier Lopez.
254 * Revision 1.4 2001/07/18 01:51:37 paulk
255 * Handles ClassFormatError and NoClassDefFoundErrror exceptions that can occur when trying to load classes. Thanks to Javier Lopez.
257 * Revision 1.3 2001/07/17 05:27:53 paulk
258 * Fixed to search vm startup classpath if classes not found on user classpath. Thanks to Javier.
260 * Revision 1.2 2001/07/07 04:49:43 paulk
261 * Removed DOS line endings.
263 * Revision 1.1 2001/07/06 01:59:02 paulk
268 // End of DynamicClassLoader.java