Save This Page
Home » openjdk-7 » javax » imageio » spi » [javadoc | source]
    1   /*
    2    * Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.imageio.spi;
   27   
   28   import java.io.File;
   29   import java.util.ArrayList;
   30   import java.util.HashMap;
   31   import java.util.Iterator;
   32   import java.util.List;
   33   import java.util.Map;
   34   import java.util.NoSuchElementException;
   35   import java.util.Set;
   36   import java.util.ServiceLoader;
   37   
   38   /**
   39    * A registry for service provider instances.
   40    *
   41    * <p> A <i>service</i> is a well-known set of interfaces and (usually
   42    * abstract) classes.  A <i>service provider</i> is a specific
   43    * implementation of a service.  The classes in a provider typically
   44    * implement the interface or subclass the class defined by the
   45    * service itself.
   46    *
   47    * <p> Service providers are stored in one or more <i>categories</i>,
   48    * each of which is defined by a class of interface (described by a
   49    * <code>Class</code> object) that all of its members must implement.
   50    * The set of categories may be changed dynamically.
   51    *
   52    * <p> Only a single instance of a given leaf class (that is, the
   53    * actual class returned by <code>getClass()</code>, as opposed to any
   54    * inherited classes or interfaces) may be registered.  That is,
   55    * suppose that the
   56    * <code>com.mycompany.mypkg.GreenServiceProvider</code> class
   57    * implements the <code>com.mycompany.mypkg.MyService</code>
   58    * interface.  If a <code>GreenServiceProvider</code> instance is
   59    * registered, it will be stored in the category defined by the
   60    * <code>MyService</code> class.  If a new instance of
   61    * <code>GreenServiceProvider</code> is registered, it will replace
   62    * the previous instance.  In practice, service provider objects are
   63    * usually singletons so this behavior is appropriate.
   64    *
   65    * <p> To declare a service provider, a <code>services</code>
   66    * subdirectory is placed within the <code>META-INF</code> directory
   67    * that is present in every JAR file.  This directory contains a file
   68    * for each service provider interface that has one or more
   69    * implementation classes present in the JAR file.  For example, if
   70    * the JAR file contained a class named
   71    * <code>com.mycompany.mypkg.MyServiceImpl</code> which implements the
   72    * <code>javax.someapi.SomeService</code> interface, the JAR file
   73    * would contain a file named: <pre>
   74    * META-INF/services/javax.someapi.SomeService </pre>
   75    *
   76    * containing the line:
   77    *
   78    * <pre>
   79    * com.mycompany.mypkg.MyService
   80    * </pre>
   81    *
   82    * <p> The service provider classes should be to be lightweight and
   83    * quick to load.  Implementations of these interfaces should avoid
   84    * complex dependencies on other classes and on native code. The usual
   85    * pattern for more complex services is to register a lightweight
   86    * proxy for the heavyweight service.
   87    *
   88    * <p> An application may customize the contents of a registry as it
   89    * sees fit, so long as it has the appropriate runtime permission.
   90    *
   91    * <p> For more details on declaring service providers, and the JAR
   92    * format in general, see the <a
   93    * href="../../../../technotes/guides/jar/jar.html">
   94    * JAR File Specification</a>.
   95    *
   96    * @see RegisterableService
   97    *
   98    */
   99   public class ServiceRegistry {
  100   
  101       // Class -> Registry
  102       private Map categoryMap = new HashMap();
  103   
  104       /**
  105        * Constructs a <code>ServiceRegistry</code> instance with a
  106        * set of categories taken from the <code>categories</code>
  107        * argument.
  108        *
  109        * @param categories an <code>Iterator</code> containing
  110        * <code>Class</code> objects to be used to define categories.
  111        *
  112        * @exception IllegalArgumentException if
  113        * <code>categories</code> is <code>null</code>.
  114        */
  115       public ServiceRegistry(Iterator<Class<?>> categories) {
  116           if (categories == null) {
  117               throw new IllegalArgumentException("categories == null!");
  118           }
  119           while (categories.hasNext()) {
  120               Class category = (Class)categories.next();
  121               SubRegistry reg = new SubRegistry(this, category);
  122               categoryMap.put(category, reg);
  123           }
  124       }
  125   
  126       // The following two methods expose functionality from
  127       // sun.misc.Service.  If that class is made public, they may be
  128       // removed.
  129       //
  130       // The sun.misc.ServiceConfigurationError class may also be
  131       // exposed, in which case the references to 'an
  132       // <code>Error</code>' below should be changed to 'a
  133       // <code>ServiceConfigurationError</code>'.
  134   
  135       /**
  136        * Searches for implementations of a particular service class
  137        * using the given class loader.
  138        *
  139        * <p> This method transforms the name of the given service class
  140        * into a provider-configuration filename as described in the
  141        * class comment and then uses the <code>getResources</code>
  142        * method of the given class loader to find all available files
  143        * with that name.  These files are then read and parsed to
  144        * produce a list of provider-class names.  The iterator that is
  145        * returned uses the given class loader to look up and then
  146        * instantiate each element of the list.
  147        *
  148        * <p> Because it is possible for extensions to be installed into
  149        * a running Java virtual machine, this method may return
  150        * different results each time it is invoked.
  151        *
  152        * @param providerClass a <code>Class</code>object indicating the
  153        * class or interface of the service providers being detected.
  154        *
  155        * @param loader the class loader to be used to load
  156        * provider-configuration files and instantiate provider classes,
  157        * or <code>null</code> if the system class loader (or, failing that
  158        * the bootstrap class loader) is to be used.
  159        *
  160        * @return An <code>Iterator</code> that yields provider objects
  161        * for the given service, in some arbitrary order.  The iterator
  162        * will throw an <code>Error</code> if a provider-configuration
  163        * file violates the specified format or if a provider class
  164        * cannot be found and instantiated.
  165        *
  166        * @exception IllegalArgumentException if
  167        * <code>providerClass</code> is <code>null</code>.
  168        */
  169       public static <T> Iterator<T> lookupProviders(Class<T> providerClass,
  170                                                     ClassLoader loader)
  171       {
  172           if (providerClass == null) {
  173               throw new IllegalArgumentException("providerClass == null!");
  174           }
  175           return ServiceLoader.load(providerClass, loader).iterator();
  176       }
  177   
  178       /**
  179        * Locates and incrementally instantiates the available providers
  180        * of a given service using the context class loader.  This
  181        * convenience method is equivalent to:
  182        *
  183        * <pre>
  184        *   ClassLoader cl = Thread.currentThread().getContextClassLoader();
  185        *   return Service.providers(service, cl);
  186        * </pre>
  187        *
  188        * @param providerClass a <code>Class</code>object indicating the
  189        * class or interface of the service providers being detected.
  190        *
  191        * @return An <code>Iterator</code> that yields provider objects
  192        * for the given service, in some arbitrary order.  The iterator
  193        * will throw an <code>Error</code> if a provider-configuration
  194        * file violates the specified format or if a provider class
  195        * cannot be found and instantiated.
  196        *
  197        * @exception IllegalArgumentException if
  198        * <code>providerClass</code> is <code>null</code>.
  199        */
  200       public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
  201           if (providerClass == null) {
  202               throw new IllegalArgumentException("providerClass == null!");
  203           }
  204           return ServiceLoader.load(providerClass).iterator();
  205       }
  206   
  207       /**
  208        * Returns an <code>Iterator</code> of <code>Class</code> objects
  209        * indicating the current set of categories.  The iterator will be
  210        * empty if no categories exist.
  211        *
  212        * @return an <code>Iterator</code> containing
  213        * <code>Class</code>objects.
  214        */
  215       public Iterator<Class<?>> getCategories() {
  216           Set keySet = categoryMap.keySet();
  217           return keySet.iterator();
  218       }
  219   
  220       /**
  221        * Returns an Iterator containing the subregistries to which the
  222        * provider belongs.
  223        */
  224       private Iterator getSubRegistries(Object provider) {
  225           List l = new ArrayList();
  226           Iterator iter = categoryMap.keySet().iterator();
  227           while (iter.hasNext()) {
  228               Class c = (Class)iter.next();
  229               if (c.isAssignableFrom(provider.getClass())) {
  230                   l.add((SubRegistry)categoryMap.get(c));
  231               }
  232           }
  233           return l.iterator();
  234       }
  235   
  236       /**
  237        * Adds a service provider object to the registry.  The provider
  238        * is associated with the given category.
  239        *
  240        * <p> If <code>provider</code> implements the
  241        * <code>RegisterableService</code> interface, its
  242        * <code>onRegistration</code> method will be called.  Its
  243        * <code>onDeregistration</code> method will be called each time
  244        * it is deregistered from a category, for example if a
  245        * category is removed or the registry is garbage collected.
  246        *
  247        * @param provider the service provide object to be registered.
  248        * @param category the category under which to register the
  249        * provider.
  250        *
  251        * @return true if no provider of the same class was previously
  252        * registered in the same category category.
  253        *
  254        * @exception IllegalArgumentException if <code>provider</code> is
  255        * <code>null</code>.
  256        * @exception IllegalArgumentException if there is no category
  257        * corresponding to <code>category</code>.
  258        * @exception ClassCastException if provider does not implement
  259        * the <code>Class</code> defined by <code>category</code>.
  260        */
  261       public <T> boolean registerServiceProvider(T provider,
  262                                                  Class<T> category) {
  263           if (provider == null) {
  264               throw new IllegalArgumentException("provider == null!");
  265           }
  266           SubRegistry reg = (SubRegistry)categoryMap.get(category);
  267           if (reg == null) {
  268               throw new IllegalArgumentException("category unknown!");
  269           }
  270           if (!category.isAssignableFrom(provider.getClass())) {
  271               throw new ClassCastException();
  272           }
  273   
  274           return reg.registerServiceProvider(provider);
  275       }
  276   
  277       /**
  278        * Adds a service provider object to the registry.  The provider
  279        * is associated within each category present in the registry
  280        * whose <code>Class</code> it implements.
  281        *
  282        * <p> If <code>provider</code> implements the
  283        * <code>RegisterableService</code> interface, its
  284        * <code>onRegistration</code> method will be called once for each
  285        * category it is registered under.  Its
  286        * <code>onDeregistration</code> method will be called each time
  287        * it is deregistered from a category or when the registry is
  288        * finalized.
  289        *
  290        * @param provider the service provider object to be registered.
  291        *
  292        * @exception IllegalArgumentException if
  293        * <code>provider</code> is <code>null</code>.
  294        */
  295       public void registerServiceProvider(Object provider) {
  296           if (provider == null) {
  297               throw new IllegalArgumentException("provider == null!");
  298           }
  299           Iterator regs = getSubRegistries(provider);
  300           while (regs.hasNext()) {
  301               SubRegistry reg = (SubRegistry)regs.next();
  302               reg.registerServiceProvider(provider);
  303           }
  304       }
  305   
  306       /**
  307        * Adds a set of service provider objects, taken from an
  308        * <code>Iterator</code> to the registry.  Each provider is
  309        * associated within each category present in the registry whose
  310        * <code>Class</code> it implements.
  311        *
  312        * <p> For each entry of <code>providers</code> that implements
  313        * the <code>RegisterableService</code> interface, its
  314        * <code>onRegistration</code> method will be called once for each
  315        * category it is registered under.  Its
  316        * <code>onDeregistration</code> method will be called each time
  317        * it is deregistered from a category or when the registry is
  318        * finalized.
  319        *
  320        * @param providers an Iterator containing service provider
  321        * objects to be registered.
  322        *
  323        * @exception IllegalArgumentException if <code>providers</code>
  324        * is <code>null</code> or contains a <code>null</code> entry.
  325        */
  326       public void registerServiceProviders(Iterator<?> providers) {
  327           if (providers == null) {
  328               throw new IllegalArgumentException("provider == null!");
  329           }
  330           while (providers.hasNext()) {
  331               registerServiceProvider(providers.next());
  332           }
  333       }
  334   
  335       /**
  336        * Removes a service provider object from the given category.  If
  337        * the provider was not previously registered, nothing happens and
  338        * <code>false</code> is returned.  Otherwise, <code>true</code>
  339        * is returned.  If an object of the same class as
  340        * <code>provider</code> but not equal (using <code>==</code>) to
  341        * <code>provider</code> is registered, it will not be
  342        * deregistered.
  343        *
  344        * <p> If <code>provider</code> implements the
  345        * <code>RegisterableService</code> interface, its
  346        * <code>onDeregistration</code> method will be called.
  347        *
  348        * @param provider the service provider object to be deregistered.
  349        * @param category the category from which to deregister the
  350        * provider.
  351        *
  352        * @return <code>true</code> if the provider was previously
  353        * registered in the same category category,
  354        * <code>false</code> otherwise.
  355        *
  356        * @exception IllegalArgumentException if <code>provider</code> is
  357        * <code>null</code>.
  358        * @exception IllegalArgumentException if there is no category
  359        * corresponding to <code>category</code>.
  360        * @exception ClassCastException if provider does not implement
  361        * the class defined by <code>category</code>.
  362        */
  363       public <T> boolean deregisterServiceProvider(T provider,
  364                                                    Class<T> category) {
  365           if (provider == null) {
  366               throw new IllegalArgumentException("provider == null!");
  367           }
  368           SubRegistry reg = (SubRegistry)categoryMap.get(category);
  369           if (reg == null) {
  370               throw new IllegalArgumentException("category unknown!");
  371           }
  372           if (!category.isAssignableFrom(provider.getClass())) {
  373               throw new ClassCastException();
  374           }
  375           return reg.deregisterServiceProvider(provider);
  376       }
  377   
  378       /**
  379        * Removes a service provider object from all categories that
  380        * contain it.
  381        *
  382        * @param provider the service provider object to be deregistered.
  383        *
  384        * @exception IllegalArgumentException if <code>provider</code> is
  385        * <code>null</code>.
  386        */
  387       public void deregisterServiceProvider(Object provider) {
  388           if (provider == null) {
  389               throw new IllegalArgumentException("provider == null!");
  390           }
  391           Iterator regs = getSubRegistries(provider);
  392           while (regs.hasNext()) {
  393               SubRegistry reg = (SubRegistry)regs.next();
  394               reg.deregisterServiceProvider(provider);
  395           }
  396       }
  397   
  398       /**
  399        * Returns <code>true</code> if <code>provider</code> is currently
  400        * registered.
  401        *
  402        * @param provider the service provider object to be queried.
  403        *
  404        * @return <code>true</code> if the given provider has been
  405        * registered.
  406        *
  407        * @exception IllegalArgumentException if <code>provider</code> is
  408        * <code>null</code>.
  409        */
  410       public boolean contains(Object provider) {
  411           if (provider == null) {
  412               throw new IllegalArgumentException("provider == null!");
  413           }
  414           Iterator regs = getSubRegistries(provider);
  415           while (regs.hasNext()) {
  416               SubRegistry reg = (SubRegistry)regs.next();
  417               if (reg.contains(provider)) {
  418                   return true;
  419               }
  420           }
  421   
  422           return false;
  423       }
  424   
  425       /**
  426        * Returns an <code>Iterator</code> containing all registered
  427        * service providers in the given category.  If
  428        * <code>useOrdering</code> is <code>false</code>, the iterator
  429        * will return all of the server provider objects in an arbitrary
  430        * order.  Otherwise, the ordering will respect any pairwise
  431        * orderings that have been set.  If the graph of pairwise
  432        * orderings contains cycles, any providers that belong to a cycle
  433        * will not be returned.
  434        *
  435        * @param category the category to be retrieved from.
  436        * @param useOrdering <code>true</code> if pairwise orderings
  437        * should be taken account in ordering the returned objects.
  438        *
  439        * @return an <code>Iterator</code> containing service provider
  440        * objects from the given category, possibly in order.
  441        *
  442        * @exception IllegalArgumentException if there is no category
  443        * corresponding to <code>category</code>.
  444        */
  445       public <T> Iterator<T> getServiceProviders(Class<T> category,
  446                                                  boolean useOrdering) {
  447           SubRegistry reg = (SubRegistry)categoryMap.get(category);
  448           if (reg == null) {
  449               throw new IllegalArgumentException("category unknown!");
  450           }
  451           return reg.getServiceProviders(useOrdering);
  452       }
  453   
  454       /**
  455        * A simple filter interface used by
  456        * <code>ServiceRegistry.getServiceProviders</code> to select
  457        * providers matching an arbitrary criterion.  Classes that
  458        * implement this interface should be defined in order to make use
  459        * of the <code>getServiceProviders</code> method of
  460        * <code>ServiceRegistry</code> that takes a <code>Filter</code>.
  461        *
  462        * @see ServiceRegistry#getServiceProviders(Class, ServiceRegistry.Filter, boolean)
  463        */
  464       public interface Filter {
  465   
  466           /**
  467            * Returns <code>true</code> if the given
  468            * <code>provider</code> object matches the criterion defined
  469            * by this <code>Filter</code>.
  470            *
  471            * @param provider a service provider <code>Object</code>.
  472            *
  473            * @return true if the provider matches the criterion.
  474            */
  475           boolean filter(Object provider);
  476       }
  477   
  478       /**
  479        * Returns an <code>Iterator</code> containing service provider
  480        * objects within a given category that satisfy a criterion
  481        * imposed by the supplied <code>ServiceRegistry.Filter</code>
  482        * object's <code>filter</code> method.
  483        *
  484        * <p> The <code>useOrdering</code> argument controls the
  485        * ordering of the results using the same rules as
  486        * <code>getServiceProviders(Class, boolean)</code>.
  487        *
  488        * @param category the category to be retrieved from.
  489        * @param filter an instance of <code>ServiceRegistry.Filter</code>
  490        * whose <code>filter</code> method will be invoked.
  491        * @param useOrdering <code>true</code> if pairwise orderings
  492        * should be taken account in ordering the returned objects.
  493        *
  494        * @return an <code>Iterator</code> containing service provider
  495        * objects from the given category, possibly in order.
  496        *
  497        * @exception IllegalArgumentException if there is no category
  498        * corresponding to <code>category</code>.
  499        */
  500       public <T> Iterator<T> getServiceProviders(Class<T> category,
  501                                                  Filter filter,
  502                                                  boolean useOrdering) {
  503           SubRegistry reg = (SubRegistry)categoryMap.get(category);
  504           if (reg == null) {
  505               throw new IllegalArgumentException("category unknown!");
  506           }
  507           Iterator iter = getServiceProviders(category, useOrdering);
  508           return new FilterIterator(iter, filter);
  509       }
  510   
  511       /**
  512        * Returns the currently registered service provider object that
  513        * is of the given class type.  At most one object of a given
  514        * class is allowed to be registered at any given time.  If no
  515        * registered object has the desired class type, <code>null</code>
  516        * is returned.
  517        *
  518        * @param providerClass the <code>Class</code> of the desired
  519        * service provider object.
  520        *
  521        * @return a currently registered service provider object with the
  522        * desired <code>Class</code>type, or <code>null</code> is none is
  523        * present.
  524        *
  525        * @exception IllegalArgumentException if <code>providerClass</code> is
  526        * <code>null</code>.
  527        */
  528       public <T> T getServiceProviderByClass(Class<T> providerClass) {
  529           if (providerClass == null) {
  530               throw new IllegalArgumentException("providerClass == null!");
  531           }
  532           Iterator iter = categoryMap.keySet().iterator();
  533           while (iter.hasNext()) {
  534               Class c = (Class)iter.next();
  535               if (c.isAssignableFrom(providerClass)) {
  536                   SubRegistry reg = (SubRegistry)categoryMap.get(c);
  537                   T provider = reg.getServiceProviderByClass(providerClass);
  538                   if (provider != null) {
  539                       return provider;
  540                   }
  541               }
  542           }
  543           return null;
  544       }
  545   
  546       /**
  547        * Sets a pairwise ordering between two service provider objects
  548        * within a given category.  If one or both objects are not
  549        * currently registered within the given category, or if the
  550        * desired ordering is already set, nothing happens and
  551        * <code>false</code> is returned.  If the providers previously
  552        * were ordered in the reverse direction, that ordering is
  553        * removed.
  554        *
  555        * <p> The ordering will be used by the
  556        * <code>getServiceProviders</code> methods when their
  557        * <code>useOrdering</code> argument is <code>true</code>.
  558        *
  559        * @param category a <code>Class</code> object indicating the
  560        * category under which the preference is to be established.
  561        * @param firstProvider the preferred provider.
  562        * @param secondProvider the provider to which
  563        * <code>firstProvider</code> is preferred.
  564        *
  565        * @return <code>true</code> if a previously unset ordering
  566        * was established.
  567        *
  568        * @exception IllegalArgumentException if either provider is
  569        * <code>null</code> or they are the same object.
  570        * @exception IllegalArgumentException if there is no category
  571        * corresponding to <code>category</code>.
  572        */
  573       public <T> boolean setOrdering(Class<T> category,
  574                                      T firstProvider,
  575                                      T secondProvider) {
  576           if (firstProvider == null || secondProvider == null) {
  577               throw new IllegalArgumentException("provider is null!");
  578           }
  579           if (firstProvider == secondProvider) {
  580               throw new IllegalArgumentException("providers are the same!");
  581           }
  582           SubRegistry reg = (SubRegistry)categoryMap.get(category);
  583           if (reg == null) {
  584               throw new IllegalArgumentException("category unknown!");
  585           }
  586           if (reg.contains(firstProvider) &&
  587               reg.contains(secondProvider)) {
  588               return reg.setOrdering(firstProvider, secondProvider);
  589           }
  590           return false;
  591       }
  592   
  593       /**
  594        * Sets a pairwise ordering between two service provider objects
  595        * within a given category.  If one or both objects are not
  596        * currently registered within the given category, or if no
  597        * ordering is currently set between them, nothing happens
  598        * and <code>false</code> is returned.
  599        *
  600        * <p> The ordering will be used by the
  601        * <code>getServiceProviders</code> methods when their
  602        * <code>useOrdering</code> argument is <code>true</code>.
  603        *
  604        * @param category a <code>Class</code> object indicating the
  605        * category under which the preference is to be disestablished.
  606        * @param firstProvider the formerly preferred provider.
  607        * @param secondProvider the provider to which
  608        * <code>firstProvider</code> was formerly preferred.
  609        *
  610        * @return <code>true</code> if a previously set ordering was
  611        * disestablished.
  612        *
  613        * @exception IllegalArgumentException if either provider is
  614        * <code>null</code> or they are the same object.
  615        * @exception IllegalArgumentException if there is no category
  616        * corresponding to <code>category</code>.
  617        */
  618       public <T> boolean unsetOrdering(Class<T> category,
  619                                        T firstProvider,
  620                                        T secondProvider) {
  621           if (firstProvider == null || secondProvider == null) {
  622               throw new IllegalArgumentException("provider is null!");
  623           }
  624           if (firstProvider == secondProvider) {
  625               throw new IllegalArgumentException("providers are the same!");
  626           }
  627           SubRegistry reg = (SubRegistry)categoryMap.get(category);
  628           if (reg == null) {
  629               throw new IllegalArgumentException("category unknown!");
  630           }
  631           if (reg.contains(firstProvider) &&
  632               reg.contains(secondProvider)) {
  633               return reg.unsetOrdering(firstProvider, secondProvider);
  634           }
  635           return false;
  636       }
  637   
  638       /**
  639        * Deregisters all service provider object currently registered
  640        * under the given category.
  641        *
  642        * @param category the category to be emptied.
  643        *
  644        * @exception IllegalArgumentException if there is no category
  645        * corresponding to <code>category</code>.
  646        */
  647       public void deregisterAll(Class<?> category) {
  648           SubRegistry reg = (SubRegistry)categoryMap.get(category);
  649           if (reg == null) {
  650               throw new IllegalArgumentException("category unknown!");
  651           }
  652           reg.clear();
  653       }
  654   
  655       /**
  656        * Deregisters all currently registered service providers from all
  657        * categories.
  658        */
  659       public void deregisterAll() {
  660           Iterator iter = categoryMap.values().iterator();
  661           while (iter.hasNext()) {
  662               SubRegistry reg = (SubRegistry)iter.next();
  663               reg.clear();
  664           }
  665       }
  666   
  667       /**
  668        * Finalizes this object prior to garbage collection.  The
  669        * <code>deregisterAll</code> method is called to deregister all
  670        * currently registered service providers.  This method should not
  671        * be called from application code.
  672        *
  673        * @exception Throwable if an error occurs during superclass
  674        * finalization.
  675        */
  676       public void finalize() throws Throwable {
  677           deregisterAll();
  678           super.finalize();
  679       }
  680   }
  681   
  682   
  683   /**
  684    * A portion of a registry dealing with a single superclass or
  685    * interface.
  686    */
  687   class SubRegistry {
  688   
  689       ServiceRegistry registry;
  690   
  691       Class category;
  692   
  693       // Provider Objects organized by partial oridering
  694       PartiallyOrderedSet poset = new PartiallyOrderedSet();
  695   
  696       // Class -> Provider Object of that class
  697       Map<Class<?>,Object> map = new HashMap();
  698   
  699       public SubRegistry(ServiceRegistry registry, Class category) {
  700           this.registry = registry;
  701           this.category = category;
  702       }
  703   
  704       public boolean registerServiceProvider(Object provider) {
  705           Object oprovider = map.get(provider.getClass());
  706           boolean present =  oprovider != null;
  707   
  708           if (present) {
  709               deregisterServiceProvider(oprovider);
  710           }
  711           map.put(provider.getClass(), provider);
  712           poset.add(provider);
  713           if (provider instanceof RegisterableService) {
  714               RegisterableService rs = (RegisterableService)provider;
  715               rs.onRegistration(registry, category);
  716           }
  717   
  718           return !present;
  719       }
  720   
  721       /**
  722        * If the provider was not previously registered, do nothing.
  723        *
  724        * @return true if the provider was previously registered.
  725        */
  726       public boolean deregisterServiceProvider(Object provider) {
  727           Object oprovider = map.get(provider.getClass());
  728   
  729           if (provider == oprovider) {
  730               map.remove(provider.getClass());
  731               poset.remove(provider);
  732               if (provider instanceof RegisterableService) {
  733                   RegisterableService rs = (RegisterableService)provider;
  734                   rs.onDeregistration(registry, category);
  735               }
  736   
  737               return true;
  738           }
  739           return false;
  740       }
  741   
  742       public boolean contains(Object provider) {
  743           Object oprovider = map.get(provider.getClass());
  744           return oprovider == provider;
  745       }
  746   
  747       public boolean setOrdering(Object firstProvider,
  748                                  Object secondProvider) {
  749           return poset.setOrdering(firstProvider, secondProvider);
  750       }
  751   
  752       public boolean unsetOrdering(Object firstProvider,
  753                                    Object secondProvider) {
  754           return poset.unsetOrdering(firstProvider, secondProvider);
  755       }
  756   
  757       public Iterator getServiceProviders(boolean useOrdering) {
  758           if (useOrdering) {
  759               return poset.iterator();
  760           } else {
  761               return map.values().iterator();
  762           }
  763       }
  764   
  765       public <T> T getServiceProviderByClass(Class<T> providerClass) {
  766           return (T)map.get(providerClass);
  767       }
  768   
  769       public void clear() {
  770           Iterator iter = map.values().iterator();
  771           while (iter.hasNext()) {
  772               Object provider = iter.next();
  773               iter.remove();
  774   
  775               if (provider instanceof RegisterableService) {
  776                   RegisterableService rs = (RegisterableService)provider;
  777                   rs.onDeregistration(registry, category);
  778               }
  779           }
  780           poset.clear();
  781       }
  782   
  783       public void finalize() {
  784           clear();
  785       }
  786   }
  787   
  788   
  789   /**
  790    * A class for wrapping <code>Iterators</code> with a filter function.
  791    * This provides an iterator for a subset without duplication.
  792    */
  793   class FilterIterator<T> implements Iterator<T> {
  794   
  795       private Iterator<T> iter;
  796       private ServiceRegistry.Filter filter;
  797   
  798       private T next = null;
  799   
  800       public FilterIterator(Iterator<T> iter,
  801                             ServiceRegistry.Filter filter) {
  802           this.iter = iter;
  803           this.filter = filter;
  804           advance();
  805       }
  806   
  807       private void advance() {
  808           while (iter.hasNext()) {
  809               T elt = iter.next();
  810               if (filter.filter(elt)) {
  811                   next = elt;
  812                   return;
  813               }
  814           }
  815   
  816           next = null;
  817       }
  818   
  819       public boolean hasNext() {
  820           return next != null;
  821       }
  822   
  823       public T next() {
  824           if (next == null) {
  825               throw new NoSuchElementException();
  826           }
  827           T o = next;
  828           advance();
  829           return o;
  830       }
  831   
  832       public void remove() {
  833           throw new UnsupportedOperationException();
  834       }
  835   }

Save This Page
Home » openjdk-7 » javax » imageio » spi » [javadoc | source]