package sk.stuba.fiit.perconik.core; import java.util.Collection; import java.util.List; import java.util.Set; import com.google.common.collect.SetMultimap; import sk.stuba.fiit.perconik.core.annotations.Internal; import sk.stuba.fiit.perconik.core.services.Services; import sk.stuba.fiit.perconik.core.services.listeners.ListenerClassesSupplier; import sk.stuba.fiit.perconik.core.services.listeners.ListenerManager; import sk.stuba.fiit.perconik.core.services.listeners.ListenerProvider; import sk.stuba.fiit.perconik.core.services.listeners.ListenerService; import sk.stuba.fiit.perconik.utilities.MoreThrowables; import sk.stuba.fiit.perconik.utilities.reflect.Reflections; import static java.util.Arrays.asList; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newLinkedList; import static com.google.common.collect.Sets.newHashSetWithExpectedSize; /** * Static accessor methods pertaining to the listeners core. * * <p>This class provides access to the underlying functionality * of the currently active {@code ListenerService}. * * @see Listener * @see Resources * * @author Pavol Zbell * @since 1.0 */ public final class Listeners { // TODO add javadocs private Listeners() {} static ListenerService service() { return Services.getListenerService(); } static ListenerProvider provider() { return service().getListenerProvider(); } static ListenerManager manager() { return service().getListenerManager(); } public static Listener forClass(final Class<? extends Listener> type) { return provider().forClass(type); } public static void register(final Listener listener) { manager().register(listener); } public static void registerAll(final Listener ... listeners) { registerAll(asList(listeners)); } public static void registerAll(final Iterable<? extends Listener> listeners) { List<Exception> failures = newLinkedList(); ListenerManager manager = manager(); for (Listener listener: listeners) { try { manager.register(listener); } catch (Exception failure) { failures.add(failure); } } if (!failures.isEmpty()) { throw MoreThrowables.initializeSuppressor(new ListenerRegistrationException(), failures); } } public static void registerAll(final ListenerClassesSupplier supplier) { List<Exception> failures = newLinkedList(); ListenerProvider provider = provider(); ListenerManager manager = manager(); for (Class<? extends Listener> implementation: supplier.get()) { Listener listener = provider.forClass(implementation); try { manager.register(listener); } catch (Exception failure) { failures.add(failure); } } if (!failures.isEmpty()) { throw MoreThrowables.initializeSuppressor(new ListenerRegistrationException(), failures); } } public static void unregister(final Listener listener) { manager().unregister(listener); } public static void unregisterAll() { unregisterAll(Listener.class); } public static void unregisterAll(final Class<? extends Listener> type) { manager().unregisterAll(type); } public static Collection<Listener> registered() { return registered(Listener.class); } public static <L extends Listener> Collection<L> registered(final Class<L> type) { return manager().registered(type); } public static SetMultimap<Resource<?>, Listener> registrations() { return manager().registrations(); } public static boolean isRegistered(final Listener listener) { return manager().registered(listener); } public static Set<Class<? extends Listener>> resolveTypes(final Listener listener) { return resolveTypes(listener.getClass()); } public static Set<Class<? extends Listener>> resolveTypes(final Class<? extends Listener> type) { Set<Class<?>> raw = Reflections.collectInterfaces(type); raw.remove(Registrable.class); raw.remove(Listener.class); Set<Class<? extends Listener>> types = newHashSetWithExpectedSize(raw.size()); for (Class<?> supertype: raw) { if (Listener.class.isAssignableFrom(supertype) && !supertype.isAnnotationPresent(Internal.class)) { types.add(supertype.asSubclass(Listener.class)); } } Iterable<Class<? extends Listener>> iterable = newArrayList(types); for (Class<?> a: iterable) { for (Class<?> b: iterable) { if (a != b && a.isAssignableFrom(b)) { types.remove(a); } } } return types; } }