/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ package javax.imageio.spi; import java.util.*; import java.util.Map.Entry; /** * The ServiceRegistry class provides ability to register, deregister, look up * and obtain service provider instances (SPIs). A service means a set of * interfaces and classes, and a service provider is an implementation of a * service. Service providers can be associated with one or more categories. * Each category is defined by a class or interface. Only a single instance of a * each class is allowed to be registered as a category. * * @since Android 1.0 */ public class ServiceRegistry { /** * The categories. */ CategoriesMap categories = new CategoriesMap(this); /** * Instantiates a new ServiceRegistry with the specified categories. * * @param categoriesIterator * an Iterator of Class objects for defining of categories. */ public ServiceRegistry(Iterator<Class<?>> categoriesIterator) { if (null == categoriesIterator) { throw new IllegalArgumentException("categories iterator should not be NULL"); } while (categoriesIterator.hasNext()) { Class<?> c = categoriesIterator.next(); categories.addCategory(c); } } /** * Looks up and instantiates the available providers of this service using * the specified class loader. * * @param providerClass * the Class object of the provider to be looked up. * @param loader * the class loader to be used. * @return the iterator of providers objects for this service. */ public static <T> Iterator<T> lookupProviders(Class<T> providerClass, ClassLoader loader) { throw new UnsupportedOperationException("Not supported yet"); } /** * Looks up and instantiates the available providers of this service using * the context class loader. * * @param providerClass * the Class object of the provider to be looked up. * @return the iterator of providers objects for this service. */ public static <T> Iterator<T> lookupProviders(Class<T> providerClass) { return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader()); } /** * Registers the specified service provider object in the specified * categories. * * @param provider * the specified provider to be registered. * @param category * the category. * @return true, if no provider of the same class is registered in this * category, false otherwise. */ public <T> boolean registerServiceProvider(T provider, Class<T> category) { return categories.addProvider(provider, category); } /** * Registers a list of service providers. * * @param providers * the list of service providers. */ public void registerServiceProviders(Iterator<?> providers) { for (Iterator<?> iterator = providers; iterator.hasNext();) { categories.addProvider(iterator.next(), null); } } /** * Registers the specified service provider object in all categories. * * @param provider * the service provider. */ public void registerServiceProvider(Object provider) { categories.addProvider(provider, null); } /** * Deregisters the specifies service provider from the specified category. * * @param provider * the service provider to be deregistered. * @param category * the specified category. * @return true, if the provider was already registered in the specified * category, false otherwise. */ public <T> boolean deregisterServiceProvider(T provider, Class<T> category) { throw new UnsupportedOperationException("Not supported yet"); } /** * Deregisters the specified service provider from all categories. * * @param provider * the specified service provider. */ public void deregisterServiceProvider(Object provider) { throw new UnsupportedOperationException("Not supported yet"); } /** * Gets an Iterator of registered service providers in the specified * category which satisfy the specified Filter. The useOrdering parameter * indicates whether the iterator will return all of the server provider * objects in a set order. * * @param category * the specified category. * @param filter * the specified filter. * @param useOrdering * the flag indicating that providers are ordered in the returned * Iterator. * @return the iterator of registered service providers. */ @SuppressWarnings("unchecked") public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) { return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category, useOrdering)); } /** * Gets an Iterator of all registered service providers in the specified * category. The useOrdering parameter indicates whether the iterator will * return all of the server provider objects in a set order. * * @param category * the specified category. * @param useOrdering * the flag indicating that providers are ordered in the returned * Iterator. * @return the Iterator of service providers. */ @SuppressWarnings("unchecked") public <T> Iterator<T> getServiceProviders(Class<T> category, boolean useOrdering) { return (Iterator<T>)categories.getProviders(category, useOrdering); } /** * Gets the registered service provider object that has the specified class * type. * * @param providerClass * the specified provider class. * @return the service provider object. */ public <T> T getServiceProviderByClass(Class<T> providerClass) { throw new UnsupportedOperationException("Not supported yet"); } /** * Sets an ordering between two service provider objects within the * specified category. * * @param category * the specified category. * @param firstProvider * the first provider. * @param secondProvider * the second provider. * @return true, if a previously unset order was set. */ public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) { throw new UnsupportedOperationException("Not supported yet"); } /** * Unsets an ordering between two service provider objects within the * specified category. * * @param category * the specified category. * @param firstProvider * the first provider. * @param secondProvider * the second provider. * @return true, if a previously unset order was removed. */ public <T> boolean unsetOrdering(Class<T> category, T firstProvider, T secondProvider) { throw new UnsupportedOperationException("Not supported yet"); } /** * Deregisters all providers from the specified category. * * @param category * the specified category. */ public void deregisterAll(Class<?> category) { throw new UnsupportedOperationException("Not supported yet"); } /** * Deregister all providers from all categories. */ public void deregisterAll() { throw new UnsupportedOperationException("Not supported yet"); } /** * Finalizes this object. * * @throws Throwable * if an error occurs during finalization. */ @Override public void finalize() throws Throwable { // TODO uncomment when deregisterAll is implemented // deregisterAll(); } /** * Checks whether the specified provider has been already registered. * * @param provider * the provider to be checked. * @return true, if the specified provider has been already registered, * false otherwise. */ public boolean contains(Object provider) { throw new UnsupportedOperationException("Not supported yet"); } /** * Gets an iterator of Class objects representing the current categories. * * @return the Iterator of Class objects. */ public Iterator<Class<?>> getCategories() { return categories.list(); } /** * The ServiceRegistry.Filter interface is used by * ServiceRegistry.getServiceProviders to filter providers according to the * specified criterion. * * @since Android 1.0 */ public static interface Filter { /** * Returns true if the specified provider satisfies the criterion of * this Filter. * * @param provider * the provider. * @return true, if the specified provider satisfies the criterion of * this Filter, false otherwise. */ boolean filter(Object provider); } /** * The Class CategoriesMap. */ private static class CategoriesMap { /** * The categories. */ Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>(); /** * The registry. */ ServiceRegistry registry; /** * Instantiates a new categories map. * * @param registry * the registry. */ public CategoriesMap(ServiceRegistry registry) { this.registry = registry; } // -- TODO: useOrdering /** * Gets the providers. * * @param category * the category. * @param useOrdering * the use ordering. * @return the providers. */ Iterator<?> getProviders(Class<?> category, boolean useOrdering) { ProvidersMap providers = categories.get(category); if (null == providers) { throw new IllegalArgumentException("Unknown category: " + category); } return providers.getProviders(useOrdering); } /** * List. * * @return the iterator< class<?>>. */ Iterator<Class<?>> list() { return categories.keySet().iterator(); } /** * Adds the category. * * @param category * the category. */ void addCategory(Class<?> category) { categories.put(category, new ProvidersMap()); } /** * Adds a provider to the category. If <code>category</code> is * <code>null</code> then the provider will be added to all categories * which the provider is assignable from. * * @param provider * provider to add. * @param category * category to add provider to. * @return true, if there were such provider in some category. */ boolean addProvider(Object provider, Class<?> category) { if (provider == null) { throw new IllegalArgumentException("provider should be != NULL"); } boolean rt; if (category == null) { rt = findAndAdd(provider); } else { rt = addToNamed(provider, category); } if (provider instanceof RegisterableService) { ((RegisterableService)provider).onRegistration(registry, category); } return rt; } /** * Adds the to named. * * @param provider * the provider. * @param category * the category. * @return true, if successful. */ private boolean addToNamed(Object provider, Class<?> category) { Object obj = categories.get(category); if (null == obj) { throw new IllegalArgumentException("Unknown category: " + category); } return ((ProvidersMap)obj).addProvider(provider); } /** * Find and add. * * @param provider * the provider. * @return true, if successful. */ private boolean findAndAdd(Object provider) { boolean rt = false; for (Entry<Class<?>, ProvidersMap> e : categories.entrySet()) { if (e.getKey().isAssignableFrom(provider.getClass())) { rt |= e.getValue().addProvider(provider); } } return rt; } } /** * The Class ProvidersMap. */ private static class ProvidersMap { // -- TODO: providers ordering support /** * The providers. */ Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>(); /** * Adds the provider. * * @param provider * the provider. * @return true, if successful. */ boolean addProvider(Object provider) { return providers.put(provider.getClass(), provider) != null; } /** * Gets the provider classes. * * @return the provider classes. */ Iterator<Class<?>> getProviderClasses() { return providers.keySet().iterator(); } // -- TODO ordering /** * Gets the providers. * * @param userOrdering * the user ordering. * @return the providers. */ Iterator<?> getProviders(boolean userOrdering) { return providers.values().iterator(); } } /** * The Class FilteredIterator. */ private static class FilteredIterator<E> implements Iterator<E> { /** * The filter. */ private Filter filter; /** * The backend. */ private Iterator<E> backend; /** * The next obj. */ private E nextObj; /** * Instantiates a new filtered iterator. * * @param filter * the filter. * @param backend * the backend. */ public FilteredIterator(Filter filter, Iterator<E> backend) { this.filter = filter; this.backend = backend; findNext(); } /** * Next. * * @return the e. */ public E next() { if (nextObj == null) { throw new NoSuchElementException(); } E tmp = nextObj; findNext(); return tmp; } /** * Checks for next. * * @return true, if successful. */ public boolean hasNext() { return nextObj != null; } /** * Removes the. */ public void remove() { throw new UnsupportedOperationException(); } /** * Sets nextObj to a next provider matching the criterion given by the * filter. */ private void findNext() { nextObj = null; while (backend.hasNext()) { E o = backend.next(); if (filter.filter(o)) { nextObj = o; return; } } } } }