/Users/lyon/j4p/src/javagroup/util/StandardLoader.java

1    package javagroup.util; 
2     
3    import java.io.File; 
4    import java.io.FileInputStream; 
5    import java.io.IOException; 
6    import java.util.StringTokenizer; 
7    import java.util.zip.ZipEntry; 
8    import java.util.zip.ZipFile; 
9     
10   /** 
11    * This is a basic ClassLoader for loading files from directories on the 
12    * local filesystem either in directories or zipfiles. 
13    * 
14    * @author Luke Gorrie 
15    */ 
16   public class StandardLoader extends ClassLoader { 
17    
18       /** 
19        * Classpath to search for class files. 
20        */ 
21       protected Object[] _classPath; 
22    
23       /** 
24        * Constructs a new StandardLoader with the specified classpath.  The 
25        * classpath can contain directories and/or zip-files. 
26        * 
27        * @param classPath The classpath to use for this loader. 
28        */ 
29       public StandardLoader(String classPath) { 
30    
31           super(); 
32    
33           // each element of the classpath is delimited by the current operating system's path separator 
34           StringTokenizer st = new StringTokenizer(classPath, 
35                   System.getProperty("path.separator")); 
36    
37           // store the individual elements in an array to speed things up during loading 
38           _classPath = new Object[st.countTokens()]; 
39           int index = 0; 
40           while (st.hasMoreTokens()) 
41               _classPath[index++] = initPath(st.nextToken()); 
42       } 
43    
44       /** 
45        * Initializes a path entry.  Directories and zip files are supported. 
46        * 
47        * @param name Path name of the entry. 
48        * @return An Object representing a classpath entry. 
49        */ 
50       protected Object initPath(String name) { 
51           // check if this entry is a zip-file 
52           if (name.substring(name.length() - ".zip".length()) 
53                   .equalsIgnoreCase(".zip")) 
54               return initZipFile(name); 
55           // if not, assume it is a directory 
56           else 
57               return initDirectory(name); 
58       } 
59    
60       /** 
61        * Initialize a directory accessible on the local filesystem. 
62        * 
63        * @param name Name of the directory. 
64        * @return A File representing the directory. 
65        */ 
66       protected File initDirectory(String name) { 
67           try { 
68               // open directory 
69               File dir = new File(name); 
70    
71               // ensure a directory was opened. 
72               if (!dir.isDirectory()) 
73                   throw new IOException(); 
74    
75               // return the directory 
76               return dir; 
77           } catch (IOException ioe) { 
78               // return null, directory did not exist. 
79               return null; 
80           } 
81       } 
82    
83       /** 
84        * Initialize a zip-file accessible on the local filesystem. 
85        * 
86        * @param name Name of the Zip-file 
87        * @return A ZipFile representing the Zip classpath entry. 
88        */ 
89       public ZipFile initZipFile(String name) { 
90    
91           try { 
92               // open and return the requested zipfile 
93               ZipFile zip = new ZipFile(name); 
94               return zip; 
95           } catch (IOException ioe) { 
96               // null if the file could not be found 
97               return null; 
98           } 
99    
100      } 
101   
102      /** 
103       * Load a class from from available locations. 
104       */ 
105      public Class loadClass(String name, boolean resolve) 
106              throws ClassNotFoundException { 
107   
108          Class clazz = null; 
109   
110          // check if the class can be found in the system classpath 
111          try { 
112              clazz = findSystemClass(name); 
113          } catch (ClassNotFoundException cnfe) { 
114          } 
115          // if not, check if it is preloaded by this classloader. 
116          if (clazz == null) { 
117              clazz = findLoadedClass(name); 
118          } 
119          // if the class is still not found, try to custom-load it 
120          if (clazz == null) { 
121   
122              // array to store class data in 
123              byte[] class_data = null; 
124   
125              // try each classpath entry 
126              for (int i = 0; i < _classPath.length; i++) { 
127   
128                  // if this entry failed to initialize, skip it 
129                  if (_classPath[i] != null) { 
130                      try { 
131                          // custom-load for this classpath entry 
132                          class_data = loadClassDef(_classPath[i], name); 
133                      } catch (IOException e) { 
134                      } 
135                      // if the load was successful, break out 
136                      if (class_data != null) 
137                          break; 
138                  } 
139              } 
140              // if the class data was loaded, define the class 
141              if (class_data != null) { 
142                  clazz = defineClass(name,class_data, 0, class_data.length); 
143                  if (resolve) 
144                      resolveClass(clazz); 
145   
146                  // success 
147                  return clazz; 
148              } 
149   
150          } 
151   
152          // failure 
153          throw new ClassNotFoundException("Cannot load class: " + name); 
154      } 
155   
156      /** 
157       * Reads a byte[] from the given path. 
158       * 
159       * @param from The path to load from. 
160       * @param name The name of the class to load. 
161       * @return A byte[] containing the class data. 
162       */ 
163      public byte[] loadClassDef(Object from, String name) 
164              throws IOException { 
165   
166          // byte array to store class data in 
167          byte[] data = null; 
168   
169          // turn the classname into a filename 
170          name = name.replace('.', File.separatorChar) + ".class"; 
171   
172          // check if this entry is a Directory 
173          if ((from instanceof File) && ((File) from).isDirectory()) { 
174              File from_file = (File) from; 
175   
176              // open file 
177              File class_file = new File(from_file, name); 
178   
179              // init array and read class data 
180              data = new byte[(int) class_file.length()]; 
181              new FileInputStream(class_file).read(data); 
182   
183              // success 
184              return data; 
185          } 
186   
187          // check if this entry is a zip-file 
188          if (from instanceof ZipFile) { 
189              ZipFile zip = (ZipFile) from; 
190   
191              // find entry in zip for class 
192              ZipEntry class_entry = zip.getEntry(name); 
193   
194              // ensure entry exists 
195              if (class_entry == null) 
196                  throw new IOException("Entry doesn't exist"); 
197   
198              // initalize and read data 
199              data = new byte[(int) class_entry.getSize()]; 
200              zip.getInputStream(class_entry).read(data); 
201   
202              // success 
203              return data; 
204          } 
205   
206          // failure 
207          return null; 
208   
209      } 
210   
211  } 
212   
213