KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > ServiceManager


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
23 package org.gjt.sp.jedit;
24
25 import java.io.*;
26 import java.net.URL JavaDoc;
27 import java.util.*;
28 import org.gjt.sp.util.Log;
29 import org.gjt.sp.util.XMLUtilities;
30
31 /**
32  * A generic way for plugins to provide various API extensions.<p>
33  *
34  * Services are loaded from files named <code>services.xml</code> inside the
35  * plugin JAR. A service definition file has the following form:
36  *
37  * <pre>&lt;?xml version="1.0"?&gt;
38  *&lt;!DOCTYPE SERVICES SYSTEM "services.dtd"&gt;
39  *&lt;SERVICES&gt;
40  * &lt;SERVICE NAME="service name" CLASS="fully qualified class name"&gt;
41  * // BeanShell code evaluated when the sevice is first activated
42  * &lt;/SERVICE&gt;
43  *&lt;/SERVICES&gt;</pre>
44  *
45  * The following elements are valid:
46  *
47  * <ul>
48  * <li>
49  * <code>SERVICES</code> is the top-level element and refers
50  * to the set of services offered by the plugin.
51  * </li>
52  * <li>
53  * A <code>SERVICE</code> contains the data for a particular service
54  * activation.
55  * It has two attributes, both required: <code>NAME</code> and
56  * <code>CLASS</code>. The <code>CLASS</code> attribute must be the name of
57  * a known sevice type; see below.
58  * </li>
59  * <li>
60  * A <code>SERVICE</code> element should the BeanShell code that returns a
61  * new instance of the named class. Note that this code can return
62  * <code>null</code>.
63  * </li>
64  * </ul>
65  *
66  * The jEdit core defines the following service types:
67  * <ul>
68  * <li>{@link org.gjt.sp.jedit.buffer.FoldHandler}</li>
69  * <li>{@link org.gjt.sp.jedit.io.VFS}</li>
70  * </ul>
71  *
72  * Plugins may provide more.<p>
73  *
74  * To have your plugin accept services, no extra steps are needed other than
75  * a piece of code somewhere that calls {@link #getServiceNames(String)} and
76  * {@link #getService(String,String)}.
77  *
78  * @see BeanShell
79  * @see PluginJAR
80  *
81  * @since jEdit 4.2pre1
82  * @author Slava Pestov
83  * @version $Id: ServiceManager.java 6505 2006-08-03 09:35:44Z kpouer $
84  */

85 public class ServiceManager
86 {
87     //{{{ loadServices() method
88
/**
89      * Loads a <code>services.xml</code> file.
90      * @since jEdit 4.2pre1
91      */

92     public static void loadServices(PluginJAR plugin, URL JavaDoc uri,
93         PluginJAR.PluginCacheEntry cache)
94     {
95         ServiceListHandler dh = new ServiceListHandler(plugin,uri);
96         try
97         {
98             if (!XMLUtilities.parseXML(uri.openStream(), dh)
99                 && cache != null)
100             {
101                 cache.cachedServices = dh.getCachedServices();
102             }
103         }
104         catch (IOException ioe)
105         {
106             Log.log(Log.ERROR, ServiceManager.class, ioe);
107         }
108     } //}}}
109

110     //{{{ unloadServices() method
111
/**
112      * Removes all services belonging to the specified plugin.
113      * @param plugin The plugin
114      * @since jEdit 4.2pre1
115      */

116     public static void unloadServices(PluginJAR plugin)
117     {
118         Iterator<Descriptor> descriptors = serviceMap.keySet().iterator();
119         while(descriptors.hasNext())
120         {
121             Descriptor d = descriptors.next();
122             if(d.plugin == plugin)
123                 descriptors.remove();
124         }
125     } //}}}
126

127     //{{{ registerService() method
128
/**
129      * Registers a service. Plugins should provide a
130      * <code>services.xml</code> file instead of calling this directly.
131      *
132      * @param clazz The service class
133      * @param name The service name
134      * @param code BeanShell code to create an instance of this
135      * @param plugin The plugin JAR, or null if this is a built-in service
136      *
137      * @since jEdit 4.2pre1
138      */

139     public static void registerService(String JavaDoc clazz, String JavaDoc name,
140         String JavaDoc code, PluginJAR plugin)
141     {
142         Descriptor d = new Descriptor(clazz,name,code,plugin);
143         serviceMap.put(d,d);
144     } //}}}
145

146     //{{{ unregisterService() method
147
/**
148      * Unregisters a service.
149      *
150      * @param clazz The service class
151      * @param name The service name
152      *
153      * @since jEdit 4.2pre1
154      */

155     public static void unregisterService(String JavaDoc clazz, String JavaDoc name)
156     {
157         Descriptor d = new Descriptor(clazz,name);
158         serviceMap.remove(d);
159     } //}}}
160

161     //{{{ getServiceTypes() method
162
/**
163      * Returns all known service class types.
164      *
165      * @since jEdit 4.2pre1
166      */

167     public static String JavaDoc[] getServiceTypes()
168     {
169         Set<String JavaDoc> returnValue = new HashSet<String JavaDoc>();
170
171         Set<Descriptor> keySet = serviceMap.keySet();
172         for (Descriptor d : keySet)
173             returnValue.add(d.clazz);
174
175         return returnValue.toArray(
176             new String JavaDoc[returnValue.size()]);
177     } //}}}
178

179     //{{{ getServiceNames() method
180
/**
181      * Returns the names of all registered services with the given
182      * class. For example, calling this with a parameter of
183      * "org.gjt.sp.jedit.io.VFS" returns all known virtual file
184      * systems.
185      *
186      * @param clazz The class name
187      * @since jEdit 4.2pre1
188      */

189     public static String JavaDoc[] getServiceNames(String JavaDoc clazz)
190     {
191         List<String JavaDoc> returnValue = new ArrayList<String JavaDoc>();
192
193         Set<Descriptor> keySet = serviceMap.keySet();
194         for (Descriptor d : keySet)
195             if(d.clazz.equals(clazz))
196                 returnValue.add(d.name);
197
198
199         return returnValue.toArray(
200             new String JavaDoc[returnValue.size()]);
201     } //}}}
202

203     //{{{ getService() method
204
/**
205      * Returns an instance of the given service. The first time this is
206      * called for a given service, the BeanShell code is evaluated. The
207      * result is cached for future invocations, so in effect services are
208      * singletons.
209      *
210      * @param clazz The service class
211      * @param name The service name
212      * @since jEdit 4.2pre1
213      */

214     public static Object JavaDoc getService(String JavaDoc clazz, String JavaDoc name)
215     {
216         // they never taught you this in undergrad computer science
217
Descriptor key = new Descriptor(clazz,name);
218         Descriptor value = serviceMap.get(key);
219         if(value == null)
220         {
221             // unknown service - <clazz,name> not in table
222
return null;
223         }
224         else
225         {
226             if(value.code == null)
227             {
228                 loadServices(value.plugin,
229                     value.plugin.getServicesURI(),
230                     null);
231                 value = serviceMap.get(key);
232             }
233             return value.getInstance();
234         }
235     } //}}}
236

237     //{{{ Package-private members
238

239     //{{{ registerService() method
240
/**
241      * Registers a service.
242      *
243      * @since jEdit 4.2pre1
244      */

245     static void registerService(Descriptor d)
246     {
247         serviceMap.put(d,d);
248     } //}}}
249

250     //}}}
251

252     //{{{ Private members
253
private static final Map<Descriptor, Descriptor> serviceMap = new HashMap<Descriptor, Descriptor>();
254     //}}}
255

256     //{{{ Descriptor class
257
static class Descriptor
258     {
259         final String JavaDoc clazz;
260         final String JavaDoc name;
261         String JavaDoc code;
262         PluginJAR plugin;
263         Object JavaDoc instance;
264         boolean instanceIsNull;
265
266         // this constructor keys the hash table
267
Descriptor(String JavaDoc clazz, String JavaDoc name)
268         {
269             this.clazz = clazz;
270             this.name = name;
271         }
272
273         // this constructor is the value of the hash table
274
Descriptor(String JavaDoc clazz, String JavaDoc name, String JavaDoc code,
275             PluginJAR plugin)
276         {
277             this.clazz = clazz;
278             this.name = name;
279             this.code = code;
280             this.plugin = plugin;
281         }
282
283         Object JavaDoc getInstance()
284         {
285             if(instanceIsNull)
286                 return null;
287             else if(instance == null)
288             {
289                 // lazy instantiation
290
instance = BeanShell.eval(null,
291                     BeanShell.getNameSpace(),
292                     code);
293                 if(instance == null)
294                 {
295                     // avoid re-running script if it gives
296
// us null
297
instanceIsNull = true;
298                 }
299             }
300
301             return instance;
302         }
303         public int hashCode()
304         {
305             return name.hashCode();
306         }
307
308         public boolean equals(Object JavaDoc o)
309         {
310             if(o instanceof Descriptor)
311             {
312                 Descriptor d = (Descriptor)o;
313                 return d.clazz.equals(clazz)
314                     && d.name.equals(name);
315             }
316             else
317                 return false;
318         }
319     } //}}}
320
}
321
Popular Tags