KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > imageio > spi > ServiceRegistry


1 /*
2  * @(#)ServiceRegistry.java 1.22 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.imageio.spi;
9
10 import java.io.File JavaDoc;
11 import java.util.ArrayList JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Map JavaDoc;
16 import java.util.NoSuchElementException JavaDoc;
17 import java.util.Set JavaDoc;
18 import sun.misc.Service;
19
20 /**
21  * A registry for service provider instances.
22  *
23  * <p> A <i>service</i> is a well-known set of interfaces and (usually
24  * abstract) classes. A <i>service provider</i> is a specific
25  * implementation of a service. The classes in a provider typically
26  * implement the interface or subclass the class defined by the
27  * service itself.
28  *
29  * <p> Service providers are stored in one or more <i>categories</i>,
30  * each of which is defined by a class of interface (described by a
31  * <code>Class</code> object) that all of its members must implement.
32  * The set of categories may be changed dynamically.
33  *
34  * <p> Only a single instance of a given leaf class (that is, the
35  * actual class returned by <code>getClass()</code>, as opposed to any
36  * inherited classes or interfaces) may be registered. That is,
37  * suppose that the
38  * <code>com.mycompany.mypkg.GreenServiceProvider</code> class
39  * implements the <code>com.mycompany.mypkg.MyService</code>
40  * interface. If a <code>GreenServiceProvider</code> instance is
41  * registered, it will be stored in the category defined by the
42  * <code>MyService</code> class. If a new instance of
43  * <code>GreenServiceProvider</code> is registered, it will replace
44  * the previous instance. In practice, service provider objects are
45  * usually singletons so this behavior is appropriate.
46  *
47  * <p> To declare a service provider, a <code>services</code>
48  * subdirectory is placed within the <code>META-INF</code> directory
49  * that is present in every JAR file. This directory contains a file
50  * for each service provider interface that has one or more
51  * implementation classes present in the JAR file. For example, if
52  * the JAR file contained a class named
53  * <code>com.mycompany.mypkg.MyServiceImpl</code> which implements the
54  * <code>javax.someapi.SomeService</code> interface, the JAR file
55  * would contain a file named: <pre>
56  * META-INF/services/javax.someapi.SomeService </pre>
57  *
58  * containing the line:
59  *
60  * <pre>
61  * com.mycompany.mypkg.MyService
62  * </pre>
63  *
64  * <p> The service provider classes should be to be lightweight and
65  * quick to load. Implementations of these interfaces should avoid
66  * complex dependencies on other classes and on native code. The usual
67  * pattern for more complex services is to register a lightweight
68  * proxy for the heavyweight service.
69  *
70  * <p> An application may customize the contents of a registry as it
71  * sees fit, so long as it has the appropriate runtime permission.
72  *
73  * <p> For more details on declaring service providers, and the JAR
74  * format in general, see the <a
75  * HREF="http://java.sun.com/products/jdk/1.3/docs/guide/jar/jar.html">
76  * JAR File Specification</a>.
77  *
78  * @see RegisterableService
79  *
80  * @version 0.5
81  */

82 public class ServiceRegistry {
83
84     // Class -> Registry
85
private Map JavaDoc categoryMap = new HashMap JavaDoc();
86
87     /**
88      * Constructs a <code>ServiceRegistry</code> instance with a
89      * set of categories taken from the <code>categories</code>
90      * argument.
91      *
92      * @param categories an <code>Iterator</code> containing
93      * <code>Class</code> objects to be used to define categories.
94      *
95      * @exception IllegalArgumentException if
96      * <code>categories</code> is <code>null</code>.
97      */

98     public ServiceRegistry(Iterator JavaDoc<Class JavaDoc<?>> categories) {
99         if (categories == null) {
100             throw new IllegalArgumentException JavaDoc("categories == null!");
101         }
102         while (categories.hasNext()) {
103             Class JavaDoc category = (Class JavaDoc)categories.next();
104             SubRegistry reg = new SubRegistry(this, category);
105             categoryMap.put(category, reg);
106         }
107     }
108
109     // The following two methods expose functionality from
110
// sun.misc.Service. If that class is made public, they may be
111
// removed.
112
//
113
// The sun.misc.ServiceConfigurationError class may also be
114
// exposed, in which case the references to 'an
115
// <code>Error</code>' below should be changed to 'a
116
// <code>ServiceConfigurationError</code>'.
117

118     /**
119      * Searches for implementations of a particular service class
120      * using the given class loader.
121      *
122      * <p> This method transforms the name of the given service class
123      * into a provider-configuration filename as described in the
124      * class comment and then uses the <code>getResources</code>
125      * method of the given class loader to find all available files
126      * with that name. These files are then read and parsed to
127      * produce a list of provider-class names. The iterator that is
128      * returned uses the given class loader to look up and then
129      * instantiate each element of the list.
130      *
131      * <p> Because it is possible for extensions to be installed into
132      * a running Java virtual machine, this method may return
133      * different results each time it is invoked.
134      *
135      * @param providerClass a <code>Class</code>object indicating the
136      * class or interface of the service providers being detected.
137      *
138      * @param loader the class loader to be used to load
139      * provider-configuration files and instantiate provider classes,
140      * or <code>null</code> if the system class loader (or, failing that
141      * the bootstrap class loader) is to be used.
142      *
143      * @return An <code>Iterator</code> that yields provider objects
144      * for the given service, in some arbitrary order. The iterator
145      * will throw an <code>Error</code> if a provider-configuration
146      * file violates the specified format or if a provider class
147      * cannot be found and instantiated.
148      *
149      * @exception IllegalArgumentException if
150      * <code>providerClass</code> is <code>null</code>.
151      */

152     public static <T> Iterator JavaDoc<T> lookupProviders(Class JavaDoc<T> providerClass,
153                           ClassLoader JavaDoc loader)
154     {
155         if (providerClass == null) {
156             throw new IllegalArgumentException JavaDoc("providerClass == null!");
157         }
158     return Service.providers(providerClass, loader);
159     }
160
161     /**
162      * Locates and incrementally instantiates the available providers
163      * of a given service using the context class loader. This
164      * convenience method is equivalent to:
165      *
166      * <pre>
167      * ClassLoader cl = Thread.currentThread().getContextClassLoader();
168      * return Service.providers(service, cl);
169      * </pre>
170      *
171      * @param providerClass a <code>Class</code>object indicating the
172      * class or interface of the service providers being detected.
173      *
174      * @return An <code>Iterator</code> that yields provider objects
175      * for the given service, in some arbitrary order. The iterator
176      * will throw an <code>Error</code> if a provider-configuration
177      * file violates the specified format or if a provider class
178      * cannot be found and instantiated.
179      *
180      * @exception IllegalArgumentException if
181      * <code>providerClass</code> is <code>null</code>.
182      */

183     public static <T> Iterator JavaDoc<T> lookupProviders(Class JavaDoc<T> providerClass) {
184         if (providerClass == null) {
185             throw new IllegalArgumentException JavaDoc("providerClass == null!");
186         }
187     return Service.providers(providerClass);
188     }
189
190     /**
191      * Returns an <code>Iterator</code> of <code>Class</code> objects
192      * indicating the current set of categories. The iterator will be
193      * empty if no categories exist.
194      *
195      * @return an <code>Iterator</code> containing
196      * <code>Class</code>objects.
197      */

198     public Iterator JavaDoc<Class JavaDoc<?>> getCategories() {
199         Set JavaDoc keySet = categoryMap.keySet();
200         return keySet.iterator();
201     }
202
203     /**
204      * Returns an Iterator containing the subregistries to which the
205      * provider belongs.
206      */

207     private Iterator JavaDoc getSubRegistries(Object JavaDoc provider) {
208         List JavaDoc l = new ArrayList JavaDoc();
209         Iterator JavaDoc iter = categoryMap.keySet().iterator();
210         while (iter.hasNext()) {
211             Class JavaDoc c = (Class JavaDoc)iter.next();
212             if (c.isAssignableFrom(provider.getClass())) {
213                 l.add((SubRegistry)categoryMap.get(c));
214             }
215         }
216         return l.iterator();
217     }
218
219     /**
220      * Adds a service provider object to the registry. The provider
221      * is associated with the given category.
222      *
223      * <p> If <code>provider</code> implements the
224      * <code>RegisterableService</code> interface, its
225      * <code>onRegistration</code> method will be called. Its
226      * <code>onDeregistration</code> method will be called each time
227      * it is deregistered from a category, for example if a
228      * category is removed or the registry is garbage collected.
229      *
230      * @param provider the service provide object to be registered.
231      * @param category the category under which to register the
232      * provider.
233      *
234      * @return true if no provider of the same class was previously
235      * registered in the same category category.
236      *
237      * @exception IllegalArgumentException if <code>provider</code> is
238      * <code>null</code>.
239      * @exception IllegalArgumentException if there is no category
240      * corresponding to <code>category</code>.
241      * @exception ClassCastException if provider does not implement
242      * the <code>Class</code> defined by <code>category</code>.
243      */

244     public <T> boolean registerServiceProvider(T provider,
245                            Class JavaDoc<T> category) {
246         if (provider == null) {
247             throw new IllegalArgumentException JavaDoc("provider == null!");
248         }
249         SubRegistry reg = (SubRegistry)categoryMap.get(category);
250         if (reg == null) {
251             throw new IllegalArgumentException JavaDoc("category unknown!");
252         }
253         if (!category.isAssignableFrom(provider.getClass())) {
254             throw new ClassCastException JavaDoc();
255         }
256         
257         return reg.registerServiceProvider(provider);
258     }
259
260     /**
261      * Adds a service provider object to the registry. The provider
262      * is associated within each category present in the registry
263      * whose <code>Class</code> it implements.
264      *
265      * <p> If <code>provider</code> implements the
266      * <code>RegisterableService</code> interface, its
267      * <code>onRegistration</code> method will be called once for each
268      * category it is registered under. Its
269      * <code>onDeregistration</code> method will be called each time
270      * it is deregistered from a category or when the registry is
271      * finalized.
272      *
273      * @param provider the service provider object to be registered.
274      *
275      * @exception IllegalArgumentException if
276      * <code>provider</code> is <code>null</code>.
277      */

278     public void registerServiceProvider(Object JavaDoc provider) {
279         if (provider == null) {
280             throw new IllegalArgumentException JavaDoc("provider == null!");
281         }
282         Iterator JavaDoc regs = getSubRegistries(provider);
283         while (regs.hasNext()) {
284             SubRegistry reg = (SubRegistry)regs.next();
285             reg.registerServiceProvider(provider);
286         }
287     }
288
289     /**
290      * Adds a set of service provider objects, taken from an
291      * <code>Iterator</code> to the registry. Each provider is
292      * associated within each category present in the registry whose
293      * <code>Class</code> it implements.
294      *
295      * <p> For each entry of <code>providers</code> that implements
296      * the <code>RegisterableService</code> interface, its
297      * <code>onRegistration</code> method will be called once for each
298      * category it is registered under. Its
299      * <code>onDeregistration</code> method will be called each time
300      * it is deregistered from a category or when the registry is
301      * finalized.
302      *
303      * @param providers an Iterator containing service provider
304      * objects to be registered.
305      *
306      * @exception IllegalArgumentException if <code>providers</code>
307      * is <code>null</code> or contains a <code>null</code> entry.
308      */

309     public void registerServiceProviders(Iterator JavaDoc<?> providers) {
310         if (providers == null) {
311             throw new IllegalArgumentException JavaDoc("provider == null!");
312         }
313         while (providers.hasNext()) {
314             registerServiceProvider(providers.next());
315         }
316     }
317
318     /**
319      * Removes a service provider object from the given category. If
320      * the provider was not previously registered, nothing happens and
321      * <code>false</code> is returned. Otherwise, <code>true</code>
322      * is returned. If an object of the same class as
323      * <code>provider</code> but not equal (using <code>==</code>) to
324      * <code>provider</code> is registered, it will not be
325      * deregistered.
326      *
327      * <p> If <code>provider</code> implements the
328      * <code>RegisterableService</code> interface, its
329      * <code>onDeregistration</code> method will be called.
330      *
331      * @param provider the service provider object to be deregistered.
332      * @param category the category from which to deregister the
333      * provider.
334      *
335      * @return <code>true</code> if the provider was previously
336      * registered in the same category category,
337      * <code>false</code> otherwise.
338      *
339      * @exception IllegalArgumentException if <code>provider</code> is
340      * <code>null</code>.
341      * @exception IllegalArgumentException if there is no category
342      * corresponding to <code>category</code>.
343      * @exception ClassCastException if provider does not implement
344      * the class defined by <code>category</code>.
345      */

346     public <T> boolean deregisterServiceProvider(T provider,
347                          Class JavaDoc<T> category) {
348         if (provider == null) {
349             throw new IllegalArgumentException JavaDoc("provider == null!");
350         }
351         SubRegistry reg = (SubRegistry)categoryMap.get(category);
352         if (reg == null) {
353             throw new IllegalArgumentException JavaDoc("category unknown!");
354         }
355         if (!category.isAssignableFrom(provider.getClass())) {
356             throw new ClassCastException JavaDoc();
357         }
358         return reg.deregisterServiceProvider(provider);
359     }
360
361     /**
362      * Removes a service provider object from all categories that
363      * contain it.
364      *
365      * @param provider the service provider object to be deregistered.
366      *
367      * @exception IllegalArgumentException if <code>provider</code> is
368      * <code>null</code>.
369      */

370     public void deregisterServiceProvider(Object JavaDoc provider) {
371         if (provider == null) {
372             throw new IllegalArgumentException JavaDoc("provider == null!");
373         }
374         Iterator JavaDoc regs = getSubRegistries(provider);
375         while (regs.hasNext()) {
376             SubRegistry reg = (SubRegistry)regs.next();
377             reg.deregisterServiceProvider(provider);
378         }
379     }
380
381     /**
382      * Returns <code>true</code> if <code>provider</code> is currently
383      * registered.
384      *
385      * @param provider the service provider object to be queried.
386      *
387      * @return <code>true</code> if the given provider has been
388      * registered.
389      *
390      * @exception IllegalArgumentException if <code>provider</code> is
391      * <code>null</code>.
392      */

393     public boolean contains(Object JavaDoc provider) {
394         if (provider == null) {
395             throw new IllegalArgumentException JavaDoc("provider == null!");
396         }
397         Iterator JavaDoc regs = getSubRegistries(provider);
398         while (regs.hasNext()) {
399             SubRegistry reg = (SubRegistry)regs.next();
400             if (reg.contains(provider)) {
401                 return true;
402             }
403         }
404
405         return false;
406     }
407
408     /**
409      * Returns an <code>Iterator</code> containing all registered
410      * service providers in the given category. If
411      * <code>useOrdering</code> is <code>false</code>, the iterator
412      * will return all of the server provider objects in an arbitrary
413      * order. Otherwise, the ordering will respect any pairwise
414      * orderings that have been set. If the graph of pairwise
415      * orderings contains cycles, any providers that belong to a cycle
416      * will not be returned.
417      *
418      * @param category the category to be retrieved from.
419      * @param useOrdering <code>true</code> if pairwise orderings
420      * should be taken account in ordering the returned objects.
421      *
422      * @return an <code>Iterator</code> containing service provider
423      * objects from the given category, possibly in order.
424      *
425      * @exception IllegalArgumentException if there is no category
426      * corresponding to <code>category</code>.
427      */

428     public <T> Iterator JavaDoc<T> getServiceProviders(Class JavaDoc<T> category,
429                            boolean useOrdering) {
430         SubRegistry reg = (SubRegistry)categoryMap.get(category);
431         if (reg == null) {
432             throw new IllegalArgumentException JavaDoc("category unknown!");
433         }
434         return reg.getServiceProviders(useOrdering);
435     }
436
437     /**
438      * A simple filter interface used by
439      * <code>ServiceRegistry.getServiceProviders</code> to select
440      * providers matching an arbitrary criterion. Classes that
441      * implement this interface should be defined in order to make use
442      * of the <code>getServiceProviders</code> method of
443      * <code>ServiceRegistry</code> that takes a <code>Filter</code>.
444      *
445      * @see ServiceRegistry#getServiceProviders(Class, ServiceRegistry.Filter, boolean)
446      */

447     public interface Filter {
448
449         /**
450          * Returns <code>true</code> if the given
451          * <code>provider</code> object matches the criterion defined
452          * by this <code>Filter</code>.
453          *
454          * @param provider a service provider <code>Object</code>.
455          *
456          * @return true if the provider matches the criterion.
457          */

458         boolean filter(Object JavaDoc provider);
459     }
460
461     /**
462      * Returns an <code>Iterator</code> containing service provider
463      * objects within a given category that satisfy a criterion
464      * imposed by the supplied <code>ServiceRegistry.Filter</code>
465      * object's <code>filter</code> method.
466      *
467      * <p> The <code>useOrdering</code> argument controls the
468      * ordering of the results using the same rules as
469      * <code>getServiceProviders(Class, boolean)</code>.
470      *
471      * @param category the category to be retrieved from.
472      * @param filter an instance of <code>ServiceRegistry.Filter</code>
473      * whose <code>filter</code> method will be invoked.
474      * @param useOrdering <code>true</code> if pairwise orderings
475      * should be taken account in ordering the returned objects.
476      *
477      * @return an <code>Iterator</code> containing service provider
478      * objects from the given category, possibly in order.
479      *
480      * @exception IllegalArgumentException if there is no category
481      * corresponding to <code>category</code>.
482      */

483     public <T> Iterator JavaDoc<T> getServiceProviders(Class JavaDoc<T> category,
484                            Filter filter,
485                            boolean useOrdering) {
486         SubRegistry reg = (SubRegistry)categoryMap.get(category);
487         if (reg == null) {
488             throw new IllegalArgumentException JavaDoc("category unknown!");
489         }
490         Iterator JavaDoc iter = getServiceProviders(category, useOrdering);
491         return new FilterIterator(iter, filter);
492     }
493
494     /**
495      * Returns the currently registered service provider object that
496      * is of the given class type. At most one object of a given
497      * class is allowed to be registered at any given time. If no
498      * registered object has the desired class type, <code>null</code>
499      * is returned.
500      *
501      * @param providerClass the <code>Class</code> of the desired
502      * service provider object.
503      *
504      * @return a currently registered service provider object with the
505      * desired <code>Class</code>type, or <code>null</code> is none is
506      * present.
507      *
508      * @exception IllegalArgumentException if <code>providerClass</code> is
509      * <code>null</code>.
510      */

511     public <T> T getServiceProviderByClass(Class JavaDoc<T> providerClass) {
512         if (providerClass == null) {
513             throw new IllegalArgumentException JavaDoc("providerClass == null!");
514         }
515         Iterator JavaDoc iter = categoryMap.keySet().iterator();
516         while (iter.hasNext()) {
517             Class JavaDoc c = (Class JavaDoc)iter.next();
518             if (c.isAssignableFrom(providerClass)) {
519                 SubRegistry reg = (SubRegistry)categoryMap.get(c);
520                 T provider = reg.getServiceProviderByClass(providerClass);
521                 if (provider != null) {
522                     return provider;
523                 }
524             }
525         }
526         return null;
527     }
528
529     /**
530      * Sets a pairwise ordering between two service provider objects
531      * within a given category. If one or both objects are not
532      * currently registered within the given category, or if the
533      * desired ordering is already set, nothing happens and
534      * <code>false</code> is returned. If the providers previously
535      * were ordered in the reverse direction, that ordering is
536      * removed.
537      *
538      * <p> The ordering will be used by the
539      * <code>getServiceProviders</code> methods when their
540      * <code>useOrdering</code> argument is <code>true</code>.
541      *
542      * @param category a <code>Class</code> object indicating the
543      * category under which the preference is to be established.
544      * @param firstProvider the preferred provider.
545      * @param secondProvider the provider to which
546      * <code>firstProvider</code> is preferred.
547      *
548      * @return <code>true</code> if a previously unset ordering
549      * was established.
550      *
551      * @exception IllegalArgumentException if either provider is
552      * <code>null</code> or they are the same object.
553      * @exception IllegalArgumentException if there is no category
554      * corresponding to <code>category</code>.
555      */

556     public <T> boolean setOrdering(Class JavaDoc<T> category,
557                    T firstProvider,
558                    T secondProvider) {
559         if (firstProvider == null || secondProvider == null) {
560             throw new IllegalArgumentException JavaDoc("provider is null!");
561         }
562         if (firstProvider == secondProvider) {
563             throw new IllegalArgumentException JavaDoc("providers are the same!");
564         }
565         SubRegistry reg = (SubRegistry)categoryMap.get(category);
566         if (reg == null) {
567             throw new IllegalArgumentException JavaDoc("category unknown!");
568         }
569         if (reg.contains(firstProvider) &&
570             reg.contains(secondProvider)) {
571             return reg.setOrdering(firstProvider, secondProvider);
572         }
573         return false;
574     }
575
576     /**
577      * Sets a pairwise ordering between two service provider objects
578      * within a given category. If one or both objects are not
579      * currently registered within the given category, or if no
580      * ordering is currently set between them, nothing happens
581      * and <code>false</code> is returned.
582      *
583      * <p> The ordering will be used by the
584      * <code>getServiceProviders</code> methods when their
585      * <code>useOrdering</code> argument is <code>true</code>.
586      *
587      * @param category a <code>Class</code> object indicating the
588      * category under which the preference is to be disestablished.
589      * @param firstProvider the formerly preferred provider.
590      * @param secondProvider the provider to which
591      * <code>firstProvider</code> was formerly preferred.
592      *
593      * @return <code>true</code> if a previously set ordering was
594      * disestablished.
595      *
596      * @exception IllegalArgumentException if either provider is
597      * <code>null</code> or they are the same object.
598      * @exception IllegalArgumentException if there is no category
599      * corresponding to <code>category</code>.
600      */

601     public <T> boolean unsetOrdering(Class JavaDoc<T> category,
602                      T firstProvider,
603                      T secondProvider) {
604         if (firstProvider == null || secondProvider == null) {
605             throw new IllegalArgumentException JavaDoc("provider is null!");
606         }
607         if (firstProvider == secondProvider) {
608             throw new IllegalArgumentException JavaDoc("providers are the same!");
609         }
610         SubRegistry reg = (SubRegistry)categoryMap.get(category);
611         if (reg == null) {
612             throw new IllegalArgumentException JavaDoc("category unknown!");
613         }
614         if (reg.contains(firstProvider) &&
615             reg.contains(secondProvider)) {
616             return reg.unsetOrdering(firstProvider, secondProvider);
617         }
618         return false;
619     }
620
621     /**
622      * Deregisters all service provider object currently registered
623      * under the given category.
624      *
625      * @param category the category to be emptied.
626      *
627      * @exception IllegalArgumentException if there is no category
628      * corresponding to <code>category</code>.
629      */

630     public void deregisterAll(Class JavaDoc<?> category) {
631         SubRegistry reg = (SubRegistry)categoryMap.get(category);
632         if (reg == null) {
633             throw new IllegalArgumentException JavaDoc("category unknown!");
634         }
635         reg.clear();
636     }
637
638     /**
639      * Deregisters all currently registered service providers from all
640      * categories.
641      */

642     public void deregisterAll() {
643         Iterator JavaDoc iter = categoryMap.values().iterator();
644         while (iter.hasNext()) {
645             SubRegistry reg = (SubRegistry)iter.next();
646             reg.clear();
647         }
648     }
649
650     /**
651      * Finalizes this object prior to garbage collection. The
652      * <code>deregisterAll</code> method is called to deregister all
653      * currently registered service providers. This method should not
654      * be called from application code.
655      *
656      * @exception Throwable if an error occurs during superclass
657      * finalization.
658      */

659     public void finalize() throws Throwable JavaDoc {
660         deregisterAll();
661         super.finalize();
662     }
663 }
664
665
666 /**
667  * A portion of a registry dealing with a single superclass or
668  * interface.
669  */

670 class SubRegistry {
671
672     ServiceRegistry JavaDoc registry;
673
674     Class JavaDoc category;
675
676     // Provider Objects organized by partial oridering
677
PartiallyOrderedSet JavaDoc poset = new PartiallyOrderedSet JavaDoc();
678
679     // Class -> Provider Object of that class
680
Map JavaDoc<Class JavaDoc<?>,Object JavaDoc> map = new HashMap JavaDoc();
681
682     public SubRegistry(ServiceRegistry JavaDoc registry, Class JavaDoc category) {
683         this.registry = registry;
684         this.category = category;
685     }
686
687     public boolean registerServiceProvider(Object JavaDoc provider) {
688         Object JavaDoc oprovider = map.get(provider.getClass());
689         boolean present = oprovider != null;
690
691         if (present) {
692             deregisterServiceProvider(oprovider);
693         }
694         map.put(provider.getClass(), provider);
695         poset.add(provider);
696         if (provider instanceof RegisterableService JavaDoc) {
697             RegisterableService JavaDoc rs = (RegisterableService JavaDoc)provider;
698             rs.onRegistration(registry, category);
699         }
700
701         return !present;
702     }
703
704     /**
705      * If the provider was not previously registered, do nothing.
706      *
707      * @return true if the provider was previously registered.
708      */

709     public boolean deregisterServiceProvider(Object JavaDoc provider) {
710         Object JavaDoc oprovider = map.get(provider.getClass());
711
712         if (provider == oprovider) {
713             map.remove(provider.getClass());
714             poset.remove(provider);
715             if (provider instanceof RegisterableService JavaDoc) {
716                 RegisterableService JavaDoc rs = (RegisterableService JavaDoc)provider;
717                 rs.onDeregistration(registry, category);
718             }
719
720             return true;
721         }
722         return false;
723     }
724
725     public boolean contains(Object JavaDoc provider) {
726         Object JavaDoc oprovider = map.get(provider.getClass());
727         return oprovider == provider;
728     }
729
730     public boolean setOrdering(Object JavaDoc firstProvider,
731                                Object JavaDoc secondProvider) {
732         return poset.setOrdering(firstProvider, secondProvider);
733     }
734     
735     public boolean unsetOrdering(Object JavaDoc firstProvider,
736                                  Object JavaDoc secondProvider) {
737         return poset.unsetOrdering(firstProvider, secondProvider);
738     }
739
740     public Iterator JavaDoc getServiceProviders(boolean useOrdering) {
741         if (useOrdering) {
742             return poset.iterator();
743         } else {
744             return map.values().iterator();
745         }
746     }
747
748     public <T> T getServiceProviderByClass(Class JavaDoc<T> providerClass) {
749         return (T)map.get(providerClass);
750     }
751
752     public void clear() {
753         Iterator JavaDoc iter = map.values().iterator();
754         while (iter.hasNext()) {
755             Object JavaDoc provider = iter.next();
756             iter.remove();
757
758             if (provider instanceof RegisterableService JavaDoc) {
759                 RegisterableService JavaDoc rs = (RegisterableService JavaDoc)provider;
760                 rs.onDeregistration(registry, category);
761             }
762         }
763         poset.clear();
764     }
765
766     public void finalize() {
767         clear();
768     }
769 }
770
771
772 /**
773  * A class for wrapping <code>Iterators</code> with a filter function.
774  * This provides an iterator for a subset without duplication.
775  */

776 class FilterIterator<T> implements Iterator JavaDoc<T> {
777
778     private Iterator JavaDoc<T> iter;
779     private ServiceRegistry.Filter JavaDoc filter;
780
781     private T next = null;
782
783     public FilterIterator(Iterator JavaDoc<T> iter,
784                           ServiceRegistry.Filter JavaDoc filter) {
785         this.iter = iter;
786         this.filter = filter;
787         advance();
788     }
789
790     private void advance() {
791         while (iter.hasNext()) {
792             T elt = iter.next();
793             if (filter.filter(elt)) {
794                 next = elt;
795                 return;
796             }
797         }
798
799         next = null;
800     }
801
802     public boolean hasNext() {
803         return next != null;
804     }
805
806     public T next() {
807         if (next == null) {
808             throw new NoSuchElementException JavaDoc();
809         }
810         T o = next;
811         advance();
812         return o;
813     }
814
815     public void remove() {
816         throw new UnsupportedOperationException JavaDoc();
817     }
818 }
819
Popular Tags