/* * 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. */ 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> 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 Iterator lookupProviders(Class 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 Iterator lookupProviders(Class 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 boolean registerServiceProvider(T provider, Class 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 boolean deregisterServiceProvider(T provider, Class 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 Iterator getServiceProviders(Class category, Filter filter, boolean useOrdering) { return new FilteredIterator(filter, (Iterator)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 Iterator getServiceProviders(Class category, boolean useOrdering) { return (Iterator)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 getServiceProviderByClass(Class 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 boolean setOrdering(Class 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 boolean unsetOrdering(Class 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 throws 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> getCategories() { return categories.list(); } /** * The ServiceRegistry.Filter interface is used by * ServiceRegistry.getServiceProviders to filter providers according * to the specified criterion. */ 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, ProvidersMap> categories = new HashMap, 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> 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 category is * null 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 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, 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, Object> providers = new HashMap, 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> 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 implements Iterator { /** The filter. */ private Filter filter; /** The backend. */ private Iterator 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 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; } } } } }