PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/BeanShellFacade.java

#
Java | 338 lines | 188 code | 27 blank | 123 comment | 21 complexity | 10505b8972d618a9559dd74f84ade38b 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. * BeanShellFacade.java - A BeanShell facade
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2007 Matthieu Casanova
  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 java.lang.reflect.InvocationTargetException;
  25. import org.gjt.sp.jedit.bsh.BshClassManager;
  26. import org.gjt.sp.jedit.bsh.BshMethod;
  27. import org.gjt.sp.jedit.bsh.CallStack;
  28. import org.gjt.sp.jedit.bsh.Interpreter;
  29. import org.gjt.sp.jedit.bsh.NameSpace;
  30. import org.gjt.sp.jedit.bsh.Primitive;
  31. import org.gjt.sp.jedit.bsh.TargetError;
  32. import org.gjt.sp.jedit.bsh.UtilEvalError;
  33. import org.gjt.sp.jedit.bsh.classpath.ClassManagerImpl;
  34. import org.gjt.sp.jedit.textarea.TextArea;
  35. import org.gjt.sp.util.Log;
  36. //}}}
  37. /**
  38. * This class will be the interface for beanshell interaction.
  39. * In jEdit it will be used with the static methods of {@link BeanShell}
  40. * @author Matthieu Casanova
  41. * @since jEdit 4.3pre13
  42. */
  43. public abstract class BeanShellFacade<T>
  44. {
  45. //{{{ BeanShellFacade constructor
  46. protected BeanShellFacade()
  47. {
  48. classManager = new ClassManagerImpl();
  49. global = new NameSpace(classManager,
  50. "jEdit embedded BeanShell interpreter");
  51. interpForMethods = createInterpreter(global);
  52. init();
  53. } //}}}
  54. //{{{ init() method
  55. /**
  56. * Initialize things. It is called by the constructor.
  57. * You can override it to import other packages
  58. */
  59. protected void init()
  60. {
  61. global.importPackage("org.gjt.sp.jedit");
  62. global.importPackage("org.gjt.sp.jedit.buffer");
  63. global.importPackage("org.gjt.sp.jedit.syntax");
  64. global.importPackage("org.gjt.sp.jedit.textarea");
  65. global.importPackage("org.gjt.sp.util");
  66. } //}}}
  67. //{{{ evalSelection() method
  68. /**
  69. * Evaluates the text selected in the specified text area.
  70. */
  71. public void evalSelection(T param, TextArea textArea)
  72. {
  73. String command = textArea.getSelectedText();
  74. if(command == null)
  75. {
  76. textArea.getToolkit().beep();
  77. return;
  78. }
  79. Object returnValue = eval(param,global,command);
  80. if(returnValue != null)
  81. textArea.setSelectedText(returnValue.toString());
  82. } //}}}
  83. //{{{ eval() method
  84. /**
  85. * Evaluates the specified BeanShell expression with the global namespace
  86. * @param param The parameter
  87. * @param command The expression
  88. */
  89. public Object eval(T param, String command)
  90. {
  91. return eval(param, global, command);
  92. } //}}}
  93. //{{{ eval() method
  94. /**
  95. * Evaluates the specified BeanShell expression. Errors are reported in
  96. * a dialog box.
  97. * @param param The parameter
  98. * @param namespace The namespace
  99. * @param command The expression
  100. */
  101. public Object eval(T param, NameSpace namespace, String command)
  102. {
  103. try
  104. {
  105. return _eval(param,namespace,command);
  106. }
  107. catch(Throwable e)
  108. {
  109. Log.log(Log.ERROR,BeanShellFacade.class,e);
  110. handleException(param,null,e);
  111. }
  112. return null;
  113. } //}}}
  114. //{{{ _eval() method
  115. /**
  116. * Evaluates the specified BeanShell expression. Unlike
  117. * <code>eval()</code>, this method passes any exceptions to the caller.
  118. *
  119. * @param view The view. Within the script, references to
  120. * <code>buffer</code>, <code>textArea</code> and <code>editPane</code>
  121. * are determined with reference to this parameter.
  122. * @param namespace The namespace
  123. * @param command The expression
  124. * @exception Exception instances are thrown when various BeanShell
  125. * errors occur
  126. */
  127. public Object _eval(T view, NameSpace namespace, String command)
  128. throws Exception
  129. {
  130. Interpreter interp = createInterpreter(namespace);
  131. try
  132. {
  133. setupDefaultVariables(namespace,view);
  134. if(Debug.BEANSHELL_DEBUG)
  135. Log.log(Log.DEBUG,BeanShellFacade.class,command);
  136. return interp.eval(command);
  137. }
  138. catch(Exception e)
  139. {
  140. unwrapException(e);
  141. // never called
  142. return null;
  143. }
  144. finally
  145. {
  146. try
  147. {
  148. resetDefaultVariables(namespace);
  149. }
  150. catch(UtilEvalError e)
  151. {
  152. // do nothing
  153. }
  154. }
  155. } //}}}
  156. //{{{ cacheBlock() method
  157. /**
  158. * Caches a block of code, returning a handle that can be passed to
  159. * runCachedBlock().
  160. * @param id An identifier.
  161. * @param code The code
  162. * @param namespace If true, the namespace will be set
  163. * @exception Exception instances are thrown when various BeanShell errors
  164. * occur
  165. */
  166. public BshMethod cacheBlock(String id, String code, boolean namespace)
  167. throws Exception
  168. {
  169. // Make local namespace so that the method could be GCed
  170. // if it becomes unnecessary.
  171. NameSpace local = new NameSpace(global, "__internal_" + id);
  172. // This name should be unique enough not to shadow any outer
  173. // identifier.
  174. String name = "__runCachedMethod";
  175. if(namespace)
  176. {
  177. _eval(null,local,name + "(ns) {\nthis.callstack.set(0,ns);\n" + code + "\n}");
  178. return local.getMethod(name,new Class[] { NameSpace.class });
  179. }
  180. else
  181. {
  182. _eval(null,local,name + "() {\n" + code + "\n}");
  183. return local.getMethod(name,new Class[0]);
  184. }
  185. } //}}}
  186. //{{{ runCachedBlock() method
  187. /**
  188. * Runs a cached block of code in the specified namespace. Faster than
  189. * evaluating the block each time.
  190. * @param method The method instance returned by cacheBlock()
  191. * @param namespace The namespace to run the code in
  192. * @exception Exception instances are thrown when various BeanShell
  193. * errors occur
  194. */
  195. public Object runCachedBlock(BshMethod method, T param,
  196. NameSpace namespace) throws Exception
  197. {
  198. boolean useNamespace;
  199. if(namespace == null)
  200. {
  201. useNamespace = false;
  202. namespace = global;
  203. }
  204. else
  205. useNamespace = true;
  206. try
  207. {
  208. setupDefaultVariables(namespace,param);
  209. Object retVal = method.invoke(useNamespace
  210. ? new Object[] { namespace }
  211. : NO_ARGS,
  212. interpForMethods,new CallStack(), null);
  213. if(retVal instanceof Primitive)
  214. {
  215. if(retVal == Primitive.VOID)
  216. return null;
  217. else
  218. return ((Primitive)retVal).getValue();
  219. }
  220. else
  221. return retVal;
  222. }
  223. catch(Exception e)
  224. {
  225. unwrapException(e);
  226. // never called
  227. return null;
  228. }
  229. finally
  230. {
  231. resetDefaultVariables(namespace);
  232. }
  233. } //}}}
  234. //{{{ getNameSpace() method
  235. /**
  236. * Returns the global namespace.
  237. */
  238. public NameSpace getNameSpace()
  239. {
  240. return global;
  241. } //}}}
  242. //{{{ resetClassManager() method
  243. /**
  244. * Causes BeanShell internal structures to drop references to cached
  245. * Class instances.
  246. */
  247. void resetClassManager()
  248. {
  249. classManager.reset();
  250. } //}}}
  251. //{{{ setVariable() method
  252. /**
  253. * Set a beanshell variable in the namespace without overriding it
  254. * @param nameSpace the namespace
  255. * @param name the name of the variable
  256. * @param object the value of the variable
  257. * @throws UtilEvalError
  258. */
  259. protected void setVariable(NameSpace nameSpace, String name, Object object) throws UtilEvalError
  260. {
  261. if (nameSpace.getVariable(name) == Primitive.VOID)
  262. nameSpace.setVariable(name,object, false);
  263. } //}}}
  264. //{{{ setupDefaultVariables() method
  265. protected abstract void setupDefaultVariables(NameSpace namespace, T param)
  266. throws UtilEvalError;
  267. //}}}
  268. //{{{ resetDefaultVariables() method
  269. protected abstract void resetDefaultVariables(NameSpace namespace)
  270. throws UtilEvalError;
  271. //}}}
  272. //{{{ handleException() method
  273. protected abstract void handleException(T param, String path, Throwable t);
  274. //}}}
  275. //{{{ createInterpreter() method
  276. protected static Interpreter createInterpreter(NameSpace nameSpace)
  277. {
  278. return new Interpreter(null,System.out,System.err,false,nameSpace);
  279. } //}}}
  280. //{{{ unwrapException() method
  281. /**
  282. * This extracts an exception from a 'wrapping' exception, as BeanShell
  283. * sometimes throws. This gives the user a more accurate error traceback
  284. */
  285. protected static void unwrapException(Exception e) throws Exception
  286. {
  287. if(e instanceof TargetError)
  288. {
  289. Throwable t = ((TargetError)e).getTarget();
  290. if(t instanceof Exception)
  291. throw (Exception)t;
  292. else if(t instanceof Error)
  293. throw (Error)t;
  294. }
  295. if(e instanceof InvocationTargetException)
  296. {
  297. Throwable t = ((InvocationTargetException)e).getTargetException();
  298. if(t instanceof Exception)
  299. throw (Exception)t;
  300. else if(t instanceof Error)
  301. throw (Error)t;
  302. }
  303. throw e;
  304. } //}}}
  305. //{{{ Static variables
  306. protected NameSpace global;
  307. protected BshClassManager classManager;
  308. private static Interpreter interpForMethods;
  309. private static final Object[] NO_ARGS = new Object[0];
  310. //}}}
  311. }