553 lines
16 KiB
Java
553 lines
16 KiB
Java
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|