/** * 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)); }
/** * 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)); }
/** @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; } }
/** * 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 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(); }
/** * 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); }
/** * 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); }
public void clear() { Iterator<T> values = instancesByType.values().iterator(); while (values.hasNext()) { T instance = values.next(); values.remove(); orderedInstances.remove(instance); notifyDeregistered(instance); } }
/** @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; }
/** * 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(); }
/** * 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); }
/** @return {true} if an instance of the same type was previously registered */ private boolean deregisterByType(final T instance) { T removed = instancesByType.remove(instance.getClass()); boolean instanceWasRemoved = removed != null; if (instanceWasRemoved) { orderedInstances.remove(removed); notifyDeregistered(removed); } return instanceWasRemoved; }