123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962 |
- /* ServiceRegistry.java -- A simple registry for service providers.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package javax.imageio.spi;
- import gnu.classpath.ServiceFactory;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.HashSet;
- import java.util.IdentityHashMap;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.Map;
- import java.util.NoSuchElementException;
- import java.util.Set;
- /**
- * A registry for service providers.
- *
- * @since 1.4
- *
- * @author Michael Koch (konqueror@gmx.de)
- * @author Sascha Brawer (brawer@dandelis.ch)
- */
- public class ServiceRegistry
- {
- // Package-private to avoid a trampoline.
- /**
- * The service categories of this registry.
- *
- * <p>Note that we expect that only very few categories will
- * typically be used with a registry. The most common case will be
- * one, it seems unlikely that any registry would contain more than
- * five or six categories. Therefore, we intentionally avoid the
- * overhead of a HashMap.
- *
- * @see #providers
- */
- final Class[] categories;
- /**
- * The registered providers for each service category, indexed by
- * the same index as the {@link #categories} array. If no provider
- * is registered for a category, the array entry will be
- * <code>null</code>.
- *
- * <p>Note that we expect that only very few providers will
- * typically be registered for a category. The most common case will
- * be one or two. Therefore, we intentionally avoid the overhead of
- * a HashMap.
- */
- private final LinkedList[] providers;
- /**
- * The ordring constaints for each service category, indexed by the
- * same index as the {@link #categories} array. The constraints for
- * a service category are stored as a <code>Map<Object,
- * Set<Object>></code>, where the Map’s values are
- * those providers that need to come after the key. If no
- * constraints are imposed on the providers of a category, the array
- * entry will be <code>null</code>. If no constraints have been set
- * whatsoever, <code>constraints</code> will be <code>null</code>.
- *
- * <p>Note that we expect that only very few constraints will
- * typically be imposed on a category. The most common case will
- * be zero.
- */
- private IdentityHashMap[] constraints;
- /**
- * Constructs a <code>ServiceRegistry</code> for the specified
- * service categories.
- *
- * @param categories the categories to support
- *
- * @throws IllegalArgumentException if <code>categories</code> is
- * <code>null</code>, or if its {@link Iterator#next()} method
- * returns <code>null</code>.
- *
- * @throws ClassCastException if <code>categories</code> does not
- * iterate over instances of {@link java.lang.Class}.
- */
- public ServiceRegistry(Iterator<Class<?>> categories)
- {
- ArrayList cats = new ArrayList(/* expected size */ 10);
- if (categories == null)
- throw new IllegalArgumentException();
- while (categories.hasNext())
- {
- Class cat = (Class) categories.next();
- if (cat == null)
- throw new IllegalArgumentException();
- cats.add(cat);
- }
- int numCats = cats.size();
- this.categories = (Class[]) cats.toArray(new Class[numCats]);
- this.providers = new LinkedList[numCats];
- }
- /**
- * Finds service providers that are implementing the specified
- * Service Provider Interface.
- *
- * <p><b>On-demand loading:</b> Loading and initializing service
- * providers is delayed as much as possible. The rationale is that
- * typical clients will iterate through the set of installed service
- * providers until one is found that matches some criteria (like
- * supported formats, or quality of service). In such scenarios, it
- * might make sense to install only the frequently needed service
- * providers on the local machine. More exotic providers can be put
- * onto a server; the server will only be contacted when no suitable
- * service could be found locally.</p>
- *
- * <p><b>Security considerations:</b> Any loaded service providers
- * are loaded through the specified ClassLoader, or the system
- * ClassLoader if <code>classLoader</code> is
- * <code>null</code>. When <code>lookupProviders</code> is called,
- * the current {@link java.security.AccessControlContext} gets
- * recorded. This captured security context will determine the
- * permissions when services get loaded via the <code>next()</code>
- * method of the returned <code>Iterator</code>.</p>
- *
- * @param spi the service provider interface which must be
- * implemented by any loaded service providers.
- *
- * @param loader the class loader that will be used to load the
- * service providers, or <code>null</code> for the system class
- * loader. For using the context class loader, see {@link
- * #lookupProviders(Class)}.
- *
- * @return an iterator over instances of <code>spi</code>.
- *
- * @throws IllegalArgumentException if <code>spi</code> is
- * <code>null</code>.
- */
- public static <T> Iterator<T> lookupProviders(Class<T> spi,
- ClassLoader loader)
- {
- return ServiceFactory.lookupProviders(spi, loader);
- }
- /**
- * Finds service providers that are implementing the specified
- * Service Provider Interface, using the context class loader
- * for loading providers.
- *
- * @param spi the service provider interface which must be
- * implemented by any loaded service providers.
- *
- * @return an iterator over instances of <code>spi</code>.
- *
- * @throws IllegalArgumentException if <code>spi</code> is
- * <code>null</code>.
- *
- * @see #lookupProviders(Class, ClassLoader)
- */
- public static <T> Iterator<T> lookupProviders(Class<T> spi)
- {
- return ServiceFactory.lookupProviders(spi);
- }
- /**
- * Returns an iterator over all service categories.
- *
- * @return an unmodifiable {@link
- * java.util.Iterator}<{@link java.lang.Class}>.
- */
- public Iterator<Class<?>> getCategories()
- {
- return new Iterator()
- {
- int index = -1;
- public boolean hasNext()
- {
- return index < categories.length - 1;
- }
- public Object next()
- {
- if (!hasNext())
- throw new NoSuchElementException();
- return categories[++index];
- }
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
- };
- }
- /**
- * Registers a provider for a service category which is specified by
- * the class-internal category ID.
- *
- * @param provider the service provider to be registered.
- *
- * @param cat the service category, which is identified by an index
- * into the {@link #categories} array.
- *
- * @return <code>true</code> if <code>provider</code> is the first
- * provider that gets registered for the specified service category;
- * <code>false</code> if other providers have already been
- * registered for the same servide category.
- *
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code>.
- *
- * @throws ClassCastException if <code>provider</code> does not
- * implement the specified service provider interface.
- */
- private synchronized boolean registerServiceProvider(Object provider,
- int cat)
- {
- LinkedList provs;
- boolean result;
- Class category;
- if (provider == null)
- throw new IllegalArgumentException();
- category = categories[cat];
- if (!category.isInstance(provider))
- throw new ClassCastException(category.getName());
- provs = providers[cat];
- if (provs == null)
- {
- result = true;
- provs = providers[cat] = new LinkedList();
- }
- else
- result = false;
- provs.add(provider);
- if (provider instanceof RegisterableService)
- ((RegisterableService) provider).onRegistration(this, category);
- return result;
- }
- /**
- * Registers a provider for the specified service category.
- *
- * <p>If <code>provider</code> implements the {@link
- * RegisterableService} interface, its {@link
- * RegisterableService#onRegistration onRegistration} method is
- * invoked in order to inform the provider about the addition to
- * this registry.
- *
- * @param provider the service provider to be registered.
- *
- * @param category the service category under which
- * <code>provider</code> shall be registered.
- *
- * @return <code>true</code> if <code>provider</code> is the first
- * provider that gets registered for the specified service category;
- * <code>false</code> if other providers have already been
- * registered for the same servide category.
- *
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code>, or if <code>category</code> is not among the
- * categories passed to the {@linkplain #ServiceRegistry(Iterator)
- * constructor} of this ServiceRegistry.
- *
- * @throws ClassCastException if <code>provider</code> does not
- * implement <code>category</code>.
- */
- public synchronized <T> boolean registerServiceProvider(T provider,
- Class<T> category)
- {
- for (int i = 0; i < categories.length; i++)
- if (categories[i] == category)
- return registerServiceProvider(provider, i);
- throw new IllegalArgumentException();
- }
- /**
- * Registers a provider under all service categories it
- * implements.
- *
- * <p>If <code>provider</code> implements the {@link
- * RegisterableService} interface, its {@link
- * RegisterableService#onRegistration onRegistration} method is
- * invoked in order to inform the provider about the addition to
- * this registry. If <code>provider</code> implements several
- * service categories, <code>onRegistration</code> gets called
- * multiple times.
- *
- * @param provider the service provider to be registered.
- *
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code>, or if <code>provider</code> does not implement
- * any of the service categories passed to the {@linkplain
- * #ServiceRegistry(Iterator) constructor} of this ServiceRegistry.
- */
- public synchronized void registerServiceProvider(Object provider)
- {
- boolean ok = false;
- if (provider == null)
- throw new IllegalArgumentException();
- for (int i = 0; i < categories.length; i++)
- if (categories[i].isInstance(provider))
- {
- ok = true;
- registerServiceProvider(provider, i);
- }
- if (!ok)
- throw new IllegalArgumentException();
- }
- /**
- * Registers a number of providers under all service categories they
- * implement.
- *
- * <p>If a provider implements the {@link RegisterableService}
- * interface, its {@link RegisterableService#onRegistration
- * onRegistration} method is invoked in order to inform the provider
- * about the addition to this registry. If <code>provider</code>
- * implements several service categories,
- * <code>onRegistration</code> gets called multiple times.
- *
- * @throws IllegalArgumentException if <code>providers</code> is
- * <code>null</code>, if any iterated provider is <code>null</code>,
- * or if some iterated provider does not implement any of the
- * service categories passed to the {@linkplain
- * #ServiceRegistry(Iterator) constructor} of this
- * <code>ServiceRegistry</code>.
- */
- public synchronized void registerServiceProviders(Iterator<?> providers)
- {
- if (providers == null)
- throw new IllegalArgumentException();
- while (providers.hasNext())
- registerServiceProvider(providers.next());
- }
- /**
- * De-registers a provider for a service category which is specified
- * by the class-internal category ID.
- *
- * @param provider the service provider to be registered.
- *
- * @param cat the service category, which is identified by an index
- * into the {@link #categories} array.
- *
- * @return <code>true</code> if <code>provider</code> was previously
- * registered for the specified service category; <code>false</code>
- * if if the provider had not been registered.
- *
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code>.
- *
- * @throws ClassCastException if <code>provider</code> does not
- * implement the specified service provider interface.
- */
- private synchronized boolean deregisterServiceProvider(Object provider,
- int cat)
- {
- LinkedList provs;
- boolean result;
- Class category;
- if (provider == null)
- throw new IllegalArgumentException();
- category = categories[cat];
- if (!category.isInstance(provider))
- throw new ClassCastException(category.getName());
- provs = providers[cat];
- if (provs == null)
- return false;
- result = provs.remove(provider);
- if (provs.isEmpty())
- providers[cat] = null;
- if (result && (provider instanceof RegisterableService))
- ((RegisterableService) provider).onDeregistration(this, category);
- return result;
- }
- /**
- * De-registers a provider for the specified service category.
- *
- * <p>If <code>provider</code> implements the {@link
- * RegisterableService} interface, its {@link
- * RegisterableService#onDeregistration onDeregistration} method is
- * invoked in order to inform the provider about the removal from
- * this registry.
- *
- * @param provider the service provider to be de-registered.
- *
- * @param category the service category from which
- * <code>provider</code> shall be de-registered.
- *
- * @return <code>true</code> if <code>provider</code> was previously
- * registered for the specified service category; <code>false</code>
- * if if the provider had not been registered.
- *
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code>, or if <code>category</code> is not among the
- * categories passed to the {@linkplain #ServiceRegistry(Iterator)
- * constructor} of this ServiceRegistry.
- *
- * @throws ClassCastException if <code>provider</code> does not
- * implement <code>category</code>.
- */
- public synchronized <T> boolean deregisterServiceProvider(T provider,
- Class<T> category)
- {
- for (int i = 0; i < categories.length; i++)
- if (categories[i] == category)
- return deregisterServiceProvider(provider, i);
- throw new IllegalArgumentException();
- }
- /**
- * De-registers a provider from all service categories it
- * implements.
- *
- * <p>If <code>provider</code> implements the {@link
- * RegisterableService} interface, its {@link
- * RegisterableService#onDeregistration onDeregistration} method is
- * invoked in order to inform the provider about the removal from
- * this registry. If <code>provider</code> implements several
- * service categories, <code>onDeregistration</code> gets called
- * multiple times.</p>
- *
- * @param provider the service provider to be de-registered.
- *
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code>, or if <code>provider</code> does not implement
- * any of the service categories passed to the {@linkplain
- * #ServiceRegistry(Iterator) constructor} of this
- * <code>ServiceRegistry</code>.
- */
- public synchronized void deregisterServiceProvider(Object provider)
- {
- boolean ok = false;
- if (provider == null)
- throw new IllegalArgumentException();
- for (int i = 0; i < categories.length; i++)
- if (categories[i].isInstance(provider))
- {
- ok = true;
- deregisterServiceProvider(provider, i);
- }
- if (!ok)
- throw new IllegalArgumentException();
- }
- /**
- * De-registers all providers which have been registered for the
- * specified service category.
- *
- * <p>If a provider implements the {@link RegisterableService}
- * interface, its {@link RegisterableService#onDeregistration
- * onDeregistration} method is invoked in order to inform the
- * provider about the removal from this registry. If the provider
- * implements several service categories,
- * <code>onDeregistration</code> gets called multiple times.
- *
- * @param category the category whose registered providers will be
- * de-registered.
- *
- * @throws IllegalArgumentException if <code>category</code> is not
- * among the categories passed to the {@linkplain
- * #ServiceRegistry(Iterator) constructor} of this
- * <code>ServiceRegistry</code>.
- */
- public synchronized void deregisterAll(Class<?> category)
- {
- boolean ok = false;
- for (int i = 0; i < categories.length; i++)
- {
- if (categories[i] != category)
- continue;
- ok = true;
- while (providers[i] != null)
- deregisterServiceProvider(providers[i].get(0), i);
- }
- if (!ok)
- throw new IllegalArgumentException();
- }
- /**
- * De-registers all service providers.
- *
- * <p>If a provider implements the {@link RegisterableService}
- * interface, its {@link RegisterableService#onDeregistration
- * onDeregistration} method is invoked in order to inform the
- * provider about the removal from this registry. If the provider
- * implements several service categories,
- * <code>onDeregistration</code> gets called multiple times.
- */
- public synchronized void deregisterAll()
- {
- for (int i = 0; i < categories.length; i++)
- while (providers[i] != null)
- deregisterServiceProvider(providers[i].get(0), i);
- }
- /**
- * Called by the Virtual Machine when it detects that this
- * <code>ServiceRegistry</code> has become garbage. De-registers all
- * service providers, which will cause those that implement {@link
- * RegisterableService} to receive a {@link
- * RegisterableService#onDeregistration onDeregistration}
- * notification.
- */
- public void finalize()
- throws Throwable
- {
- super.finalize();
- deregisterAll();
- }
- /**
- * Determines whether a provider has been registered with this
- * registry.
- *
- * @return <code>true</code> if <code>provider</code> has been
- * registered under any service category; <code>false</code> if
- * it is not registered.
- *
- * @throws IllegalArgumentException if <code>provider</code> is
- * <code>null</code>.
- */
- public synchronized boolean contains(Object provider)
- {
- if (provider == null)
- throw new IllegalArgumentException();
- // Note that contains is rather unlikely to be ever called,
- // so it would be wasteful to keep a special data structure
- // (such as a HashSet) for making it a fast operation.
- for (int i = 0; i < providers.length; i++)
- {
- // If provider does not implement categories[i],
- // it would not have been possible to register it there.
- // In that case, it would be pointless to look there.
- if (!categories[i].isInstance(provider))
- continue;
- // But if the list of registered providers contains provider,
- // we have found it.
- LinkedList p = providers[i];
- if (p != null && p.contains(provider))
- return true;
- }
- return false;
- }
- /**
- * Returns the index in {@link #categories} occupied by the
- * specified service category.
- *
- * @throws IllegalArgumentException if <code>category</code> is not
- * among the categories passed to the {@linkplain
- * #ServiceRegistry(Iterator) constructor} of this ServiceRegistry.
- */
- private int getCategoryID(Class category)
- {
- for (int i = 0; i < categories.length; i++)
- if (categories[i] == category)
- return i;
- throw new IllegalArgumentException();
- }
- /**
- * Retrieves all providers that have been registered for the
- * specified service category.
- *
- * @param category the service category whose providers are
- * to be retrieved.
- *
- * @param useOrdering <code>true</code> in order to retrieve the
- * providers in an order imposed by the {@linkplain #setOrdering
- * ordering constraints}; <code>false</code> in order to retrieve
- * the providers in any order.
- *
- * @throws IllegalArgumentException if <code>category</code> is not
- * among the categories passed to the {@linkplain
- * #ServiceRegistry(Iterator) constructor} of this
- * <code>ServiceRegistry</code>.
- *
- * @see #getServiceProviders(Class, Filter, boolean)
- */
- public <T> Iterator<T> getServiceProviders(Class<T> category,
- boolean useOrdering)
- {
- return getServiceProviders(category, null, useOrdering);
- }
- /**
- * Retrieves all providers that have been registered for the
- * specified service category and that satisfy the criteria
- * of a custom filter.
- *
- * @param category the service category whose providers are
- * to be retrieved.
- *
- * @param filter a custom filter, or <code>null</code> to
- * retrieve all registered providers for the specified
- * category.
- *
- * @param useOrdering <code>true</code> in order to retrieve the
- * providers in an order imposed by the {@linkplain #setOrdering
- * ordering constraints}; <code>false</code> in order to retrieve
- * the providers in any order.
- *
- * @throws IllegalArgumentException if <code>category</code> is not
- * among the categories passed to the {@linkplain
- * #ServiceRegistry(Iterator) constructor} of this
- * <code>ServiceRegistry</code>.
- */
- public synchronized <T> Iterator<T> getServiceProviders(Class<T> category,
- Filter filter,
- boolean useOrdering)
- {
- int catid;
- LinkedList provs;
- ArrayList result;
- catid = getCategoryID(category);
- provs = providers[catid];
- if (provs == null)
- return Collections.EMPTY_LIST.iterator();
- result = new ArrayList(provs.size());
- for (Iterator iter = provs.iterator(); iter.hasNext();)
- {
- Object provider = iter.next();
- if (filter == null || filter.filter(provider))
- result.add(provider);
- }
- // If we are supposed to obey ordering constraints, and
- // if any constraints have been imposed on the specified
- // service category, sort the result.
- if (useOrdering && constraints != null)
- {
- final Map cons = constraints[catid];
- if (cons != null)
- Collections.sort(result, new Comparator()
- {
- public int compare(Object o1, Object o2)
- {
- Set s;
- if (o1 == o2)
- return 0;
- s = (Set) cons.get(o1);
- if (s != null && s.contains(o2))
- return -1; // o1 < o2
- s = (Set) cons.get(o2);
- if (s != null && s.contains(o1))
- return 1; // o1 > o2
- return 0; // o1 == o2
- }
- });
- }
- return result.iterator();
- }
- /**
- * Returns one of the service providers that is a subclass of the
- * specified class.
- *
- * @param providerClass a class to search for.
- */
- public synchronized <T> T getServiceProviderByClass(Class<T> providerClass)
- {
- if (providerClass == null)
- throw new IllegalArgumentException();
- // Note that the method getServiceProviderByClass is rather
- // unlikely to be ever called, so it would be wasteful to keep a
- // special data structure for making it a fast operation.
- for (int cat = 0; cat < categories.length; cat++)
- {
- if (!categories[cat].isAssignableFrom(providerClass))
- continue;
- LinkedList provs = providers[cat];
- if (provs == null)
- continue;
- for (Iterator iter = provs.iterator(); iter.hasNext();)
- {
- Object provider = iter.next();
- if (providerClass.isInstance(provider))
- return (T) provider;
- }
- }
- return null;
- }
- /**
- * Adds an ordering constraint on service providers.
- *
- * @param category the service category to which an ordering
- * constraint is to be added.
- *
- * @param firstProvider the provider which is supposed to come before
- * <code>second</code>.
- *
- * @param secondProvider the provider which is supposed to come after
- * <code>first</code>.
- *
- * @throws IllegalArgumentException if <code>first</code> and
- * <code>second</code> are referring to the same object, or if one
- * of them is <code>null</code>.
- *
- * @see #unsetOrdering
- * @see #getServiceProviders(Class, Filter, boolean)
- */
- public synchronized <T> boolean setOrdering(Class<T> category,
- T firstProvider,
- T secondProvider)
- {
- return addConstraint(getCategoryID(category), firstProvider,
- secondProvider);
- }
- /**
- * Removes an ordering constraint on service providers.
- *
- * @param category the service category from which an ordering
- * constraint is to be removed.
- *
- * @param firstProvider the provider which is supposed to come before
- * <code>second</code>.
- *
- * @param secondProvider the provider which is supposed to come after
- * <code>first</code>.
- *
- * @throws IllegalArgumentException if <code>first</code> and
- * <code>second</code> are referring to the same object, or if one
- * of them is <code>null</code>.
- *
- * @see #setOrdering
- */
- public synchronized <T> boolean unsetOrdering(Class<T> category,
- T firstProvider,
- T secondProvider)
- {
- return removeConstraint(getCategoryID(category),
- firstProvider, secondProvider);
- }
- /**
- * Adds an ordering constraint on service providers.
- *
- * @param catid the service category ID, which is the
- * category’s index into the {@link #categories} array.
- *
- * @param first the provider which is supposed to come before
- * <code>second</code>.
- *
- * @param second the provider which is supposed to come after
- * <code>first</code>.
- *
- * @throws IllegalArgumentException if <code>first</code> and
- * <code>second</code> are referring to the same object, or if one
- * of them is <code>null</code>.
- */
- private boolean addConstraint(int catid, Object first, Object second)
- {
- Set s;
- IdentityHashMap cons;
- // Also checks argument validity.
- removeConstraint(catid, second, first);
- if (constraints == null)
- constraints = new IdentityHashMap[categories.length];
- cons = constraints[catid];
- if (cons == null)
- cons = constraints[catid] = new IdentityHashMap();
- s = (Set) cons.get(first);
- if (s == null)
- cons.put(first, s = new HashSet());
- return s.add(second);
- }
- /**
- * Removes an ordering constraint on service providers.
- *
- * @param catid the service category ID, which is the
- * category’s index into the {@link #categories} array.
- *
- * @param first the provider which is supposed to come before
- * <code>second</code>.
- *
- * @param second the provider which is supposed to come after
- * <code>first</code>.
- *
- * @throws IllegalArgumentException if <code>first</code> and
- * <code>second</code> are referring to the same object, or if one
- * of them is <code>null</code>.
- */
- private boolean removeConstraint(int catid, Object first, Object second)
- {
- Collection s;
- IdentityHashMap cons;
- if (first == null || second == null || first == second)
- throw new IllegalArgumentException();
- if (constraints == null)
- return false;
- cons = constraints[catid];
- if (cons == null)
- return false;
- s = (Collection) cons.get(first);
- if (s == null)
- return false;
- if (!s.remove(second))
- return false;
- // If we removed the last constraint for a service category,
- // we can get free some memory.
- if (cons.isEmpty())
- {
- constraints[catid] = null;
- boolean anyConstraints = false;
- for (int i = 0; i < constraints.length; i++)
- {
- if (constraints[i] != null)
- {
- anyConstraints = true;
- break;
- }
- }
- if (!anyConstraints)
- constraints = null;
- }
- return true;
- }
- /**
- * A filter for selecting service providers that match custom
- * criteria.
- *
- * @see ServiceRegistry#getServiceProviders(Class, Filter,
- * boolean)
- *
- * @since 1.4
- *
- * @author Michael Koch (konqueror@gmx.de)
- * @author Sascha Brawer (brawer@dandelis.ch)
- */
- public static interface Filter
- {
- /**
- * Checks whether the specified service provider matches the
- * constraints of this Filter.
- *
- * @param provider the service provider in question.
- *
- * @return <code>true</code> if <code>provider</code> matches the
- * criteria; <code>false</code> if it does not match.
- */
- boolean filter(Object provider);
- }
- }
|