package sk.stuba.fiit.perconik.core.services.listeners; import java.util.Set; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import sk.stuba.fiit.perconik.core.Listener; import sk.stuba.fiit.perconik.core.Listeners; import sk.stuba.fiit.perconik.core.Resource; import sk.stuba.fiit.perconik.core.ResourceNotRegistredException; import sk.stuba.fiit.perconik.core.resources.DefaultResources; import sk.stuba.fiit.perconik.core.services.AbstractManager; import sk.stuba.fiit.perconik.core.services.resources.ResourceManager; import static com.google.common.cache.CacheBuilder.newBuilder; /** * An abstract implementation of {@link ListenerManager}. This class * implements the listener registration mechanism based on the underlying * {@link ResourceManager}. * * @author Pavol Zbell * @since 1.0 */ public abstract class AbstractListenerManager extends AbstractManager implements ListenerManager { // TODO add javadocs static final int resolvedTypesCacheMaximumSize = 128; private final LoadingCache<Class<? extends Listener>, Set<Class<? extends Listener>>> resolvedTypesCache; /** * Constructor for use by subclasses. */ protected AbstractListenerManager() { this.resolvedTypesCache = newBuilder().maximumSize(resolvedTypesCacheMaximumSize).build(new CacheLoader<Class<? extends Listener>, Set<Class<? extends Listener>>>() { @Override public Set<Class<? extends Listener>> load(final Class<? extends Listener> supertype) throws Exception { return Listeners.resolveTypes(supertype); } }); } protected abstract ResourceManager underlyingResourceManager(); private <L extends Listener> Set<Resource<? super L>> registrables(final L listener) { // safe cast as registrables always fetch resources with listener supertypes @SuppressWarnings("unchecked") Class<L> supertype = (Class<L>) listener.getClass(); ResourceManager manager = this.underlyingResourceManager(); Set<Resource<? super L>> resources = manager.registrables(supertype); for (Class<? extends Listener> type: this.resolvedTypesCache.getUnchecked(supertype)) { if (manager.registrables(type).isEmpty()) { throw new ResourceNotRegistredException("No registred resources for listener implementation " + listener.getClass().getName() + " as " + type.getName()); } } return resources; } public final <L extends Listener> void register(final L listener) { DefaultResources.registerTo(this.registrables(listener), listener); } public final <L extends Listener> void unregister(final L listener) { DefaultResources.unregisterFrom(this.registrables(listener), listener); } }