Home | History | Annotate | Download | only in spi
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 /**
     18  * @author Rustem V. Rafikov
     19  * @version $Revision: 1.3 $
     20  */
     21 
     22 package javax.imageio.spi;
     23 
     24 import java.util.*;
     25 import java.util.Map.Entry;
     26 
     27 /**
     28  * The ServiceRegistry class provides ability to register, deregister, look up
     29  * and obtain service provider instances (SPIs). A service means a set of
     30  * interfaces and classes, and a service provider is an implementation of a
     31  * service. Service providers can be associated with one or more categories.
     32  * Each category is defined by a class or interface. Only a single instance of a
     33  * each class is allowed to be registered as a category.
     34  *
     35  * @since Android 1.0
     36  */
     37 public class ServiceRegistry {
     38 
     39     /**
     40      * The categories.
     41      */
     42     CategoriesMap categories = new CategoriesMap(this);
     43 
     44     /**
     45      * Instantiates a new ServiceRegistry with the specified categories.
     46      *
     47      * @param categoriesIterator
     48      *            an Iterator of Class objects for defining of categories.
     49      */
     50     public ServiceRegistry(Iterator<Class<?>> categoriesIterator) {
     51         if (null == categoriesIterator) {
     52             throw new IllegalArgumentException("categories iterator should not be NULL");
     53         }
     54         while (categoriesIterator.hasNext()) {
     55             Class<?> c = categoriesIterator.next();
     56             categories.addCategory(c);
     57         }
     58     }
     59 
     60     /**
     61      * Looks up and instantiates the available providers of this service using
     62      * the specified class loader.
     63      *
     64      * @param providerClass
     65      *            the Class object of the provider to be looked up.
     66      * @param loader
     67      *            the class loader to be used.
     68      * @return the iterator of providers objects for this service.
     69      */
     70     public static <T> Iterator<T> lookupProviders(Class<T> providerClass, ClassLoader loader) {
     71         throw new UnsupportedOperationException("Not supported yet");
     72     }
     73 
     74     /**
     75      * Looks up and instantiates the available providers of this service using
     76      * the context class loader.
     77      *
     78      * @param providerClass
     79      *            the Class object of the provider to be looked up.
     80      * @return the iterator of providers objects for this service.
     81      */
     82     public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
     83         return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader());
     84     }
     85 
     86     /**
     87      * Registers the specified service provider object in the specified
     88      * categories.
     89      *
     90      * @param provider
     91      *            the specified provider to be registered.
     92      * @param category
     93      *            the category.
     94      * @return true, if no provider of the same class is registered in this
     95      *         category, false otherwise.
     96      */
     97     public <T> boolean registerServiceProvider(T provider, Class<T> category) {
     98         return categories.addProvider(provider, category);
     99     }
    100 
    101     /**
    102      * Registers a list of service providers.
    103      *
    104      * @param providers
    105      *            the list of service providers.
    106      */
    107     public void registerServiceProviders(Iterator<?> providers) {
    108         for (Iterator<?> iterator = providers; iterator.hasNext();) {
    109             categories.addProvider(iterator.next(), null);
    110         }
    111     }
    112 
    113     /**
    114      * Registers the specified service provider object in all categories.
    115      *
    116      * @param provider
    117      *            the service provider.
    118      */
    119     public void registerServiceProvider(Object provider) {
    120         categories.addProvider(provider, null);
    121     }
    122 
    123     /**
    124      * Deregisters the specifies service provider from the specified category.
    125      *
    126      * @param provider
    127      *            the service provider to be deregistered.
    128      * @param category
    129      *            the specified category.
    130      * @return true, if the provider was already registered in the specified
    131      *         category, false otherwise.
    132      */
    133     public <T> boolean deregisterServiceProvider(T provider, Class<T> category) {
    134         throw new UnsupportedOperationException("Not supported yet");
    135     }
    136 
    137     /**
    138      * Deregisters the specified service provider from all categories.
    139      *
    140      * @param provider
    141      *            the specified service provider.
    142      */
    143     public void deregisterServiceProvider(Object provider) {
    144         throw new UnsupportedOperationException("Not supported yet");
    145     }
    146 
    147     /**
    148      * Gets an Iterator of registered service providers in the specified
    149      * category which satisfy the specified Filter. The useOrdering parameter
    150      * indicates whether the iterator will return all of the server provider
    151      * objects in a set order.
    152      *
    153      * @param category
    154      *            the specified category.
    155      * @param filter
    156      *            the specified filter.
    157      * @param useOrdering
    158      *            the flag indicating that providers are ordered in the returned
    159      *            Iterator.
    160      * @return the iterator of registered service providers.
    161      */
    162     @SuppressWarnings("unchecked")
    163     public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) {
    164         return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category,
    165                 useOrdering));
    166     }
    167 
    168     /**
    169      * Gets an Iterator of all registered service providers in the specified
    170      * category. The useOrdering parameter indicates whether the iterator will
    171      * return all of the server provider objects in a set order.
    172      *
    173      * @param category
    174      *            the specified category.
    175      * @param useOrdering
    176      *            the flag indicating that providers are ordered in the returned
    177      *            Iterator.
    178      * @return the Iterator of service providers.
    179      */
    180     @SuppressWarnings("unchecked")
    181     public <T> Iterator<T> getServiceProviders(Class<T> category, boolean useOrdering) {
    182         return (Iterator<T>)categories.getProviders(category, useOrdering);
    183     }
    184 
    185     /**
    186      * Gets the registered service provider object that has the specified class
    187      * type.
    188      *
    189      * @param providerClass
    190      *            the specified provider class.
    191      * @return the service provider object.
    192      */
    193     public <T> T getServiceProviderByClass(Class<T> providerClass) {
    194         throw new UnsupportedOperationException("Not supported yet");
    195     }
    196 
    197     /**
    198      * Sets an ordering between two service provider objects within the
    199      * specified category.
    200      *
    201      * @param category
    202      *            the specified category.
    203      * @param firstProvider
    204      *            the first provider.
    205      * @param secondProvider
    206      *            the second provider.
    207      * @return true, if a previously unset order was set.
    208      */
    209     public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) {
    210         throw new UnsupportedOperationException("Not supported yet");
    211     }
    212 
    213     /**
    214      * Unsets an ordering between two service provider objects within the
    215      * specified category.
    216      *
    217      * @param category
    218      *            the specified category.
    219      * @param firstProvider
    220      *            the first provider.
    221      * @param secondProvider
    222      *            the second provider.
    223      * @return true, if a previously unset order was removed.
    224      */
    225     public <T> boolean unsetOrdering(Class<T> category, T firstProvider, T secondProvider) {
    226         throw new UnsupportedOperationException("Not supported yet");
    227     }
    228 
    229     /**
    230      * Deregisters all providers from the specified category.
    231      *
    232      * @param category
    233      *            the specified category.
    234      */
    235     public void deregisterAll(Class<?> category) {
    236         throw new UnsupportedOperationException("Not supported yet");
    237     }
    238 
    239     /**
    240      * Deregister all providers from all categories.
    241      */
    242     public void deregisterAll() {
    243         throw new UnsupportedOperationException("Not supported yet");
    244     }
    245 
    246     /**
    247      * Finalizes this object.
    248      *
    249      * @throws Throwable
    250      *             if an error occurs during finalization.
    251      */
    252     @Override
    253     public void finalize() throws Throwable {
    254         // TODO uncomment when deregisterAll is implemented
    255         // deregisterAll();
    256     }
    257 
    258     /**
    259      * Checks whether the specified provider has been already registered.
    260      *
    261      * @param provider
    262      *            the provider to be checked.
    263      * @return true, if the specified provider has been already registered,
    264      *         false otherwise.
    265      */
    266     public boolean contains(Object provider) {
    267         throw new UnsupportedOperationException("Not supported yet");
    268     }
    269 
    270     /**
    271      * Gets an iterator of Class objects representing the current categories.
    272      *
    273      * @return the Iterator of Class objects.
    274      */
    275     public Iterator<Class<?>> getCategories() {
    276         return categories.list();
    277     }
    278 
    279     /**
    280      * The ServiceRegistry.Filter interface is used by
    281      * ServiceRegistry.getServiceProviders to filter providers according to the
    282      * specified criterion.
    283      *
    284      * @since Android 1.0
    285      */
    286     public static interface Filter {
    287 
    288         /**
    289          * Returns true if the specified provider satisfies the criterion of
    290          * this Filter.
    291          *
    292          * @param provider
    293          *            the provider.
    294          * @return true, if the specified provider satisfies the criterion of
    295          *         this Filter, false otherwise.
    296          */
    297         boolean filter(Object provider);
    298     }
    299 
    300     /**
    301      * The Class CategoriesMap.
    302      */
    303     private static class CategoriesMap {
    304 
    305         /**
    306          * The categories.
    307          */
    308         Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>();
    309 
    310         /**
    311          * The registry.
    312          */
    313         ServiceRegistry registry;
    314 
    315         /**
    316          * Instantiates a new categories map.
    317          *
    318          * @param registry
    319          *            the registry.
    320          */
    321         public CategoriesMap(ServiceRegistry registry) {
    322             this.registry = registry;
    323         }
    324 
    325         // -- TODO: useOrdering
    326         /**
    327          * Gets the providers.
    328          *
    329          * @param category
    330          *            the category.
    331          * @param useOrdering
    332          *            the use ordering.
    333          * @return the providers.
    334          */
    335         Iterator<?> getProviders(Class<?> category, boolean useOrdering) {
    336             ProvidersMap providers = categories.get(category);
    337             if (null == providers) {
    338                 throw new IllegalArgumentException("Unknown category: " + category);
    339             }
    340             return providers.getProviders(useOrdering);
    341         }
    342 
    343         /**
    344          * List.
    345          *
    346          * @return the iterator< class<?>>.
    347          */
    348         Iterator<Class<?>> list() {
    349             return categories.keySet().iterator();
    350         }
    351 
    352         /**
    353          * Adds the category.
    354          *
    355          * @param category
    356          *            the category.
    357          */
    358         void addCategory(Class<?> category) {
    359             categories.put(category, new ProvidersMap());
    360         }
    361 
    362         /**
    363          * Adds a provider to the category. If <code>category</code> is
    364          * <code>null</code> then the provider will be added to all categories
    365          * which the provider is assignable from.
    366          *
    367          * @param provider
    368          *            provider to add.
    369          * @param category
    370          *            category to add provider to.
    371          * @return true, if there were such provider in some category.
    372          */
    373         boolean addProvider(Object provider, Class<?> category) {
    374             if (provider == null) {
    375                 throw new IllegalArgumentException("provider should be != NULL");
    376             }
    377 
    378             boolean rt;
    379             if (category == null) {
    380                 rt = findAndAdd(provider);
    381             } else {
    382                 rt = addToNamed(provider, category);
    383             }
    384 
    385             if (provider instanceof RegisterableService) {
    386                 ((RegisterableService)provider).onRegistration(registry, category);
    387             }
    388 
    389             return rt;
    390         }
    391 
    392         /**
    393          * Adds the to named.
    394          *
    395          * @param provider
    396          *            the provider.
    397          * @param category
    398          *            the category.
    399          * @return true, if successful.
    400          */
    401         private boolean addToNamed(Object provider, Class<?> category) {
    402             Object obj = categories.get(category);
    403 
    404             if (null == obj) {
    405                 throw new IllegalArgumentException("Unknown category: " + category);
    406             }
    407 
    408             return ((ProvidersMap)obj).addProvider(provider);
    409         }
    410 
    411         /**
    412          * Find and add.
    413          *
    414          * @param provider
    415          *            the provider.
    416          * @return true, if successful.
    417          */
    418         private boolean findAndAdd(Object provider) {
    419             boolean rt = false;
    420             for (Entry<Class<?>, ProvidersMap> e : categories.entrySet()) {
    421                 if (e.getKey().isAssignableFrom(provider.getClass())) {
    422                     rt |= e.getValue().addProvider(provider);
    423                 }
    424             }
    425             return rt;
    426         }
    427     }
    428 
    429     /**
    430      * The Class ProvidersMap.
    431      */
    432     private static class ProvidersMap {
    433         // -- TODO: providers ordering support
    434 
    435         /**
    436          * The providers.
    437          */
    438         Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>();
    439 
    440         /**
    441          * Adds the provider.
    442          *
    443          * @param provider
    444          *            the provider.
    445          * @return true, if successful.
    446          */
    447         boolean addProvider(Object provider) {
    448             return providers.put(provider.getClass(), provider) != null;
    449         }
    450 
    451         /**
    452          * Gets the provider classes.
    453          *
    454          * @return the provider classes.
    455          */
    456         Iterator<Class<?>> getProviderClasses() {
    457             return providers.keySet().iterator();
    458         }
    459 
    460         // -- TODO ordering
    461         /**
    462          * Gets the providers.
    463          *
    464          * @param userOrdering
    465          *            the user ordering.
    466          * @return the providers.
    467          */
    468         Iterator<?> getProviders(boolean userOrdering) {
    469             return providers.values().iterator();
    470         }
    471     }
    472 
    473     /**
    474      * The Class FilteredIterator.
    475      */
    476     private static class FilteredIterator<E> implements Iterator<E> {
    477 
    478         /**
    479          * The filter.
    480          */
    481         private Filter filter;
    482 
    483         /**
    484          * The backend.
    485          */
    486         private Iterator<E> backend;
    487 
    488         /**
    489          * The next obj.
    490          */
    491         private E nextObj;
    492 
    493         /**
    494          * Instantiates a new filtered iterator.
    495          *
    496          * @param filter
    497          *            the filter.
    498          * @param backend
    499          *            the backend.
    500          */
    501         public FilteredIterator(Filter filter, Iterator<E> backend) {
    502             this.filter = filter;
    503             this.backend = backend;
    504             findNext();
    505         }
    506 
    507         /**
    508          * Next.
    509          *
    510          * @return the e.
    511          */
    512         public E next() {
    513             if (nextObj == null) {
    514                 throw new NoSuchElementException();
    515             }
    516             E tmp = nextObj;
    517             findNext();
    518             return tmp;
    519         }
    520 
    521         /**
    522          * Checks for next.
    523          *
    524          * @return true, if successful.
    525          */
    526         public boolean hasNext() {
    527             return nextObj != null;
    528         }
    529 
    530         /**
    531          * Removes the.
    532          */
    533         public void remove() {
    534             throw new UnsupportedOperationException();
    535         }
    536 
    537         /**
    538          * Sets nextObj to a next provider matching the criterion given by the
    539          * filter.
    540          */
    541         private void findNext() {
    542             nextObj = null;
    543             while (backend.hasNext()) {
    544                 E o = backend.next();
    545                 if (filter.filter(o)) {
    546                     nextObj = o;
    547                     return;
    548                 }
    549             }
    550         }
    551     }
    552 }
    553