/** * Constructs a new registry for the specified categories. * * @param categories The categories. */ public FactoryRegistry(final Collection<Class<?>> categories) { registry = new CategoryRegistry(this, categories); needScanForPlugins.addAll(categories); }
/** * Removes the ordering between the specified factories, so that the first no longer appears * before the second. * * @param category The category to clear instance order for. * @param firstFactory * @param secondFactory * @return {@code true} if that ordering was previously defined */ public <T> boolean unsetOrdering( final Class<T> category, final T firstFactory, final T secondFactory) { if (firstFactory == secondFactory) { throw new IllegalArgumentException("Factories must not be the same instance."); } return registry.clearOrder(category, firstFactory, secondFactory); } }
/** * 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 */ public void deregisterFactory(final Object factory) { registry.deregisterInstance(factory); }
/** * 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)); }
/** * Returns all instances that were registered with the specified category * * @param category The category for which instances are. * @param useOrder whether to return instances in topological order as specified by {@link * #setOrder} * @return The instances registered for the specified category. */ public <T> Stream<T> streamInstances(final Class<T> category, final boolean useOrder) { return instanceRegistry(category).stream(useOrder); }
public Stream<Class<?>> streamCategories() { return registry.streamCategories(); }
/** * Clear registered factories for a provided category. * * @param category */ public void deregisterAll(Class<?> category) { registry.deregisterInstances(category); }
/** * Manually register 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 */ public void registerFactory(final Object factory) { registry.registerInstance(factory); }
/** * Factories for the provided category type. * * @param category The category to look for. Usually an interface class (not the actual * implementation class). * @param useOrdering true to use provided pairwise orderings * @return factories registered for category * @since 19 */ public <T> Stream<T> getFactories(final Class<T> category, final boolean useOrdering) { return registry.streamInstances(category, useOrdering); }
/** * Instance of category, or null if not available. * * @param category The category to look for. Usually an interface class (not the actual * implementation class). * @return instance, or null of not available * @since 19 */ public <T> T getFactoryByClass(Class<T> category) { return registry.getInstanceOfType(category).orElse(null); }
/** * Define pairwise ordering giving priority to the <code>firstFactory</code> over the <code> * secondFactory</code>. * * @param category * @param firstFactory * @param secondFactory * @return if this call establishes a new order */ public <T> boolean setOrdering( final Class<T> category, final T firstFactory, final T secondFactory) { if (firstFactory == secondFactory) { throw new IllegalArgumentException("Factories must not be the same instance."); } return registry.setOrder(category, firstFactory, secondFactory); }
/** * 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)); }
/** * Registers the specified instance under the specified category. The category itself must * already be registered. * * @param instance The instance to register. * @param category The category to register the instance under. * @return {@code true} if this the first instance of its class. */ public <T> boolean registerInstance(final T instance, final Class<T> category) { return instanceRegistry(category).register(instance); }
/** * Scans for factory plug-ins on the application class path. This method is needed because the * application class path can theoretically change, or additional plug-ins may become available. * Rather than re-scanning the classpath on every invocation of the API, the class path is * scanned automatically only on the first invocation. Clients can call this method to prompt a * re-scan. Thus this method need only be invoked by sophisticated applications which * dynamically make new plug-ins available at runtime. */ public void scanForPlugins() { final Set<ClassLoader> loaders = getClassLoaders(); registry.streamCategories().forEach(category -> scanForPlugins(loaders, category)); }
/** Clear all registered factories. */ public void deregisterAll() { registry.deregisterInstances(); }
/** * Manually register 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 registerFactory(final T factory, final Class<T> category) { if (!category.isAssignableFrom(factory.getClass())) { throw new ClassCastException(); } return registry.registerInstance(factory, category); }
/** * Deregisters all instances registered under the specified category. The category itself remain * registered. * * @param category The category from which to deregister instances. */ public void deregisterInstances(Class<?> category) { instanceRegistry(category).clear(); }
/** * 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(); }
/** * 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); }
/** * Deregisters all instances with the same type as the specified one from the specified * category. The category must be registered. If instances of the same type are registered under * other categories they remain available under them. * * @param instance The instance to deregister. * @param category The category, from which the instance should be removed. * @return {true} if an instance of the same type was previously registered */ public <T> boolean deregisterInstance(final T instance, final Class<T> category) { return instanceRegistry(category).deregister(instance); }