package net.jxta.endpoint;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class MessengerStateBarrier implements MessengerStateListener {
public static final int NO_MATCH = 0;
private final CountDownLatch latch;
private final int awaitedState;
private AtomicInteger matchingState;
private AtomicBoolean expired;
public MessengerStateBarrier(int awaitedState) {
this.latch = new CountDownLatch(1);
this.awaitedState = awaitedState;
this.matchingState = new AtomicInteger(0);
this.expired = new AtomicBoolean(false);
}
public boolean messengerStateChanged(int newState) {
if(expired.get()) {
return false;
}
if((newState & awaitedState) != 0) {
// ensures that the value is only changed once
matchingState.compareAndSet(0, newState);
expired.set(true);
latch.countDown();
return false;
}
return true;
}
/**
* Waits for the provided number of milliseconds for the current state of the
* Messenger to match one of the expected states.
*
* @param timeoutInMillis the number of milliseconds to wait for the messenger
* to be in one of the expected states. A timeout of 0 indicates that the thread
* should wait indefinitely. A timeout of less than 0 is illegal.
* @return the matching state of the messenger, if it transitioned to one of
* the expected states within the specified time interval. If the timeout expires,
* NO_MATCH is returned.
* @throws InterruptedException if the thread is interrupted while waiting for
* a match.
*/
public int awaitMatch(long timeoutInMillis) throws InterruptedException {
if(timeoutInMillis < 0) {
throw new IllegalArgumentException(String.format("timeoutInMillis is negative: given %d", timeoutInMillis));
} else if(timeoutInMillis == 0) {
latch.await();
return matchingState.get();
} else if(latch.await(timeoutInMillis, TimeUnit.MILLISECONDS)) {
return matchingState.get();
} else {
return NO_MATCH;
}
}
public void expire() {
expired.set(true);
}
}