blob: 1a18b021e4bb059c742fce04a57d882014c87fb2 [file] [log] [blame]
/*
* 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<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 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<Class<?>> 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<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 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;
}
}
}
}
}