/jEdit/tags/jedit-4-2-pre5/org/gjt/sp/jedit/BeanShell.java

# · Java · 798 lines · 457 code · 77 blank · 264 comment · 57 complexity · e64c03483b2593440fa4d2b1d63d9712 MD5 · raw file

  1. /*
  2. * BeanShell.java - BeanShell scripting support
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2001, 2002 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit;
  23. //{{{ Imports
  24. import bsh.*;
  25. import java.io.*;
  26. import java.lang.ref.*;
  27. import java.lang.reflect.InvocationTargetException;
  28. import java.util.*;
  29. import org.gjt.sp.jedit.io.*;
  30. import org.gjt.sp.jedit.gui.BeanShellErrorDialog;
  31. import org.gjt.sp.jedit.textarea.*;
  32. import org.gjt.sp.util.Log;
  33. //}}}
  34. /**
  35. * BeanShell is jEdit's extension language.<p>
  36. *
  37. * When run from jEdit, BeanShell code has access to the following predefined
  38. * variables:
  39. *
  40. * <ul>
  41. * <li><code>view</code> - the currently active {@link View}.</li>
  42. * <li><code>editPane</code> - the currently active {@link EditPane}.</li>
  43. * <li><code>textArea</code> - the edit pane's {@link JEditTextArea}.</li>
  44. * <li><code>buffer</code> - the edit pane's {@link Buffer}.</li>
  45. * <li><code>wm</code> - the view's {@link
  46. * org.gjt.sp.jedit.gui.DockableWindowManager}.</li>
  47. * <li><code>scriptPath</code> - the path name of the currently executing
  48. * BeanShell script.</li>
  49. * </ul>
  50. *
  51. * @author Slava Pestov
  52. * @version $Id: BeanShell.java 4883 2003-09-09 23:40:44Z spestov $
  53. */
  54. public class BeanShell
  55. {
  56. //{{{ evalSelection() method
  57. /**
  58. * Evaluates the text selected in the specified text area.
  59. * @since jEdit 2.7pre2
  60. */
  61. public static void evalSelection(View view, JEditTextArea textArea)
  62. {
  63. String command = textArea.getSelectedText();
  64. if(command == null)
  65. {
  66. view.getToolkit().beep();
  67. return;
  68. }
  69. Object returnValue = eval(view,global,command);
  70. if(returnValue != null)
  71. textArea.setSelectedText(returnValue.toString());
  72. } //}}}
  73. //{{{ showEvaluateDialog() method
  74. /**
  75. * Prompts for a BeanShell expression to evaluate.
  76. * @since jEdit 2.7pre2
  77. */
  78. public static void showEvaluateDialog(View view)
  79. {
  80. String command = GUIUtilities.input(view,"beanshell-eval-input",null);
  81. if(command != null)
  82. {
  83. if(!command.endsWith(";"))
  84. command = command + ";";
  85. int repeat = view.getInputHandler().getRepeatCount();
  86. if(view.getMacroRecorder() != null)
  87. {
  88. view.getMacroRecorder().record(repeat,command);
  89. }
  90. Object returnValue = null;
  91. try
  92. {
  93. for(int i = 0; i < repeat; i++)
  94. {
  95. returnValue = _eval(view,global,command);
  96. }
  97. }
  98. catch(Throwable e)
  99. {
  100. Log.log(Log.ERROR,BeanShell.class,e);
  101. handleException(view,null,e);
  102. }
  103. if(returnValue != null)
  104. {
  105. String[] args = { returnValue.toString() };
  106. GUIUtilities.message(view,"beanshell-eval",args);
  107. }
  108. }
  109. } //}}}
  110. //{{{ showEvaluateLinesDialog() method
  111. /**
  112. * Evaluates the specified script for each selected line.
  113. * @since jEdit 4.0pre1
  114. */
  115. public static void showEvaluateLinesDialog(View view)
  116. {
  117. String command = GUIUtilities.input(view,"beanshell-eval-line",null);
  118. JEditTextArea textArea = view.getTextArea();
  119. Buffer buffer = view.getBuffer();
  120. if(command == null || command.length() == 0)
  121. return;
  122. Selection[] selection = textArea.getSelection();
  123. if(selection.length == 0)
  124. {
  125. view.getToolkit().beep();
  126. return;
  127. }
  128. if(!command.endsWith(";"))
  129. command = command + ";";
  130. String script = "int[] lines = textArea.getSelectedLines();\n"
  131. + "for(int i = 0; i < lines.length; i++)\n"
  132. + "{\n"
  133. + "line = lines[i];\n"
  134. + "index = line - lines[0];\n"
  135. + "start = buffer.getLineStartOffset(line);\n"
  136. + "end = buffer.getLineEndOffset(line);\n"
  137. + "text = buffer.getText(start,end - start - 1);\n"
  138. + "newText = " + command + "\n"
  139. + "if(newText != null)\n"
  140. + "{\n"
  141. + "buffer.remove(start,end - start - 1);\n"
  142. + "buffer.insert(start,String.valueOf(newText));\n"
  143. + "}\n"
  144. + "}\n";
  145. if(view.getMacroRecorder() != null)
  146. view.getMacroRecorder().record(1,script);
  147. try
  148. {
  149. buffer.beginCompoundEdit();
  150. BeanShell.eval(view,global,script);
  151. }
  152. finally
  153. {
  154. buffer.endCompoundEdit();
  155. }
  156. textArea.selectNone();
  157. } //}}}
  158. //{{{ runScript() method
  159. /**
  160. * Runs a BeanShell script. Errors are shown in a dialog box.<p>
  161. *
  162. * If the <code>in</code> parameter is non-null, the script is
  163. * read from that stream; otherwise it is read from the file identified
  164. * by <code>path</code>.<p>
  165. *
  166. * The <code>scriptPath</code> BeanShell variable is set to the path
  167. * name of the script.
  168. *
  169. * @param view The view. Within the script, references to
  170. * <code>buffer</code>, <code>textArea</code> and <code>editPane</code>
  171. * are determined with reference to this parameter.
  172. * @param path The script file's VFS path.
  173. * @param in The reader to read the script from, or <code>null</code>.
  174. * @param ownNamespace If set to <code>false</code>, methods and
  175. * variables defined in the script will be available to all future
  176. * uses of BeanShell; if set to <code>true</code>, they will be lost as
  177. * soon as the script finishes executing. jEdit uses a value of
  178. * <code>false</code> when running startup scripts, and a value of
  179. * <code>true</code> when running all other macros.
  180. *
  181. * @since jEdit 4.0pre7
  182. */
  183. public static void runScript(View view, String path, Reader in,
  184. boolean ownNamespace)
  185. {
  186. try
  187. {
  188. _runScript(view,path,in,ownNamespace);
  189. }
  190. catch(Throwable e)
  191. {
  192. Log.log(Log.ERROR,BeanShell.class,e);
  193. handleException(view,path,e);
  194. }
  195. } //}}}
  196. //{{{ runScript() method
  197. /**
  198. * Runs a BeanShell script. Errors are shown in a dialog box.<p>
  199. *
  200. * If the <code>in</code> parameter is non-null, the script is
  201. * read from that stream; otherwise it is read from the file identified
  202. * by <code>path</code>.<p>
  203. *
  204. * The <code>scriptPath</code> BeanShell variable is set to the path
  205. * name of the script.
  206. *
  207. * @param view The view. Within the script, references to
  208. * <code>buffer</code>, <code>textArea</code> and <code>editPane</code>
  209. * are determined with reference to this parameter.
  210. * @param path The script file's VFS path.
  211. * @param in The reader to read the script from, or <code>null</code>.
  212. * @param namespace The namespace to run the script in.
  213. *
  214. * @since jEdit 4.2pre5
  215. */
  216. public static void runScript(View view, String path, Reader in,
  217. NameSpace namespace)
  218. {
  219. try
  220. {
  221. _runScript(view,path,in,namespace);
  222. }
  223. catch(Throwable e)
  224. {
  225. Log.log(Log.ERROR,BeanShell.class,e);
  226. handleException(view,path,e);
  227. }
  228. } //}}}
  229. //{{{ _runScript() method
  230. /**
  231. * Runs a BeanShell script. Errors are passed to the caller.<p>
  232. *
  233. * If the <code>in</code> parameter is non-null, the script is
  234. * read from that stream; otherwise it is read from the file identified
  235. * by <code>path</code>.<p>
  236. *
  237. * The <code>scriptPath</code> BeanShell variable is set to the path
  238. * name of the script.
  239. *
  240. * @param view The view. Within the script, references to
  241. * <code>buffer</code>, <code>textArea</code> and <code>editPane</code>
  242. * are determined with reference to this parameter.
  243. * @param path The script file's VFS path.
  244. * @param in The reader to read the script from, or <code>null</code>.
  245. * @param ownNamespace If set to <code>false</code>, methods and
  246. * variables defined in the script will be available to all future
  247. * uses of BeanShell; if set to <code>true</code>, they will be lost as
  248. * soon as the script finishes executing. jEdit uses a value of
  249. * <code>false</code> when running startup scripts, and a value of
  250. * <code>true</code> when running all other macros.
  251. * @exception Exception instances are thrown when various BeanShell errors
  252. * occur
  253. * @since jEdit 4.0pre7
  254. */
  255. public static void _runScript(View view, String path, Reader in,
  256. boolean ownNamespace) throws Exception
  257. {
  258. _runScript(view,path,in,ownNamespace
  259. ? new NameSpace(global,"script namespace")
  260. : global);
  261. } //}}}
  262. //{{{ _runScript() method
  263. /**
  264. * Runs a BeanShell script. Errors are passed to the caller.<p>
  265. *
  266. * If the <code>in</code> parameter is non-null, the script is
  267. * read from that stream; otherwise it is read from the file identified
  268. * by <code>path</code>.<p>
  269. *
  270. * The <code>scriptPath</code> BeanShell variable is set to the path
  271. * name of the script.
  272. *
  273. * @param view The view. Within the script, references to
  274. * <code>buffer</code>, <code>textArea</code> and <code>editPane</code>
  275. * are determined with reference to this parameter.
  276. * @param path The script file's VFS path.
  277. * @param in The reader to read the script from, or <code>null</code>.
  278. * @param namespace The namespace to run the script in.
  279. * @exception Exception instances are thrown when various BeanShell errors
  280. * occur
  281. * @since jEdit 4.2pre5
  282. */
  283. public static void _runScript(View view, String path, Reader in,
  284. NameSpace namespace) throws Exception
  285. {
  286. Log.log(Log.MESSAGE,BeanShell.class,"Running script " + path);
  287. Interpreter interp = createInterpreter(namespace);
  288. VFS vfs = null;
  289. Object session = null;
  290. try
  291. {
  292. if(in == null)
  293. {
  294. Buffer buffer = jEdit.getBuffer(path);
  295. vfs = VFSManager.getVFSForPath(path);
  296. session = vfs.createVFSSession(path,view);
  297. if(session == null)
  298. {
  299. // user cancelled???
  300. return;
  301. }
  302. if(buffer != null)
  303. {
  304. if(!buffer.isLoaded())
  305. VFSManager.waitForRequests();
  306. in = new StringReader(buffer.getText(0,
  307. buffer.getLength()));
  308. }
  309. else
  310. {
  311. in = new BufferedReader(new InputStreamReader(
  312. vfs._createInputStream(session,
  313. path,false,view)));
  314. }
  315. }
  316. setupDefaultVariables(namespace,view);
  317. interp.set("scriptPath",path);
  318. running = true;
  319. interp.eval(in,namespace,path);
  320. }
  321. catch(Exception e)
  322. {
  323. unwrapException(e);
  324. }
  325. finally
  326. {
  327. running = false;
  328. if(session != null)
  329. {
  330. try
  331. {
  332. vfs._endVFSSession(session,view);
  333. }
  334. catch(IOException io)
  335. {
  336. Log.log(Log.ERROR,BeanShell.class,io);
  337. GUIUtilities.error(view,"read-error",
  338. new String[] { path, io.toString() });
  339. }
  340. }
  341. try
  342. {
  343. // no need to do this for macros!
  344. if(namespace == global)
  345. {
  346. resetDefaultVariables(namespace);
  347. interp.unset("scriptPath");
  348. }
  349. }
  350. catch(EvalError e)
  351. {
  352. // do nothing
  353. }
  354. }
  355. } //}}}
  356. //{{{ eval() method
  357. /**
  358. * Evaluates the specified BeanShell expression. Errors are reported in
  359. * a dialog box.
  360. * @param view The view. Within the script, references to
  361. * <code>buffer</code>, <code>textArea</code> and <code>editPane</code>
  362. * are determined with reference to this parameter.
  363. * @param namespace The namespace
  364. * @param command The expression
  365. * @since jEdit 4.0pre8
  366. */
  367. public static Object eval(View view, NameSpace namespace, String command)
  368. {
  369. try
  370. {
  371. return _eval(view,namespace,command);
  372. }
  373. catch(Throwable e)
  374. {
  375. Log.log(Log.ERROR,BeanShell.class,e);
  376. handleException(view,null,e);
  377. }
  378. return null;
  379. } //}}}
  380. //{{{ _eval() method
  381. /**
  382. * Evaluates the specified BeanShell expression. Unlike
  383. * <code>eval()</code>, this method passes any exceptions to the caller.
  384. *
  385. * @param view The view. Within the script, references to
  386. * <code>buffer</code>, <code>textArea</code> and <code>editPane</code>
  387. * are determined with reference to this parameter.
  388. * @param namespace The namespace
  389. * @param command The expression
  390. * @exception Exception instances are thrown when various BeanShell
  391. * errors occur
  392. * @since jEdit 3.2pre7
  393. */
  394. public static Object _eval(View view, NameSpace namespace, String command)
  395. throws Exception
  396. {
  397. Interpreter interp = createInterpreter(namespace);
  398. try
  399. {
  400. setupDefaultVariables(namespace,view);
  401. if(Debug.BEANSHELL_DEBUG)
  402. Log.log(Log.DEBUG,BeanShell.class,command);
  403. return interp.eval(command);
  404. }
  405. catch(Exception e)
  406. {
  407. unwrapException(e);
  408. // never called
  409. return null;
  410. }
  411. finally
  412. {
  413. try
  414. {
  415. resetDefaultVariables(namespace);
  416. }
  417. catch(UtilEvalError e)
  418. {
  419. // do nothing
  420. }
  421. }
  422. } //}}}
  423. //{{{ cacheBlock() method
  424. /**
  425. * Caches a block of code, returning a handle that can be passed to
  426. * runCachedBlock().
  427. * @param id An identifier. If null, a unique identifier is generated
  428. * @param code The code
  429. * @param namespace If true, the namespace will be set
  430. * @exception Exception instances are thrown when various BeanShell errors
  431. * occur
  432. * @since jEdit 4.1pre1
  433. */
  434. public static BshMethod cacheBlock(String id, String code, boolean namespace)
  435. throws Exception
  436. {
  437. String name = "__internal_" + id;
  438. // evaluate a method declaration
  439. if(namespace)
  440. {
  441. _eval(null,global,name + "(ns) {\nthis.callstack.set(0,ns);\n" + code + "\n}");
  442. return global.getMethod(name,new Class[] { NameSpace.class });
  443. }
  444. else
  445. {
  446. _eval(null,global,name + "() {\n" + code + "\n}");
  447. return global.getMethod(name,new Class[0]);
  448. }
  449. } //}}}
  450. //{{{ runCachedBlock() method
  451. /**
  452. * Runs a cached block of code in the specified namespace. Faster than
  453. * evaluating the block each time.
  454. * @param method The method instance returned by cacheBlock()
  455. * @param view The view
  456. * @param namespace The namespace to run the code in
  457. * @exception Exception instances are thrown when various BeanShell
  458. * errors occur
  459. * @since jEdit 4.1pre1
  460. */
  461. public static Object runCachedBlock(BshMethod method, View view,
  462. NameSpace namespace) throws Exception
  463. {
  464. boolean useNamespace;
  465. if(namespace == null)
  466. {
  467. useNamespace = false;
  468. namespace = global;
  469. }
  470. else
  471. useNamespace = true;
  472. try
  473. {
  474. setupDefaultVariables(namespace,view);
  475. Object retVal = method.invoke(useNamespace
  476. ? new Object[] { namespace }
  477. : NO_ARGS,
  478. interpForMethods,new CallStack());
  479. if(retVal instanceof Primitive)
  480. {
  481. if(retVal == Primitive.VOID)
  482. return null;
  483. else
  484. return ((Primitive)retVal).getValue();
  485. }
  486. else
  487. return retVal;
  488. }
  489. catch(Exception e)
  490. {
  491. unwrapException(e);
  492. // never called
  493. return null;
  494. }
  495. finally
  496. {
  497. resetDefaultVariables(namespace);
  498. }
  499. } //}}}
  500. //{{{ isScriptRunning() method
  501. /**
  502. * Returns if a BeanShell script or macro is currently running.
  503. * @since jEdit 2.7pre2
  504. */
  505. public static boolean isScriptRunning()
  506. {
  507. return running;
  508. } //}}}
  509. //{{{ getNameSpace() method
  510. /**
  511. * Returns the global namespace.
  512. * @since jEdit 3.2pre5
  513. */
  514. public static NameSpace getNameSpace()
  515. {
  516. return global;
  517. } //}}}
  518. //{{{ Deprecated functions
  519. //{{{ runScript() method
  520. /**
  521. * @deprecated The <code>rethrowBshErrors</code> parameter is now
  522. * obsolete; call <code>_runScript()</code> or <code>runScript()</code>
  523. * instead.
  524. */
  525. public static void runScript(View view, String path,
  526. boolean ownNamespace, boolean rethrowBshErrors)
  527. {
  528. runScript(view,path,null,ownNamespace);
  529. } //}}}
  530. //{{{ runScript() method
  531. /**
  532. * @deprecated The <code>rethrowBshErrors</code> parameter is now
  533. * obsolete; call <code>_runScript()</code> or <code>runScript()</code>
  534. * instead.
  535. */
  536. public static void runScript(View view, String path, Reader in,
  537. boolean ownNamespace, boolean rethrowBshErrors)
  538. {
  539. runScript(view,path,in,ownNamespace);
  540. } //}}}
  541. //{{{ eval() method
  542. /**
  543. * @deprecated The <code>rethrowBshErrors</code> parameter is now
  544. * obsolete; call <code>_eval()</code> or <code>eval()</code> instead.
  545. */
  546. public static Object eval(View view, String command,
  547. boolean rethrowBshErrors)
  548. {
  549. return eval(view,global,command);
  550. } //}}}
  551. //{{{ eval() method
  552. /**
  553. * @deprecated The <code>rethrowBshErrors</code> parameter is now
  554. * obsolete; call <code>_eval()</code> or <code>eval()</code> instead.
  555. */
  556. public static Object eval(View view, NameSpace namespace,
  557. String command, boolean rethrowBshErrors)
  558. {
  559. return eval(view,namespace,command);
  560. } //}}}
  561. //}}}
  562. //{{{ Package-private members
  563. //{{{ init() method
  564. static void init()
  565. {
  566. classManager = new CustomClassManager();
  567. classManager.setClassLoader(new JARClassLoader());
  568. global = new NameSpace(classManager,
  569. "jEdit embedded BeanShell interpreter");
  570. global.importPackage("org.gjt.sp.jedit");
  571. global.importPackage("org.gjt.sp.jedit.browser");
  572. global.importPackage("org.gjt.sp.jedit.buffer");
  573. global.importPackage("org.gjt.sp.jedit.gui");
  574. global.importPackage("org.gjt.sp.jedit.help");
  575. global.importPackage("org.gjt.sp.jedit.io");
  576. global.importPackage("org.gjt.sp.jedit.menu");
  577. global.importPackage("org.gjt.sp.jedit.msg");
  578. global.importPackage("org.gjt.sp.jedit.options");
  579. global.importPackage("org.gjt.sp.jedit.pluginmgr");
  580. global.importPackage("org.gjt.sp.jedit.print");
  581. global.importPackage("org.gjt.sp.jedit.search");
  582. global.importPackage("org.gjt.sp.jedit.syntax");
  583. global.importPackage("org.gjt.sp.jedit.textarea");
  584. global.importPackage("org.gjt.sp.util");
  585. interpForMethods = createInterpreter(global);
  586. } //}}}
  587. //{{{ resetClassManager() method
  588. /**
  589. * Causes BeanShell internal structures to drop references to cached
  590. * Class instances.
  591. */
  592. static void resetClassManager()
  593. {
  594. classManager.reset();
  595. } //}}}
  596. //}}}
  597. //{{{ Private members
  598. //{{{ Static variables
  599. private static final Object[] NO_ARGS = new Object[0];
  600. private static CustomClassManager classManager;
  601. private static Interpreter interpForMethods;
  602. private static NameSpace global;
  603. private static boolean running;
  604. //}}}
  605. //{{{ setupDefaultVariables() method
  606. private static void setupDefaultVariables(NameSpace namespace, View view)
  607. throws UtilEvalError
  608. {
  609. if(view != null)
  610. {
  611. EditPane editPane = view.getEditPane();
  612. namespace.setVariable("view",view);
  613. namespace.setVariable("editPane",editPane);
  614. namespace.setVariable("buffer",editPane.getBuffer());
  615. namespace.setVariable("textArea",editPane.getTextArea());
  616. namespace.setVariable("wm",view.getDockableWindowManager());
  617. }
  618. } //}}}
  619. //{{{ resetDefaultVariables() method
  620. private static void resetDefaultVariables(NameSpace namespace)
  621. throws UtilEvalError
  622. {
  623. namespace.setVariable("view",null);
  624. namespace.setVariable("editPane",null);
  625. namespace.setVariable("buffer",null);
  626. namespace.setVariable("textArea",null);
  627. namespace.setVariable("wm",null);
  628. } //}}}
  629. //{{{ unwrapException() method
  630. /**
  631. * This extracts an exception from a 'wrapping' exception, as BeanShell
  632. * sometimes throws. This gives the user a more accurate error traceback
  633. */
  634. private static void unwrapException(Exception e) throws Exception
  635. {
  636. if(e instanceof TargetError)
  637. {
  638. Throwable t = ((TargetError)e).getTarget();
  639. if(t instanceof Exception)
  640. throw (Exception)t;
  641. else if(t instanceof Error)
  642. throw (Error)t;
  643. }
  644. if(e instanceof InvocationTargetException)
  645. {
  646. Throwable t = ((InvocationTargetException)e).getTargetException();
  647. if(t instanceof Exception)
  648. throw (Exception)t;
  649. else if(t instanceof Error)
  650. throw (Error)t;
  651. }
  652. throw e;
  653. } //}}}
  654. //{{{ handleException() method
  655. private static void handleException(View view, String path, Throwable t)
  656. {
  657. if(t instanceof IOException)
  658. {
  659. VFSManager.error(view,path,"ioerror.read-error",
  660. new String[] { t.toString() });
  661. }
  662. else
  663. new BeanShellErrorDialog(view,t);
  664. } //}}}
  665. //{{{ createInterpreter() method
  666. private static Interpreter createInterpreter(NameSpace nameSpace)
  667. {
  668. return new Interpreter(null,System.out,System.err,false,nameSpace);
  669. } //}}}
  670. //}}}
  671. //{{{ CustomClassManager class
  672. static class CustomClassManager extends BshClassManager
  673. {
  674. private LinkedList listeners = new LinkedList();
  675. private ReferenceQueue refQueue = new ReferenceQueue();
  676. // copy and paste from bsh/classpath/ClassManagerImpl.java...
  677. public synchronized void addListener( Listener l )
  678. {
  679. listeners.add( new WeakReference( l, refQueue) );
  680. // clean up old listeners
  681. Reference deadref;
  682. while ( (deadref = refQueue.poll()) != null )
  683. {
  684. boolean ok = listeners.remove( deadref );
  685. if ( ok )
  686. {
  687. //System.err.println("cleaned up weak ref: "+deadref);
  688. }
  689. else
  690. {
  691. if ( Interpreter.DEBUG ) Interpreter.debug(
  692. "tried to remove non-existent weak ref: "+deadref);
  693. }
  694. }
  695. }
  696. public void removeListener( Listener l )
  697. {
  698. throw new Error("unimplemented");
  699. }
  700. public void reset()
  701. {
  702. classLoaderChanged();
  703. }
  704. protected synchronized void classLoaderChanged()
  705. {
  706. // clear the static caches in BshClassManager
  707. clearCaches();
  708. for (Iterator iter = listeners.iterator();
  709. iter.hasNext(); )
  710. {
  711. WeakReference wr = (WeakReference)
  712. iter.next();
  713. Listener l = (Listener)wr.get();
  714. if ( l == null ) // garbage collected
  715. iter.remove();
  716. else
  717. l.classLoaderChanged();
  718. }
  719. }
  720. } //}}}
  721. }