KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > JARClassLoader


1 /*
2  * JARClassLoader.java - Loads classes from JAR files
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 1999, 2003 Slava Pestov
7  * Portions copyright (C) 1999 mike dillon
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */

23
24 package org.gjt.sp.jedit;
25
26 //{{{ Imports
27
import java.io.InputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.util.*;
31 import java.util.zip.ZipEntry JavaDoc;
32 import java.util.zip.ZipFile JavaDoc;
33 import org.gjt.sp.util.Log;
34
35 import java.util.jar.Manifest JavaDoc;
36 import java.util.jar.JarFile JavaDoc;
37 import java.net.MalformedURLException JavaDoc;
38 import java.util.jar.Attributes JavaDoc;
39 import java.util.jar.Attributes.Name;
40 //}}}
41

42 /**
43  * A class loader implementation that loads classes from JAR files. All
44  * instances share the same set of classes.
45  * @author Slava Pestov
46  * @version $Id: JARClassLoader.java 6459 2006-07-30 00:54:17Z vanza $
47  */

48 public class JARClassLoader extends ClassLoader JavaDoc
49 {
50     //{{{ JARClassLoader constructor
51
/**
52      * This constructor creates a class loader for loading classes from all
53      * plugins. For example BeanShell uses one of these so that scripts can
54      * use plugin classes.
55      */

56     public JARClassLoader()
57     {
58         this(true);
59     }
60
61     /**
62      * Creates a class loader that will optionally delegate the
63      * finding of classes to the parent class loader by default.
64      *
65      * @since jEdit 4.3pre6
66      */

67     public JARClassLoader(boolean delegateFirst) {
68         this.delegateFirst = delegateFirst;
69         // for debugging
70
id = INDEX++;
71         live++;
72     } //}}}
73

74     //{{{ loadClass() method
75
/**
76      * @exception ClassNotFoundException if the class could not be found
77      */

78     public Class JavaDoc loadClass(String JavaDoc clazz, boolean resolveIt)
79         throws ClassNotFoundException JavaDoc
80     {
81         ClassNotFoundException JavaDoc pending = null;
82         if (delegateFirst)
83         {
84             try
85             {
86                 return loadFromParent(clazz);
87             }
88             catch (ClassNotFoundException JavaDoc cnf)
89             {
90                 // keep going if class was not found.
91
pending = cnf;
92             }
93         }
94
95         Object JavaDoc obj = classHash.get(clazz);
96         if(obj == NO_CLASS)
97         {
98             // we remember which classes we don't exist
99
// because BeanShell tries loading all possible
100
// <imported prefix>.<class name> combinations
101
throw new ClassNotFoundException JavaDoc(clazz);
102         }
103         else if(obj instanceof JARClassLoader)
104         {
105             JARClassLoader classLoader = (JARClassLoader)obj;
106             try
107             {
108                 return classLoader._loadClass(clazz,resolveIt);
109             } catch (ClassNotFoundException JavaDoc cnf2)
110             {
111                 classHash.put(clazz,NO_CLASS);
112                 throw cnf2;
113             }
114         }
115         else if (delegateFirst)
116         {
117             // if delegating, reaching this statement means
118
// the class was really not found. Otherwise
119
// we'll try loading from the parent class loader.
120
throw pending;
121         }
122
123         return loadFromParent(clazz);
124     } //}}}
125

126     //{{{ getResourceAsStream() method
127
public InputStream JavaDoc getResourceAsStream(String JavaDoc name)
128     {
129         if(jar == null)
130             return null;
131
132         try
133         {
134             ZipFile JavaDoc zipFile = jar.getZipFile();
135             ZipEntry JavaDoc entry = zipFile.getEntry(name);
136             if(entry == null)
137                 return getSystemResourceAsStream(name);
138             else
139                 return zipFile.getInputStream(entry);
140         }
141         catch(IOException JavaDoc io)
142         {
143             Log.log(Log.ERROR,this,io);
144
145             return null;
146         }
147     } //}}}
148

149     //{{{ getResource() method
150
public URL JavaDoc getResource(String JavaDoc name)
151     {
152         if(jar == null)
153             return null;
154
155         try
156         {
157             ZipFile JavaDoc zipFile = jar.getZipFile();
158             ZipEntry JavaDoc entry = zipFile.getEntry(name);
159             if(entry == null)
160                 return getSystemResource(name);
161             else
162                 return new URL JavaDoc(getResourceAsPath(name));
163         }
164         catch(IOException JavaDoc io)
165         {
166             Log.log(Log.ERROR,this,io);
167             return null;
168         }
169     } //}}}
170

171     //{{{ getResourceAsPath() method
172
public String JavaDoc getResourceAsPath(String JavaDoc name)
173     {
174         if(jar == null)
175             return null;
176
177         if(!name.startsWith("/"))
178             name = "/" + name;
179
180         return "jeditresource:/" + MiscUtilities.getFileName(
181             jar.getPath()) + "!" + name;
182     } //}}}
183

184     //{{{ getZipFile() method
185
/**
186      * @deprecated Call <code>PluginJAR.getZipFile()</code> instead.
187      */

188     public ZipFile JavaDoc getZipFile()
189     {
190         try
191         {
192             return jar.getZipFile();
193         }
194         catch(IOException JavaDoc io)
195         {
196             Log.log(Log.ERROR,this,io);
197             return null;
198         }
199     } //}}}
200

201     //{{{ dump() method
202
/**
203      * For debugging.
204      */

205     public static void dump()
206     {
207         Log.log(Log.DEBUG,JARClassLoader.class,
208             "Total instances created: " + INDEX);
209         Log.log(Log.DEBUG,JARClassLoader.class,
210             "Live instances: " + live);
211         synchronized(classHash)
212         {
213             Iterator entries = classHash.entrySet().iterator();
214             while(entries.hasNext())
215             {
216                 Map.Entry entry = (Map.Entry)entries.next();
217                 if(entry.getValue() != NO_CLASS)
218                 {
219                     Log.log(Log.DEBUG,JARClassLoader.class,
220                         entry.getKey() + " ==> "
221                         + entry.getValue());
222                 }
223             }
224         }
225     } //}}}
226

227     //{{{ toString() method
228
public String JavaDoc toString()
229     {
230         if(jar == null)
231             return "<anonymous>(" + id + ")";
232         else
233             return jar.getPath() + " (" + id + ")";
234     } //}}}
235

236     //{{{ findResources() method
237
protected Enumeration findResources(String JavaDoc name) throws IOException JavaDoc
238     {
239         class SingleElementEnumeration implements Enumeration
240         {
241             private Object JavaDoc element;
242
243             public SingleElementEnumeration(Object JavaDoc element)
244             {
245                 this.element = element;
246             }
247
248             public boolean hasMoreElements()
249             {
250                 return (element != null);
251             }
252
253             public Object JavaDoc nextElement()
254             {
255                 if(element != null)
256                 {
257                     Object JavaDoc retval = element;
258                     element = null;
259                     return retval;
260                 }
261                 else
262                     throw new NoSuchElementException();
263             }
264         }
265
266         URL JavaDoc resource = getResource(name);
267         return new SingleElementEnumeration(resource);
268     } //}}}
269

270     //{{{ finalize() method
271
protected void finalize()
272     {
273         live--;
274     } //}}}
275

276     //{{{ Package-private members
277

278     //{{{ JARClassLoader constructor
279
/**
280      * @since jEdit 4.2pre1
281      */

282     JARClassLoader(PluginJAR jar)
283     {
284         this();
285         this.jar = jar;
286     } //}}}
287

288     //{{{ activate() method
289
void activate()
290     {
291         if (jar.getPlugin() != null)
292         {
293             String JavaDoc _delegate = jEdit.getProperty(
294                 "plugin." + jar.getPlugin().getClassName() + ".class_loader_delegate");
295             delegateFirst = (_delegate == null || "true".equals(_delegate));
296         }
297
298         String JavaDoc[] classes = jar.getClasses();
299         if(classes != null)
300         {
301             for(int i = 0; i < classes.length; i++)
302             {
303                 classHash.put(classes[i],this);
304             }
305         }
306     } //}}}
307

308     //{{{ deactivate() method
309
void deactivate()
310     {
311         String JavaDoc[] classes = jar.getClasses();
312         if(classes == null)
313             return;
314
315         for(int i = 0; i < classes.length; i++)
316         {
317             Object JavaDoc loader = classHash.get(classes[i]);
318             if(loader == this)
319                 classHash.remove(classes[i]);
320             else
321                 /* two plugins provide same class! */;
322         }
323     } //}}}
324

325     //}}}
326

327     //{{{ Private members
328

329     // used to mark non-existent classes in class hash
330
private static final Object JavaDoc NO_CLASS = new Object JavaDoc();
331
332     private static int INDEX;
333     private static int live;
334     private static Hashtable classHash = new Hashtable();
335
336     private int id;
337     private boolean delegateFirst;
338     private PluginJAR jar;
339
340     //{{{ _loadClass() method
341
/**
342      * Load class from this JAR only.
343      */

344     private synchronized Class JavaDoc _loadClass(String JavaDoc clazz, boolean resolveIt)
345         throws ClassNotFoundException JavaDoc
346     {
347         jar.activatePlugin();
348
349         synchronized(this)
350         {
351             Class JavaDoc cls = findLoadedClass(clazz);
352             if(cls != null)
353             {
354                 if(resolveIt)
355                     resolveClass(cls);
356                 return cls;
357             }
358
359             String JavaDoc name = MiscUtilities.classToFile(clazz);
360
361             try
362             {
363                 definePackage(clazz);
364                 ZipFile JavaDoc zipFile = jar.getZipFile();
365                 ZipEntry JavaDoc entry = zipFile.getEntry(name);
366
367                 if(entry == null)
368                     throw new ClassNotFoundException JavaDoc(clazz);
369
370                 InputStream JavaDoc in = zipFile.getInputStream(entry);
371
372                 int len = (int)entry.getSize();
373                 byte[] data = new byte[len];
374                 int success = 0;
375                 int offset = 0;
376                 while(success < len)
377                 {
378                     len -= success;
379                     offset += success;
380                     success = in.read(data,offset,len);
381                     if(success == -1)
382                     {
383                         Log.log(Log.ERROR,this,"Failed to load class "
384                             + clazz + " from " + zipFile.getName());
385                         throw new ClassNotFoundException JavaDoc(clazz);
386                     }
387                 }
388
389                 cls = defineClass(clazz,data,0,data.length);
390
391                 if(resolveIt)
392                     resolveClass(cls);
393
394                 return cls;
395             }
396             catch(IOException JavaDoc io)
397             {
398                 Log.log(Log.ERROR,this,io);
399
400                 throw new ClassNotFoundException JavaDoc(clazz);
401             }
402         }
403     } //}}}
404

405     //{{{ definePackage(clazz) method
406
private void definePackage(String JavaDoc clazz) throws IOException JavaDoc
407     {
408         int idx = clazz.lastIndexOf('.');
409         if (idx != -1) {
410             String JavaDoc name = clazz.substring(0, idx);
411             if (getPackage(name) == null) definePackage(name, new JarFile JavaDoc(jar.getFile()).getManifest());
412         }
413     } //}}}
414

415     //{{{ getMfValue() method
416
private String JavaDoc getMfValue(Attributes JavaDoc sectionAttrs, Attributes JavaDoc mainAttrs, Attributes.Name JavaDoc name)
417     {
418         String JavaDoc value=null;
419         if (sectionAttrs != null)
420             value = sectionAttrs.getValue(name);
421         else if (mainAttrs != null) {
422             value = mainAttrs.getValue(name);
423         }
424         return value;
425     }
426     //}}}
427

428     //{{{ definePackage(packageName, manifest) method
429
private void definePackage(String JavaDoc name, Manifest JavaDoc mf)
430     {
431         if (mf==null)
432         {
433             definePackage(name, null, null, null, null, null,
434             null, null);
435             return;
436         }
437
438         Attributes JavaDoc sa = mf.getAttributes(name.replace('.', '/') + "/");
439         Attributes JavaDoc ma = mf.getMainAttributes();
440
441         URL JavaDoc sealBase = null;
442         if (Boolean.valueOf(getMfValue(sa, ma, Name.SEALED)).booleanValue())
443         {
444             try
445             {
446                 sealBase = jar.getFile().toURL();
447             } catch (MalformedURLException JavaDoc e) { }
448         }
449
450         Package JavaDoc pkg=definePackage(
451             name,
452             getMfValue(sa, ma, Name.SPECIFICATION_TITLE),
453             getMfValue(sa, ma, Name.SPECIFICATION_VERSION),
454             getMfValue(sa, ma, Name.SPECIFICATION_VENDOR),
455             getMfValue(sa, ma, Name.IMPLEMENTATION_TITLE),
456             getMfValue(sa, ma, Name.IMPLEMENTATION_VERSION),
457             getMfValue(sa, ma, Name.IMPLEMENTATION_VENDOR),
458             sealBase);
459     } //}}}
460

461     //{{{ loadFromParent() method
462
private Class JavaDoc loadFromParent(String JavaDoc clazz)
463         throws ClassNotFoundException JavaDoc
464     {
465         Class JavaDoc cls;
466
467         ClassLoader JavaDoc parentLoader = getClass().getClassLoader();
468         if (parentLoader != null)
469             cls = parentLoader.loadClass(clazz);
470         else
471             cls = findSystemClass(clazz);
472
473         return cls;
474     } //}}}
475

476     //}}}
477
}
478
Popular Tags