package net.jxta.impl.endpoint;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import net.jxta.endpoint.Message;
/**
* Simple implementation of {@link MessageWriteListener} that allows code
* to wait for the result of a write, either indefinitely or with a fixed
* timeout. Also takes care of setting the appropriate success or failure
* flags on the associated Message object
*
* @author Iain McGinniss (iain.mcginniss@onedrum.com)
*/
public class AsynchronousMessageWriteListener implements MessageWriteListener {
CountDownLatch completionLatch = new CountDownLatch(1);
private AtomicBoolean complete = new AtomicBoolean(false);
private AtomicBoolean presentedForwrite = new AtomicBoolean(false);
private AtomicReference<Throwable> failureCause = new AtomicReference<Throwable>(null);
private Message message;
public AsynchronousMessageWriteListener(Message message) {
this.message = message;
}
/**
* Awaits the success or failure of this associated message being sent.
* Once this method returns, {@link #wasSuccessful()} can be called.
* @throws InterruptedException if the thread is interrupted while waiting.
*/
public void await() throws InterruptedException {
completionLatch.await();
}
/**
* Awaits the success or failure of this associated message being sent.
* If the method returns true, {@link #wasSuccessful()} can be called.
* Otherwise, the wait timed out and it is not yet known if the message
* has been sent successfully.
* @return whether or not the wait operation timed out.
* @throws InterruptedException if the thread is interrupted while waiting.
*/
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return completionLatch.await(timeout, unit);
}
public boolean isDone() {
return complete.get();
}
/**
* @return whether the message was sent successfully.
* @throws IllegalStateException if the message has not yet been marked as successful or
* not. One must call {@link #isDone()} or {@link #await()} before calling this method.
*/
public boolean wasSuccessful() {
if(!complete.get()) {
throw new IllegalStateException("Message has not yet been marked as successful or not");
}
return failureCause.get() == null;
}
/**
* @return the cause of failure. If the message was sent successfully, this method will
* return null.
* @throws IllegalStateException if the message has not yet been marked as successful or
* not. One must call {@link #isDone()} or {@link #await()} before calling this method.
*/
public Throwable getFailureCause() {
if(!complete.get()) {
throw new IllegalStateException("Message has not yet been marked as successful or not");
}
return failureCause.get();
}
/**
* Used to notify that the message failed to send, for the provided reason.
*/
public void writeFailure(Throwable cause) {
failureCause.set(cause);
TransportUtils.markMessageWithSendFailure(message, cause);
complete.set(true);
completionLatch.countDown();
}
public boolean isWriteSubmitted()
{
return presentedForwrite.get();
}
public void writeSubmitted()
{
presentedForwrite.set(true);
}
/**
* Used to notify that the message successfully sent.
*/
public void writeSuccess() {
failureCause.set(null);
TransportUtils.markMessageWithSendSuccess(message);
complete.set(true);
completionLatch.countDown();
}
}