/** * Manually deregister factories. * * <p>Used to facilitate integration with other plug-in systems, such as OSGi or Spring, that * block CLASSPATH visibility of {@link ServiceLoader} implementation registration. * * @param factories */ public void deregisterFactories(final Iterable<?> factories) { ensureArgumentNonNull("factories", factories); factories.forEach(this::deregisterFactory); }
/** * Manually register factories. * * <p>Used to facilitate integration with other plug-in systems, such as OSGi or Spring, that * block CLASSPATH visibility of {@link ServiceLoader} implementation registration. * * @param factories */ public void registerFactories(final Iterable<?> factories) { ensureArgumentNonNull("factories", factories); factories.forEach(this::registerFactory); }
/** * Manually register factories. * * <p>Used to facilitate integration with other plug-in systems, such as OSGi or Spring, that * block CLASSPATH visibility of {@link ServiceLoader} implementation registration. * * @param factories */ public void registerFactories(final Iterator<?> factories) { ensureArgumentNonNull("factories", factories); factories.forEachRemaining(this::registerFactory); }
/** * Manually deregister factories. * * <p>Used to facilitate integration with other plug-in systems, such as OSGi or Spring, that * block CLASSPATH visibility of {@link ServiceLoader} implementation registration. * * @param factories */ public void deregisterFactories(final Iterator<?> factories) { ensureArgumentNonNull("factories", factories); factories.forEachRemaining(this::deregisterFactory); }
public <S> Optional<S> getInstanceOfType(Class<S> type) { ensureArgumentNonNull("type", type); @SuppressWarnings("unchecked") S instance = (S) instancesByType.get(type); return Optional.ofNullable(instance); }
/** @deprecated Replaced with {@link #setOrdering(Class, boolean, Predicate, Predicate)} */ @Deprecated public <T> boolean setOrdering( final Class<T> base, final boolean set, final ServiceRegistry.Filter filter1, final ServiceRegistry.Filter filter2) { ensureArgumentNonNull("filter1", filter1); ensureArgumentNonNull("filter2", filter2); return setOrdering(base, set, (Predicate<T>) filter1::filter, filter2::filter); }
/** * Finds the {@link InstanceRegistry} for the specified category. Throws an exception if that * category was not registered. */ private <T> InstanceRegistry<T> instanceRegistry(final Class<T> category) { ensureArgumentNonNull("category", category); @SuppressWarnings("unchecked") // during construction, we registered `InstanceRegistry<T>` for `Class<T>`, so this cast is // save InstanceRegistry<T> registry = (InstanceRegistry<T>) categories.get(category); if (registry == null) { throw new IllegalArgumentException("The category '" + category + "' is not registered"); } return registry; }
/** @see CategoryRegistry#clearOrder(Class, Object, Object) */ public boolean clearOrder(T firstInstance, T secondInstance) { ensureArgumentNonNull("firstInstance", firstInstance); ensureArgumentNonNull("secondInstance", secondInstance); return instancesByType.containsKey(firstInstance.getClass()) && instancesByType.containsKey(secondInstance.getClass()) // if both are contained, set the order && orderedInstances.clearOrder(firstInstance, secondInstance); }
/** * Manually deregister a factory * * <p>Used to facilitate integration with other plug-in systems, such as OSGi or Spring, that * block CLASSPATH visibility of {@link ServiceLoader} implementation registration. * * @param factory * @param category * @return */ public <T> boolean deregisterFactory(final T factory, final Class<T> category) { ensureArgumentNonNull("factory", factory); ensureArgumentNonNull("category", category); if (!category.isAssignableFrom(factory.getClass())) { throw new ClassCastException(); } return registry.deregisterInstance(factory, category); }
/** * Orders the specified instances, so that the first appears before the second when {@link * #streamInstances(Class, boolean) iterateInstances} is called with {@code useOrder = true}. * * @param category The category to order instances for. * @return {@code true} if this establishes a new order */ public <T> boolean setOrder(Class<T> category, T firstInstance, T secondInstance) { ensureArgumentNonNull("firstInstance", firstInstance); ensureArgumentNonNull("secondInstance", secondInstance); return instanceRegistry(category).setOrder(firstInstance, secondInstance); }
/** @return {true} if an instance of the same type was previously registered */ public boolean deregister(final T instance) { ensureArgumentNonNull("instance", instance); if (instancesByType.containsKey(instance.getClass())) { deregisterByType(instance); return true; } else { return false; } }
/** * Removes the ordering between the specified instances, so that the first no longer appears * before the second when {@link #streamInstances(Class, boolean) iterateInstances} is called * with {@code useOrder = true}. * * @param category The category to clear instance order for. * @return {@code true} if that ordering existed before */ public <T> boolean clearOrder(Class<T> category, T firstInstance, T secondInstance) { ensureArgumentNonNull("firstInstance", firstInstance); ensureArgumentNonNull("secondInstance", secondInstance); return instanceRegistry(category).clearOrder(firstInstance, secondInstance); }
/** * Creates a new registry with the specified Registers the specified category. If the same * category is registered multiple times, all instances previously registered for that category * are lost. * * @param factoryRegistry The {@link FactoryRegistry} this registry belongs to. * @param categories The categories to register; must not be {@code null} but can contain {@code * null}. */ public CategoryRegistry( final FactoryRegistry factoryRegistry, final Iterable<Class<?>> categories) { ensureArgumentNonNull("factoryRegistry", factoryRegistry); ensureArgumentNonNull("categories", categories); // use an unmodifiable map to guarantee immutability this.categories = stream(categories) .collect( collectingAndThen( toMap( category -> category, category -> new InstanceRegistry<>( factoryRegistry, category), (firstRegistry, secondRegistry) -> secondRegistry), Collections::unmodifiableMap)); }
/** * Returns an arbitrary instance that extends/implements the specified type that is filed under * a category that also extends/implements that type. * * @param type The type to look up. * @return An instance if one was found. */ public <S> Optional<S> getInstanceOfType(Class<S> type) { ensureArgumentNonNull("type", type); return streamCategories() .filter(category -> category.isAssignableFrom(type)) .map(this::instanceRegistry) .flatMap(registry -> stream(registry.getInstanceOfType(type))) .findFirst(); }
/** * Registers the specified instance under all categories that are supertypes of the instance. * * @param instance The instance to register. */ @SuppressWarnings("unchecked") public <T> void registerInstance(final T instance) { ensureArgumentNonNull("instance", instance); streamCategories() .filter(category -> category.isAssignableFrom(instance.getClass())) // the cast is correct because the filter above only leaves categories that are // supertypes of `instance` .map(category -> (InstanceRegistry<? super T>) instanceRegistry(category)) .forEach(registry -> registry.register(instance)); }
/** * Deregisters all instances with the same type as the specified one from all categories. * * @param instance The instance to deregister. */ @SuppressWarnings("unchecked") public <T> void deregisterInstance(final T instance) { ensureArgumentNonNull("instance", instance); streamCategories() .filter(category -> category.isAssignableFrom(instance.getClass())) // the cast is correct because the filter above only leaves categories that are // supertypes of `instance` .map(category -> (InstanceRegistry<? super T>) instanceRegistry(category)) .forEach(registry -> registry.deregister(instance)); }
/** * Sets or unsets a pairwise ordering between all factories meeting a criterion. * * <p>For example in the CRS framework ({@link org.geotools.referencing.FactoryFinder}), this is * used for setting ordering between all factories provided by two vendors, or for two * authorities. If one or both factories are not currently registered, or if the desired * ordering is already set/unset, nothing happens and false is returned. * * @param <T> The class represented by the {@code base} argument. * @param base The base category. Only categories {@linkplain Class#isAssignableFrom assignable} * to {@code base} will be processed. * @param set {@code true} for setting the ordering, or {@code false} for unsetting. * @param filter1 Predicate for the preferred factory. * @param filter2 Predicate for the factory to which {@code filter1} is preferred. * @return {@code true} if the ordering changed as a result of this call. */ public <T> boolean setOrdering( final Class<T> base, final boolean set, final Predicate<? super T> filter1, final Predicate<? super T> filter2) { ensureArgumentNonNull("filter1", filter1); ensureArgumentNonNull("filter2", filter2); return registry.streamCategories() .flatMap(category -> streamIfSubtype(category, base)) .map(category -> setOrUnsetOrdering(category, set, filter1, filter2)) .reduce((done1, done2) -> done1 || done2) .orElse(false); }
/** @return {@code true} if this the first instance of its class. */ public boolean register(final T instance) { ensureArgumentNonNull("instance", instance); boolean deregistered = deregisterByType(instance); registerInternal(instance); notifyRegistered(instance); return !deregistered; }