/* * DynamicClassLoader.java * Copyright (C) 2001 Javier Lopez (jslopez@forumsys.com) * * $Revision: 1.6 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package jde.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.StringTokenizer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * The class DynamicClassLoader extends the * abstract class ClassLoader. * This class loads the class binaries from the file system * all the time, it does not catch the class information. * There is caveat to this, classes that come with the JDK * such as java.lang.*, are loaded using the standard class loader. * The rest of the class are always reloaded from the file system. * * Created: Sun Jul 01 08:11:12 2001 * * @author * @version 1.0 * @since jde2.2.8beta2 */ public class DynamicClassLoader extends ClassLoader { /** * Class path. * */ public static final String CLASS_PATH = System.getProperty("java.class.path"); /** * Platform dependent file separator. * */ public static final String FILE_SEPARATOR = System.getProperty("file.separator"); /** * Platform dependent path separator. i.e. in Win32 is ';' in Unix is ':'. * */ public static final String PATH_SEPARATOR = System.getProperty("path.separator"); /** * Char use to separate packages. i.e. '.' * */ public static final char PACKAGE_SEPARATOR = '.'; /** * Classes file type. i.e. class * */ public static final String CLASS_FILE_TYPE = "class"; /** * Loads a class information from the file system, * if it fails it tries Class.forName(argClassName) * * @param argClassName name of the class to be loaded. * @return Class of the type argClassName * @exception ClassNotFoundException if the class cannot be found. */ public Class loadClass(String argClassName) throws ClassNotFoundException { File file; byte[] classBytes = null; Class c; //Checking if the class belong to either java.* or javax.* if ((argClassName.startsWith("java.")) || (argClassName.startsWith("javax."))) { return Class.forName(argClassName); } // end of if () //First convert the class name from java.lang.String to java/lang/String //where '/' is platform dependent. String className = argClassName.replace(PACKAGE_SEPARATOR, FILE_SEPARATOR.charAt(0)); //Then add the class file termination i.e. from java/lang/String //to java/lang/String.class className += PACKAGE_SEPARATOR + CLASS_FILE_TYPE; //Look for the class file in the current project classfile or in //the system class path if there is no current classpath ProjectClasses pc = JdeUtilities.getCurrentProjectClass(); String classpath = null; if (pc != null) { classpath = pc.getClassPath(); } // end of if (pc != null) if (classpath == null || classpath.equals("")) { classpath = CLASS_PATH; } // end of if (classpath == null ) StringTokenizer st = new StringTokenizer(classpath, PATH_SEPARATOR); ZipFile zf; while (st.hasMoreTokens()) { file = new File(st.nextToken()); //Check if the file is a directory if is not //assume it is a jar or zip file try { if (file.isDirectory()) { //if the file is a directory try to locate the class file //and load it. file = new File(file, className); classBytes = loadFile(file); if (classBytes != null) { break; } // end of if (classBytes != null) } else { zf = new ZipFile(file); classBytes = loadFile(zf, className); if (classBytes != null) { break; } // end of if (classBytes != null) }// end of if-else } catch (IOException e) { //ignore } // end of try-catch } // end of while (st.hasMoreTokens()) if (classBytes != null) { try { c = defineClass(argClassName, classBytes, 0, classBytes.length); } catch (SecurityException e) { //basic packages such as java.lang.* can't be loaded directly c = Class.forName(argClassName); } catch (ClassFormatError e) { c = Class.forName(argClassName); } catch (NoClassDefFoundError e) { c = Class.forName(argClassName); } return c; } else { try { return Class.forName(argClassName); } catch (ClassNotFoundException e) { throw new ClassNotFoundException(argClassName); } // end of try-catch } // end of else }//end of loadClass private byte[] loadFile(File argFile) { byte[] b = null; InputStream in = null; if (argFile.exists()) { try { in = new FileInputStream(argFile); b = new byte[(int)argFile.length()]; in.read(b); } catch (FileNotFoundException e) { b = null; } catch (IOException e) { b = null; } finally { try { in.close(); } catch (IOException e) { } // end of try-catch }//end of try-finally }// end of if return b; }//end of loadFile private byte[] loadFile(ZipFile argFile, String argClassName) { //zip and jar files seems to always be separated by a '/' argClassName = argClassName.replace(FILE_SEPARATOR.charAt(0), '/'); byte[] b = null; ZipEntry ze; InputStream in; try { ze = argFile.getEntry(argClassName); if (ze != null) { in = argFile.getInputStream(ze); b = new byte[(int)ze.getSize()]; in.read(b); }//end of if } catch (IOException e) { b = null; } finally { try { argFile.close(); } catch (IOException e) { } // end of try-catch }//end of try-finally return b; }//end of loadFile }// DynamicClassLoader /* * $Log: DynamicClassLoader.java,v $ * Revision 1.6 2002/02/21 12:26:45 jslopez * Updates the DynamicClassLoader to use the current project * classpath stored in JdeUtilities. * * Revision 1.5 2001/07/21 04:01:21 paulk * 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. * * Revision 1.4 2001/07/18 01:51:37 paulk * Handles ClassFormatError and NoClassDefFoundErrror exceptions that can occur when trying to load classes. Thanks to Javier Lopez. * * Revision 1.3 2001/07/17 05:27:53 paulk * Fixed to search vm startup classpath if classes not found on user classpath. Thanks to Javier. * * Revision 1.2 2001/07/07 04:49:43 paulk * Removed DOS line endings. * * Revision 1.1 2001/07/06 01:59:02 paulk * Initial revision. * */ // End of DynamicClassLoader.java