PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/JARClassLoader.java

#
Java | 342 lines | 221 code | 42 blank | 79 comment | 37 complexity | f5f94298fe2819f029cc390f52965897 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  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. package org.gjt.sp.jedit;
  24. //{{{ Imports
  25. import java.io.InputStream;
  26. import java.io.IOException;
  27. import java.net.URL;
  28. import java.util.*;
  29. import java.util.zip.ZipEntry;
  30. import java.util.zip.ZipFile;
  31. import org.gjt.sp.util.Log;
  32. //}}}
  33. /**
  34. * A class loader implementation that loads classes from JAR files. All
  35. * instances share the same set of classes.
  36. * @author Slava Pestov
  37. * @version $Id: JARClassLoader.java 4989 2004-03-11 05:21:00Z spestov $
  38. */
  39. public class JARClassLoader extends ClassLoader
  40. {
  41. //{{{ JARClassLoader constructor
  42. /**
  43. * This constructor creates a class loader for loading classes from all
  44. * plugins. For example BeanShell uses one of these so that scripts can
  45. * use plugin classes.
  46. */
  47. public JARClassLoader()
  48. {
  49. // for debugging
  50. id = INDEX++;
  51. live++;
  52. } //}}}
  53. //{{{ loadClass() method
  54. /**
  55. * @exception ClassNotFoundException if the class could not be found
  56. */
  57. public Class loadClass(String clazz, boolean resolveIt)
  58. throws ClassNotFoundException
  59. {
  60. // see what JARClassLoader this class is in
  61. Object obj = classHash.get(clazz);
  62. if(obj == NO_CLASS)
  63. {
  64. // we remember which classes we don't exist
  65. // because BeanShell tries loading all possible
  66. // <imported prefix>.<class name> combinations
  67. throw new ClassNotFoundException(clazz);
  68. }
  69. else if(obj instanceof JARClassLoader)
  70. {
  71. JARClassLoader classLoader = (JARClassLoader)obj;
  72. return classLoader._loadClass(clazz,resolveIt);
  73. }
  74. // if it's not in the class hash, and not marked as
  75. // non-existent, try loading it from the CLASSPATH
  76. try
  77. {
  78. Class cls;
  79. /* Defer to whoever loaded us (such as JShell,
  80. * Echidna, etc) */
  81. ClassLoader parentLoader = getClass().getClassLoader();
  82. if (parentLoader != null)
  83. cls = parentLoader.loadClass(clazz);
  84. else
  85. cls = findSystemClass(clazz);
  86. return cls;
  87. }
  88. catch(ClassNotFoundException cnf)
  89. {
  90. // remember that this class doesn't exist for
  91. // future reference
  92. classHash.put(clazz,NO_CLASS);
  93. throw cnf;
  94. }
  95. } //}}}
  96. //{{{ getResourceAsStream() method
  97. public InputStream getResourceAsStream(String name)
  98. {
  99. if(jar == null)
  100. return null;
  101. try
  102. {
  103. ZipFile zipFile = jar.getZipFile();
  104. ZipEntry entry = zipFile.getEntry(name);
  105. if(entry == null)
  106. return getSystemResourceAsStream(name);
  107. else
  108. return zipFile.getInputStream(entry);
  109. }
  110. catch(IOException io)
  111. {
  112. Log.log(Log.ERROR,this,io);
  113. return null;
  114. }
  115. } //}}}
  116. //{{{ getResource() method
  117. public URL getResource(String name)
  118. {
  119. if(jar == null)
  120. return null;
  121. try
  122. {
  123. ZipFile zipFile = jar.getZipFile();
  124. ZipEntry entry = zipFile.getEntry(name);
  125. if(entry == null)
  126. return getSystemResource(name);
  127. else
  128. return new URL(getResourceAsPath(name));
  129. }
  130. catch(IOException io)
  131. {
  132. Log.log(Log.ERROR,this,io);
  133. return null;
  134. }
  135. } //}}}
  136. //{{{ getResourceAsPath() method
  137. public String getResourceAsPath(String name)
  138. {
  139. if(jar == null)
  140. return null;
  141. if(!name.startsWith("/"))
  142. name = "/" + name;
  143. return "jeditresource:/" + MiscUtilities.getFileName(
  144. jar.getPath()) + "!" + name;
  145. } //}}}
  146. //{{{ getZipFile() method
  147. /**
  148. * @deprecated Call <code>PluginJAR.getZipFile()</code> instead.
  149. */
  150. public ZipFile getZipFile()
  151. {
  152. try
  153. {
  154. return jar.getZipFile();
  155. }
  156. catch(IOException io)
  157. {
  158. Log.log(Log.ERROR,this,io);
  159. return null;
  160. }
  161. } //}}}
  162. //{{{ dump() method
  163. /**
  164. * For debugging.
  165. */
  166. public static void dump()
  167. {
  168. Log.log(Log.DEBUG,JARClassLoader.class,
  169. "Total instances created: " + INDEX);
  170. Log.log(Log.DEBUG,JARClassLoader.class,
  171. "Live instances: " + live);
  172. synchronized(classHash)
  173. {
  174. Iterator entries = classHash.entrySet().iterator();
  175. while(entries.hasNext())
  176. {
  177. Map.Entry entry = (Map.Entry)entries.next();
  178. if(entry.getValue() != NO_CLASS)
  179. {
  180. Log.log(Log.DEBUG,JARClassLoader.class,
  181. entry.getKey() + " ==> "
  182. + entry.getValue());
  183. }
  184. }
  185. }
  186. } //}}}
  187. //{{{ toString() method
  188. public String toString()
  189. {
  190. if(jar == null)
  191. return "<anonymous>(" + id + ")";
  192. else
  193. return jar.getPath() + " (" + id + ")";
  194. } //}}}
  195. //{{{ finalize() method
  196. protected void finalize()
  197. {
  198. live--;
  199. } //}}}
  200. //{{{ Package-private members
  201. //{{{ JARClassLoader constructor
  202. /**
  203. * @since jEdit 4.2pre1
  204. */
  205. JARClassLoader(PluginJAR jar)
  206. {
  207. this();
  208. this.jar = jar;
  209. } //}}}
  210. //{{{ activate() method
  211. void activate()
  212. {
  213. String[] classes = jar.getClasses();
  214. if(classes != null)
  215. {
  216. for(int i = 0; i < classes.length; i++)
  217. {
  218. classHash.put(classes[i],this);
  219. }
  220. }
  221. } //}}}
  222. //{{{ deactivate() method
  223. void deactivate()
  224. {
  225. String[] classes = jar.getClasses();
  226. if(classes == null)
  227. return;
  228. for(int i = 0; i < classes.length; i++)
  229. {
  230. Object loader = classHash.get(classes[i]);
  231. if(loader == this)
  232. classHash.remove(classes[i]);
  233. else
  234. /* two plugins provide same class! */;
  235. }
  236. } //}}}
  237. //}}}
  238. //{{{ Private members
  239. // used to mark non-existent classes in class hash
  240. private static final Object NO_CLASS = new Object();
  241. private static int INDEX;
  242. private static int live;
  243. private static Hashtable classHash = new Hashtable();
  244. private int id;
  245. private PluginJAR jar;
  246. //{{{ _loadClass() method
  247. /**
  248. * Load class from this JAR only.
  249. */
  250. private synchronized Class _loadClass(String clazz, boolean resolveIt)
  251. throws ClassNotFoundException
  252. {
  253. jar.activatePlugin();
  254. synchronized(this)
  255. {
  256. Class cls = findLoadedClass(clazz);
  257. if(cls != null)
  258. {
  259. if(resolveIt)
  260. resolveClass(cls);
  261. return cls;
  262. }
  263. String name = MiscUtilities.classToFile(clazz);
  264. try
  265. {
  266. ZipFile zipFile = jar.getZipFile();
  267. ZipEntry entry = zipFile.getEntry(name);
  268. if(entry == null)
  269. throw new ClassNotFoundException(clazz);
  270. InputStream in = zipFile.getInputStream(entry);
  271. int len = (int)entry.getSize();
  272. byte[] data = new byte[len];
  273. int success = 0;
  274. int offset = 0;
  275. while(success < len)
  276. {
  277. len -= success;
  278. offset += success;
  279. success = in.read(data,offset,len);
  280. if(success == -1)
  281. {
  282. Log.log(Log.ERROR,this,"Failed to load class "
  283. + clazz + " from " + zipFile.getName());
  284. throw new ClassNotFoundException(clazz);
  285. }
  286. }
  287. cls = defineClass(clazz,data,0,data.length);
  288. if(resolveIt)
  289. resolveClass(cls);
  290. return cls;
  291. }
  292. catch(IOException io)
  293. {
  294. Log.log(Log.ERROR,this,io);
  295. throw new ClassNotFoundException(clazz);
  296. }
  297. }
  298. } //}}}
  299. //}}}
  300. }