org.jtrim2.access.AbstractAccessToken Maven / Gradle / Ivy
package org.jtrim2.access;
import java.util.concurrent.TimeUnit;
import org.jtrim2.cancel.CancellationToken;
import org.jtrim2.event.EventListeners;
import org.jtrim2.event.ListenerRef;
import org.jtrim2.event.OneShotListenerManager;
/**
* A convenient base class for {@link AccessToken} implementations.
*
* This class implements the {@code addTerminateListener} listener method but
* subclasses need to call the {@code #notifyReleaseListeners()} method
* after the {@code AccessToken} was released. This abstract class
* provides a safe and robust handling of release listeners. The provided
* implementation will guarantee that listeners will not be notified multiple
* times and will be automatically unregistered after they have been notified
* (allowing the listeners to be garbage collected, even if not unregistered
* manually).
*
* This class also adds a simple implementation for the
* {@link #awaitRelease(CancellationToken) awaitRelease(CancellationToken)}
* method which relies on the other {@code awaitRelease} method (the one with
* the timeout argument).
*
* @param the type of the access ID (see
* {@link AccessToken#getAccessID() getAccessID()})
*/
public abstract class AbstractAccessToken
implements
AccessToken {
private final OneShotListenerManager listeners;
/**
* Initializes the {@code AbstractAccessToken}.
*/
public AbstractAccessToken() {
this.listeners = new OneShotListenerManager<>();
}
/**
* Notifies the currently registered release listeners. This method may
* only be called if this {@code AccessToken} is already in the released
* state (i.e.: {@link #isReleased() isReleased()} returns {@code true}.
* Note that once a {@code TaskExecutorService} is in the released state it
* must remain in the terminated state forever after. The
* {@code AbstractAccessToken} actually relies on this property for
* correctness.
*
* If called after this token is already in released state, this method is
* idempotent.
*/
protected final void notifyReleaseListeners() {
if (!isReleased()) {
throw new IllegalStateException(
"May only be called in the terminated state.");
}
EventListeners.dispatchRunnable(listeners);
}
/**
* {@inheritDoc }
*
* Implementation note: Listeners added by this method will be
* automatically unregistered after they have been notified.
*/
@Override
public ListenerRef addReleaseListener(Runnable listener) {
return listeners.registerOrNotifyListener(listener);
}
/**
* {@inheritDoc }
*
* Implementation note: This method simply repeatedly calls the
* {@link #tryAwaitRelease(CancellationToken, long, TimeUnit) tryAwaitRelease(CancellationToken, long, TimeUnit)}
* method until it returns {@code true}.
*/
@Override
public void awaitRelease(CancellationToken cancelToken) {
while (!tryAwaitRelease(cancelToken, Long.MAX_VALUE, TimeUnit.NANOSECONDS)) {
// Repeat until it has been released, or throws an exception.
}
}
}