PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/ServiceManager.java

#
Java | 352 lines | 174 code | 25 blank | 153 comment | 19 complexity | e2de61679d155d244f8c21094460e9ac 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. * ServiceManager.java - Handles services.xml files in plugins
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2003 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. import com.microstar.xml.*;
  24. import java.io.*;
  25. import java.net.URL;
  26. import java.util.*;
  27. import org.gjt.sp.util.Log;
  28. /**
  29. * A generic way for plugins to provide various API extensions.<p>
  30. *
  31. * Services are loaded from files named <code>services.xml</code> inside the
  32. * plugin JAR. A service definition file has the following form:
  33. *
  34. * <pre>&lt;?xml version="1.0"?&gt;
  35. *&lt;!DOCTYPE SERVICES SYSTEM "services.dtd"&gt;
  36. *&lt;SERVICES&gt;
  37. * &lt;SERVICE NAME="service name" CLASS="fully qualified class name"&gt;
  38. * // BeanShell code evaluated when the sevice is first activated
  39. * &lt;/SERVICE&gt;
  40. *&lt;/SERVICES&gt;</pre>
  41. *
  42. * The following elements are valid:
  43. *
  44. * <ul>
  45. * <li>
  46. * <code>SERVICES</code> is the top-level element and refers
  47. * to the set of services offered by the plugin.
  48. * </li>
  49. * <li>
  50. * A <code>SERVICE</code> contains the data for a particular service
  51. * activation.
  52. * It has two attributes, both required: <code>NAME</code> and
  53. * <code>CLASS</code>. The <code>CLASS</code> attribute must be the name of
  54. * a known sevice type; see below.
  55. * </li>
  56. * <li>
  57. * A <code>SERVICE</code> element should the BeanShell code that returns a
  58. * new instance of the named class. Note that this code can return
  59. * <code>null</code>.
  60. * </li>
  61. * </ul>
  62. *
  63. * The jEdit core defines the following service types:
  64. * <ul>
  65. * <li>{@link org.gjt.sp.jedit.buffer.FoldHandler}</li>
  66. * <li>{@link org.gjt.sp.jedit.io.VFS}</li>
  67. * </ul>
  68. *
  69. * Plugins may provide more.<p>
  70. *
  71. * To have your plugin accept services, no extra steps are needed other than
  72. * a piece of code somewhere that calls {@link #getServiceNames(String)} and
  73. * {@link #getService(String,String)}.
  74. *
  75. * @see BeanShell
  76. * @see PluginJAR
  77. *
  78. * @since jEdit 4.2pre1
  79. * @author Slava Pestov
  80. * @version $Id: ServiceManager.java 4696 2003-05-10 00:43:19Z spestov $
  81. */
  82. public class ServiceManager
  83. {
  84. //{{{ loadServices() method
  85. /**
  86. * Loads a <code>services.xml</code> file.
  87. * @since jEdit 4.2pre1
  88. */
  89. public static void loadServices(PluginJAR plugin, URL uri,
  90. PluginJAR.PluginCacheEntry cache)
  91. {
  92. Reader in = null;
  93. try
  94. {
  95. Log.log(Log.DEBUG,jEdit.class,"Loading services from " + uri);
  96. ServiceListHandler dh = new ServiceListHandler(plugin,uri);
  97. XmlParser parser = new XmlParser();
  98. parser.setHandler(dh);
  99. in = new BufferedReader(
  100. new InputStreamReader(
  101. uri.openStream()));
  102. parser.parse(null, null, in);
  103. if(cache != null)
  104. cache.cachedServices = dh.getCachedServices();
  105. }
  106. catch(XmlException xe)
  107. {
  108. int line = xe.getLine();
  109. String message = xe.getMessage();
  110. Log.log(Log.ERROR,ServiceManager.class,uri + ":" + line
  111. + ": " + message);
  112. }
  113. catch(Exception e)
  114. {
  115. Log.log(Log.ERROR,ServiceManager.class,e);
  116. }
  117. finally
  118. {
  119. try
  120. {
  121. if(in != null)
  122. in.close();
  123. }
  124. catch(IOException io)
  125. {
  126. Log.log(Log.ERROR,ServiceManager.class,io);
  127. }
  128. }
  129. } //}}}
  130. //{{{ unloadServices() method
  131. /**
  132. * Removes all services belonging to the specified plugin.
  133. * @param plugin The plugin
  134. * @since jEdit 4.2pre1
  135. */
  136. public static void unloadServices(PluginJAR plugin)
  137. {
  138. Iterator descriptors = serviceMap.keySet().iterator();
  139. while(descriptors.hasNext())
  140. {
  141. Descriptor d = (Descriptor)descriptors.next();
  142. if(d.plugin == plugin)
  143. descriptors.remove();
  144. }
  145. } //}}}
  146. //{{{ registerService() method
  147. /**
  148. * Registers a service. Plugins should provide a
  149. * <code>services.xml</code> file instead of calling this directly.
  150. *
  151. * @param clazz The service class
  152. * @param name The service name
  153. * @param code BeanShell code to create an instance of this
  154. * @param plugin The plugin JAR, or null if this is a built-in service
  155. *
  156. * @since jEdit 4.2pre1
  157. */
  158. public static void registerService(String clazz, String name,
  159. String code, PluginJAR plugin)
  160. {
  161. Descriptor d = new Descriptor(clazz,name,code,plugin);
  162. serviceMap.put(d,d);
  163. } //}}}
  164. //{{{ unregisterService() method
  165. /**
  166. * Unregisters a service.
  167. *
  168. * @param clazz The service class
  169. * @param name The service name
  170. * @param code BeanShell code to create an instance of this
  171. *
  172. * @since jEdit 4.2pre1
  173. */
  174. public static void unregisterService(String clazz, String name)
  175. {
  176. Descriptor d = new Descriptor(clazz,name);
  177. serviceMap.remove(d);
  178. } //}}}
  179. //{{{ getServiceTypes() method
  180. /**
  181. * Returns all known service class types.
  182. *
  183. * @since jEdit 4.2pre1
  184. */
  185. public static String[] getServiceTypes()
  186. {
  187. HashSet returnValue = new HashSet();
  188. Iterator descriptors = serviceMap.keySet().iterator();
  189. while(descriptors.hasNext())
  190. {
  191. Descriptor d = (Descriptor)descriptors.next();
  192. returnValue.add(d.clazz);
  193. }
  194. return (String[])returnValue.toArray(
  195. new String[returnValue.size()]);
  196. } //}}}
  197. //{{{ getServiceNames() method
  198. /**
  199. * Returns the names of all registered services with the given
  200. * class. For example, calling this with a parameter of
  201. * "org.gjt.sp.jedit.io.VFS" returns all known virtual file
  202. * systems.
  203. *
  204. * @param clazz The class name
  205. * @since jEdit 4.2pre1
  206. */
  207. public static String[] getServiceNames(String clazz)
  208. {
  209. ArrayList returnValue = new ArrayList();
  210. Iterator descriptors = serviceMap.keySet().iterator();
  211. while(descriptors.hasNext())
  212. {
  213. Descriptor d = (Descriptor)descriptors.next();
  214. if(d.clazz.equals(clazz))
  215. returnValue.add(d.name);
  216. }
  217. return (String[])returnValue.toArray(
  218. new String[returnValue.size()]);
  219. } //}}}
  220. //{{{ getService() method
  221. /**
  222. * Returns an instance of the given service. The first time this is
  223. * called for a given service, the BeanShell code is evaluated. The
  224. * result is cached for future invocations, so in effect services are
  225. * singletons.
  226. *
  227. * @param clazz The service class
  228. * @param name The service name
  229. * @since jEdit 4.2pre1
  230. */
  231. public static Object getService(String clazz, String name)
  232. {
  233. // they never taught you this in undergrad computer science
  234. Descriptor key = new Descriptor(clazz,name);
  235. Descriptor value = (Descriptor)serviceMap.get(key);
  236. if(value == null)
  237. {
  238. // unknown service - <clazz,name> not in table
  239. return null;
  240. }
  241. else
  242. {
  243. if(value.code == null)
  244. {
  245. loadServices(value.plugin,
  246. value.plugin.getServicesURI(),
  247. null);
  248. value = (Descriptor)serviceMap.get(key);
  249. }
  250. return value.getInstance();
  251. }
  252. } //}}}
  253. //{{{ Package-private members
  254. //{{{ registerService() method
  255. /**
  256. * Registers a service.
  257. *
  258. * @since jEdit 4.2pre1
  259. */
  260. static void registerService(Descriptor d)
  261. {
  262. serviceMap.put(d,d);
  263. } //}}}
  264. //}}}
  265. //{{{ Private members
  266. private static Map serviceMap = new HashMap();
  267. //}}}
  268. //{{{ Descriptor class
  269. static class Descriptor
  270. {
  271. String clazz;
  272. String name;
  273. String code;
  274. PluginJAR plugin;
  275. Object instance;
  276. boolean instanceIsNull;
  277. // this constructor keys the hash table
  278. Descriptor(String clazz, String name)
  279. {
  280. this.clazz = clazz;
  281. this.name = name;
  282. }
  283. // this constructor is the value of the hash table
  284. Descriptor(String clazz, String name, String code,
  285. PluginJAR plugin)
  286. {
  287. this.clazz = clazz;
  288. this.name = name;
  289. this.code = code;
  290. this.plugin = plugin;
  291. }
  292. Object getInstance()
  293. {
  294. if(instanceIsNull)
  295. return null;
  296. else if(instance == null)
  297. {
  298. // lazy instantiation
  299. instance = BeanShell.eval(null,
  300. BeanShell.getNameSpace(),
  301. code);
  302. if(instance == null)
  303. {
  304. // avoid re-running script if it gives
  305. // us null
  306. instanceIsNull = true;
  307. }
  308. }
  309. return instance;
  310. }
  311. public int hashCode()
  312. {
  313. return name.hashCode();
  314. }
  315. public boolean equals(Object o)
  316. {
  317. if(o instanceof Descriptor)
  318. {
  319. Descriptor d = (Descriptor)o;
  320. return d.clazz.equals(clazz)
  321. && d.name.equals(name);
  322. }
  323. else
  324. return false;
  325. }
  326. } //}}}
  327. }