Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

SearchClassLoader.java

00001 /*
00002  * SearchClassLoader.java
00003  *
00004  * Created on 13 June 2003, 22:21
00005  */
00006 
00007 package Sct;
00008 
00009 import java.util.StringTokenizer;
00010 import java.util.jar.*;
00011 import java.util.zip.*;
00012 import java.util.Enumeration;
00013 import java.util.*;
00014 import java.io.*;
00015 
00024 public class SearchClassLoader extends ClassLoader {
00025     private static SearchClassLoader loader = new SearchClassLoader();
00026     //A Map of CacheData to Class
00027     private HashMap cache = new HashMap();
00028     
00029     class CacheData {
00030         String name;
00031         Class[] prototype;
00032         
00033         CacheData(String name, Class[] prototype) {
00034             this.name = name;
00035             this.prototype = prototype;
00036         }                
00037         public boolean equals(Object ob) {
00038             CacheData cd = (CacheData) ob;
00039             if (cd == null) return false;
00040             boolean equal = name.equals(cd.name) && prototype.length == cd.prototype.length;
00041             
00042             if (!equal) return false;
00043             for (int i=0; i<prototype.length && equal; ++i) {
00044                 equal &= prototype[i].equals(cd.prototype[i]);
00045             }
00046             return equal;
00047         }
00048         
00049         public int hashCode() {
00050             int hash = name.hashCode();
00051             for (int i=0; i<prototype.length; ++i) {
00052                 hash += prototype[i].hashCode();
00053             }
00054             return hash;
00055         }
00056     }
00057     
00058     public static SearchClassLoader instance() {
00059         return loader;
00060     }    
00061 
00062     //Note that it is quicker to search ClassPath first - presumably
00063     //because you avoid going through all the gazillions of system packages...
00064     //if necessary, it would be possible to speed that up to I guess - just
00065     //don't check if it starts with java or sun.
00066     public Class loadClass(String name, Class[] prototype) throws ClassNotFoundException {
00067         Class c = findInMap(name, prototype);
00068         if (c!=null) return c;
00069         c = findClassInParent(name, prototype);
00070         if (c == null) c = findClassInClassPath(name, prototype);                         
00071         if (c == null) c = findClassInPackages(name, prototype); 
00072         
00073         if (c != null) {
00074             addToMap(name, c, prototype);
00075             return c;
00076         }
00077         else throw new ClassNotFoundException("ClassLoaderIS could not find class: " + name);
00078     }
00079     
00080     private void addToMap(String name, Class c, Class[] prototype) {
00081         CacheData cd = new CacheData(name, prototype);
00082         cache.put(cd, c);
00083     }
00084     
00085     private Class findInMap(String name, Class[] prototype) {
00086         CacheData cd = new CacheData(name, prototype);
00087         return (Class)cache.get(cd);
00088     }
00089     
00090     private boolean checkClass(Class c, Class[] prototype) {
00091         //System.out.println("Checking class: " + c.getName());
00092         try {            
00093             //Will throw if fails.
00094             c.getConstructor(prototype);
00095             return true;
00096         } catch (NoSuchMethodException nsme) {
00097             //System.out.println("checkClass failed for: " + c.getName());
00098             return false;
00099         }
00100     }
00101     
00102     private Class findClassInParent(String name, Class[] prototype) {
00103         //System.out.println("findClassInParent: " + name);
00104         try {             
00105             Class c = loadClass(name);
00106             if (checkClass(c, prototype)) return c;
00107         } catch (ClassNotFoundException e) {}
00108         return null;        
00109     }
00110     
00111     private Class findClassInPackages(String name, Class[] prototype) {
00112         Class c = null;
00113         Package[] p = getPackages();            
00114         int i = 0;
00115         while (c==null && i<p.length) {                
00116             c = findClassInParent(p[i].getName() + "." + name, prototype);
00117             ++i;
00118         }
00119         return c;    
00120     }
00121     
00122     //Looks in all jar files in classpath
00125     private Class findClassInClassPath(String name, Class[] prototype) {
00126         Class c = null;
00127         String classPath = System.getProperty("java.class.path");
00128         //System.out.println(classPath "+\n");        
00129         String classFileName = name + ".class";
00130         StringTokenizer st = new StringTokenizer(classPath, ":");
00131         
00132         while (st.hasMoreTokens() && c==null) {
00133             String cpElement = st.nextToken();
00134             //System.out.println(cpElement);            
00135             if (cpElement.endsWith(".jar")) c = findInJarFile(classFileName, cpElement, prototype);
00136             else if (cpElement.endsWith(".zip")) c = findInZipFile(classFileName, cpElement, prototype);
00137             else c = findInDir(classFileName, cpElement, prototype);
00138             //System.out.println("FindClassInClassPath: " + c);
00139         }    
00140         
00141         return c;
00142     }
00143     
00144     private Class findInDir(String fileName, String dirName, Class[] prototype) {
00145         File f = new File(dirName);
00146         //System.out.println("DirName: " + dirName);
00147         if (!f.isDirectory()) return null;
00148         return findInDir(fileName, f.getAbsolutePath(), f, prototype);
00149     }    
00150 
00151     private Class findInDir(String fileName, String parentDir, File dir, Class[] prototype) {
00152         File[] files = dir.listFiles(new MyFileNameFilter(fileName));
00153         
00154         if (files.length > 0) {            
00155             String className = files[0].getAbsolutePath();
00156             //Make sure we remove the /!
00157             className = className.substring(parentDir.length() + 1, className.length() - 6);
00158             //System.out.println("findInDir candidate: " + className);
00159             Class c = findClassInParent(className, prototype);
00160             if (c!=null) return c;
00161         }
00162         
00163         //loop to find class
00164         files = dir.listFiles();
00165         Class c;
00166         for (int i=0; i<files.length; ++i) {
00167             if (files[i].isDirectory()) {
00168                 c = findInDir(fileName, parentDir, files[i], prototype);
00169                 if (c!=null) return c;
00170             }
00171         }
00172         return null;
00173     }
00174     
00175     private class MyFileNameFilter implements FilenameFilter {
00176         private String name;
00177         MyFileNameFilter(String name) {
00178             this.name = name;
00179         }
00180         
00181         public boolean accept(File dir, String name) {
00182             return this.name.equals(name);
00183         }
00184     }
00185 
00186     
00187     private Class findInZipFile(String classFileName, String cpElement, Class[] prototype) {
00188         ZipFile f = null;
00189         try {
00190             f = new ZipFile(cpElement); 
00191             return findInZipFile(f, classFileName, prototype);
00192         } catch (IOException e) {
00193         } finally {
00194             try {
00195                 if (f != null) f.close();
00196             } catch (IOException e) {}
00197         } 
00198         return null;    
00199     }
00200     
00201     private Class findInJarFile(String classFileName, String cpElement, Class[] prototype) {
00202         JarFile f = null;
00203         try {
00204             f = new JarFile(cpElement); 
00205             return findInZipFile(f, classFileName, prototype);
00206         } catch (IOException e) {
00207         } finally {
00208             try {
00209                 if (f != null) f.close();
00210             } catch (IOException e) {}
00211         } 
00212         return null;
00213     }
00214     
00215     private Class findInZipFile(ZipFile f, String classFileName, Class[] prototype) {
00216         Enumeration e = f.entries();
00217         while (e.hasMoreElements()) {                
00218             String entry = ((ZipEntry)e.nextElement()).getName();
00219             if (entry.endsWith("/" + classFileName)) {                   
00220                 String className = entry.substring(0, entry.length() - 6);
00221                 className.replace('/', '.');
00222                 Class c = findClassInParent(className, prototype);
00223                 if (c != null) return c;
00224             }
00225         }                               
00226         return null;
00227     }
00228 
00229      
00230     public static void main(String[] args) {
00231         find("Test");
00232         find("SctControl.Test");
00233         find("SctControl/Test");
00234         find("SctControl/Test.class");
00235     }
00236      
00237     public static void find(String name) {        
00238         System.out.println("\n\nSearching for:" + name +"\n");
00239         SearchClassLoader cl = SearchClassLoader.instance();
00240         Class[] argTypes = {IStream.class, ObjectManager.class};
00241         try {
00242             Class c = cl.loadClass(name, argTypes);
00243             System.out.println("Success!!! : " + c.getName());
00244         } catch (ClassNotFoundException e) {
00245             System.out.println(e.getMessage());            
00246         }         
00247     }
00248 }

Generated on Thu Jul 15 09:55:49 2004 for SCT DAQ/DCS Software - Java by doxygen 1.3.5