PageRenderTime 42ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/bsh/BshClassManager.java

#
Java | 332 lines | 107 code | 36 blank | 189 comment | 18 complexity | 0c43b46498b4e99d7219235a91e7d0f3 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. * *
  3. * This file is part of the BeanShell Java Scripting distribution. *
  4. * Documentation and updates may be found at http://www.beanshell.org/ *
  5. * *
  6. * Sun Public License Notice: *
  7. * *
  8. * The contents of this file are subject to the Sun Public License Version *
  9. * 1.0 (the "License"); you may not use this file except in compliance with *
  10. * the License. A copy of the License is available at http://www.sun.com *
  11. * *
  12. * The Original Code is BeanShell. The Initial Developer of the Original *
  13. * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
  14. * (C) 2000. All Rights Reserved. *
  15. * *
  16. * GNU Public License Notice: *
  17. * *
  18. * Alternatively, the contents of this file may be used under the terms of *
  19. * the GNU Lesser General Public License (the "LGPL"), in which case the *
  20. * provisions of LGPL are applicable instead of those above. If you wish to *
  21. * allow use of your version of this file only under the terms of the LGPL *
  22. * and not to allow others to use your version of this file under the SPL, *
  23. * indicate your decision by deleting the provisions above and replace *
  24. * them with the notice and other provisions required by the LGPL. If you *
  25. * do not delete the provisions above, a recipient may use your version of *
  26. * this file under either the SPL or the LGPL. *
  27. * *
  28. * Patrick Niemeyer (pat@pat.net) *
  29. * Author of Learning Java, O'Reilly & Associates *
  30. * http://www.pat.net/~pat/ *
  31. * *
  32. *****************************************************************************/
  33. package bsh;
  34. import java.net.*;
  35. import java.util.*;
  36. import java.io.IOException;
  37. import java.io.*;
  38. /**
  39. BshClassManager manages all classloading in BeanShell.
  40. It also supports a dynamically loaded extension (bsh.classpath package)
  41. which allows classpath extension and class file reloading.
  42. Currently the extension relies on 1.2 for BshClassLoader and weak
  43. references.
  44. See http://www.beanshell.org/manual/classloading.html for details
  45. on the bsh classloader architecture.
  46. <p>
  47. Bsh has a multi-tiered class loading architecture. No class loader is
  48. used unless/until the classpath is modified or a class is reloaded.
  49. <p>
  50. Note: currently class loading features affect all instances of the
  51. Interpreter. However the basic design of this class will allow for
  52. per instance class management in the future if it is desired.
  53. */
  54. /*
  55. Implementation notes:
  56. Note: we may need some synchronization in here
  57. Note on jdk1.2 dependency:
  58. <p>
  59. We are forced to use weak references here to accomodate all of the
  60. fleeting namespace listeners as they fall out of scope. (NameSpaces must
  61. be informed if the class space changes so that they can un-cache names).
  62. I had the thought that a way around this would be to implement BeanShell's
  63. own garbage collector... Then I came to my senses.
  64. <p>
  65. Perhaps a simpler idea would be to have entities that reference cached
  66. types always perform a light weight check with a counter / reference
  67. value and use that to detect changes in the namespace. This puts the
  68. burden on the consumer to check at appropriate times, but could eliminate
  69. the need for the listener system in many places and the necessity of weak
  70. references in this package.
  71. <p>
  72. */
  73. public abstract class BshClassManager
  74. {
  75. /** Singleton class manager */
  76. private static BshClassManager manager;
  77. private static boolean checkedForManager;
  78. // Use a hashtable as a Set...
  79. private static Object NOVALUE = new Object();
  80. /**
  81. An external classloader supplied by the setClassLoader() command.
  82. */
  83. private static ClassLoader externalClassLoader;
  84. /**
  85. Global cache for things we know are classes.
  86. Note: these should probably be re-implemented with Soft references.
  87. (as opposed to strong or Weak)
  88. */
  89. protected transient static Hashtable absoluteClassCache = new Hashtable();
  90. /**
  91. Global cache for things we know are *not* classes.
  92. Note: these should probably be re-implemented with Soft references.
  93. (as opposed to strong or Weak)
  94. */
  95. protected transient static Hashtable absoluteNonClasses = new Hashtable();
  96. // Begin static methods
  97. /**
  98. @return the BshClassManager singleton or null, indicating no
  99. class manager is available.
  100. */
  101. // Note: this should probably throw Capabilities.Unavailable instead of
  102. // returning null
  103. public static BshClassManager getClassManager()
  104. {
  105. // Bootstrap the class manager if it exists
  106. // have we loaded it before?
  107. if ( !checkedForManager && manager == null )
  108. // Do we have the necessary jdk1.2 packages?
  109. try {
  110. if ( plainClassForName("java.lang.ref.WeakReference") != null
  111. && plainClassForName("java.util.HashMap") != null )
  112. {
  113. // try to load the implementation
  114. Class bcm = plainClassForName(
  115. "bsh.classpath.ClassManagerImpl");
  116. manager = (BshClassManager)bcm.newInstance();
  117. }
  118. } catch ( ClassNotFoundException e ) {
  119. //System.err.println("No class manager available.");
  120. } catch ( Exception e ) {
  121. System.err.println("Error loading classmanager: "+e);
  122. }
  123. checkedForManager = true;
  124. return manager;
  125. }
  126. public static boolean classExists( String name ) {
  127. return ( classForName( name ) != null );
  128. }
  129. /**
  130. Load the specified class by name, taking into account added classpath
  131. and reloaded classes, etc.
  132. @return the class or null
  133. */
  134. public static Class classForName( String name ) {
  135. BshClassManager manager = getClassManager(); // prime the singleton
  136. if ( manager != null )
  137. return manager.getClassForName( name );
  138. else
  139. try {
  140. return plainClassForName( name );
  141. } catch ( ClassNotFoundException e ) {
  142. return null;
  143. }
  144. }
  145. /**
  146. Perform a plain Class.forName()
  147. This simply wraps that method call and provides a central point for
  148. monitoring and handling certain Java version dependent bugs, etc.
  149. Note: this used to be called loadSystemClass()
  150. @return the class
  151. */
  152. public static Class plainClassForName( String name )
  153. throws ClassNotFoundException
  154. {
  155. try {
  156. Class c;
  157. if ( externalClassLoader != null ) {
  158. c = externalClassLoader.loadClass( name );
  159. }else
  160. c = Class.forName(name);
  161. cacheClassInfo( name, c );
  162. return c;
  163. /*
  164. This is weird... jdk under Win is throwing these to
  165. warn about lower case / upper case possible mismatch.
  166. e.g. bsh.console bsh.Console
  167. */
  168. } catch ( NoClassDefFoundError e ) {
  169. cacheClassInfo( name, null ); // non-class
  170. throw new ClassNotFoundException( e.toString() );
  171. }
  172. }
  173. /**
  174. Cache info about whether name is a class or not.
  175. @param value
  176. if value is non-null, cache the class
  177. if value is null, set the flag that it is *not* a class to
  178. speed later resolution
  179. */
  180. public static void cacheClassInfo( String name, Class value ) {
  181. if ( value != null )
  182. absoluteClassCache.put( name, value );
  183. else
  184. absoluteNonClasses.put( name, NOVALUE );
  185. }
  186. /**
  187. Clear the static caches in BshClassManager
  188. */
  189. protected void clearCaches() {
  190. absoluteNonClasses = new Hashtable();
  191. absoluteClassCache = new Hashtable();
  192. }
  193. /**
  194. Add a BshClassManager.Listener to the class manager.
  195. The listener is informed upon changes to the classpath.
  196. This is a static convenience form of BshClassManager addListener().
  197. If there is no class manager the listener will be ignored.
  198. */
  199. public static void addCMListener( Listener l ) {
  200. getClassManager(); // prime it
  201. if ( manager != null )
  202. manager.addListener( l );
  203. }
  204. /**
  205. Set an external class loader. BeanShell will use this at the same
  206. point it would otherwise use the plain Class.forName().
  207. i.e. if no explicit classpath management is done from the script
  208. (addClassPath(), setClassPath(), reloadClasses()) then BeanShell will
  209. only use the supplied classloader. If additional classpath management
  210. is done then BeanShell will perform that in addition to the supplied
  211. external classloader.
  212. However BeanShell is not currently able to reload
  213. classes supplied through the external classloader.
  214. */
  215. public static void setClassLoader( ClassLoader externalCL )
  216. {
  217. externalClassLoader = externalCL;
  218. BshClassManager bcm = getClassManager();
  219. if ( bcm != null )
  220. bcm.classLoaderChanged();
  221. }
  222. // end static methods
  223. public static interface Listener
  224. {
  225. public void classLoaderChanged();
  226. }
  227. // Begin interface methods
  228. public abstract Class getClassForName( String name );
  229. public abstract ClassLoader getBaseLoader();
  230. public abstract ClassLoader getLoaderForClass( String name );
  231. public abstract void addClassPath( URL path )
  232. throws IOException;
  233. /**
  234. Clear all loaders and start over. No class loading.
  235. */
  236. public abstract void reset();
  237. /**
  238. Set a new base classpath and create a new base classloader.
  239. This means all types change.
  240. */
  241. public abstract void setClassPath( URL [] cp );
  242. /**
  243. Overlay the entire path with a new class loader.
  244. Set the base path to the user path + base path.
  245. No point in including the boot class path (can't reload thos).
  246. */
  247. public abstract void reloadAllClasses() throws ClassPathException;
  248. /**
  249. Reloading classes means creating a new classloader and using it
  250. whenever we are asked for classes in the appropriate space.
  251. For this we use a DiscreteFilesClassLoader
  252. */
  253. public abstract void reloadClasses( String [] classNames )
  254. throws ClassPathException;
  255. /**
  256. Reload all classes in the specified package: e.g. "com.sun.tools"
  257. The special package name "<unpackaged>" can be used to refer
  258. to unpackaged classes.
  259. */
  260. public abstract void reloadPackage( String pack )
  261. throws ClassPathException ;
  262. /**
  263. This has been removed from the interface to shield the core from the
  264. rest of the classpath package. If you need the classpath you will have
  265. to cast the classmanager to its impl.
  266. public abstract BshClassPath getClassPath() throws ClassPathException;
  267. */
  268. /**
  269. Support for "import *;"
  270. Hide details in here as opposed to NameSpace.
  271. Note: this used to be package private...
  272. */
  273. public abstract void doSuperImport() throws EvalError;
  274. /**
  275. Return the name or null if none is found,
  276. Throw an ClassPathException containing detail if name is ambigous.
  277. Note: this used to be package private...
  278. */
  279. public abstract String getClassNameByUnqName( String name )
  280. throws ClassPathException;
  281. public abstract void addListener( Listener l );
  282. public abstract void removeListener( Listener l );
  283. public abstract void dump( PrintWriter pw );
  284. protected abstract void classLoaderChanged();
  285. }