package sk.stuba.fiit.perconik.core.services.listeners;
import javax.annotation.Nullable;
import sk.stuba.fiit.perconik.core.IllegalListenerClassException;
import sk.stuba.fiit.perconik.core.Listener;
import sk.stuba.fiit.perconik.core.services.AbstractProvider;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Throwables.propagate;
import static sk.stuba.fiit.perconik.utilities.MoreThrowables.initializeSuppressor;
/**
* An abstract implementation of {@link ListenerProvider}. This class
* implements the listener providing mechanism based on an underlying
* {@code ClassLoader} of standard Java classes.
*
* TODO doc providing process, class loading / instantiation
*
* @author Pavol Zbell
* @since 1.0
*/
public abstract class AbstractListenerProvider extends AbstractProvider implements ListenerProvider {
// TODO add javadocs
/**
* Constructor for use by subclasses.
*/
protected AbstractListenerProvider() {}
protected abstract ClassLoader loader();
protected final Class<?> load(final String name) throws ClassNotFoundException {
checkArgument(!name.isEmpty());
return this.loader().loadClass(name);
}
protected final static Class<? extends Listener> cast(final Class<?> implementation) {
if (!Listener.class.isAssignableFrom(implementation)) {
throw new IllegalListenerClassException("Class " + implementation.getName() + " is not assignable to " + Listener.class.getName());
}
if (implementation.isInterface() || implementation.isAnnotation()) {
throw new IllegalListenerClassException("Type " + implementation.getName() + " can not be an interface or an annotation");
}
return implementation.asSubclass(Listener.class);
}
protected final ListenerProvider parentOrFailure() {
ListenerProvider parent = this.parent();
if (parent == null) {
throw new IllegalStateException("Provider hierarchy root reached");
}
return parent;
}
protected final <L extends Listener> L parentForClass(final Class<L> implementation, @Nullable final Exception cause) {
try {
return this.parentOrFailure().forClass(implementation);
} catch (Exception failure) {
throw propagate(initializeSuppressor(failure, cause));
}
}
protected final Class<? extends Listener> parentLoadClass(final String name, @Nullable final Exception cause) {
try {
return this.parentOrFailure().loadClass(name);
} catch (Exception failure) {
throw propagate(initializeSuppressor(failure, cause));
}
}
}