use of jakarta.websocket.SendResult in project atmosphere by Atmosphere.
the class JSR356WebSocketTest method test_semaphore_is_released_in_case_of_failing_write.
@Test(timeOut = 1000)
public void test_semaphore_is_released_in_case_of_failing_write() throws Exception {
mockWriteResult(new SendResult(new RuntimeException("Fails")));
webSocket.write("Hello");
webSocket.write("Hello");
verify(asyncRemoteEndpoint, times(2)).sendText(eq("Hello"), any(SendHandler.class));
}
use of jakarta.websocket.SendResult in project tomcat by apache.
the class WsSession method doClose.
/**
* WebSocket 1.0. Section 2.1.5.
* Need internal close method as spec requires that the local endpoint
* receives a 1006 on timeout.
*
* @param closeReasonMessage The close reason to pass to the remote endpoint
* @param closeReasonLocal The close reason to pass to the local endpoint
* @param closeSocket Should the socket be closed immediately rather than waiting
* for the server to respond
*/
public void doClose(CloseReason closeReasonMessage, CloseReason closeReasonLocal, boolean closeSocket) {
// Double-checked locking. OK because state is volatile
if (state != State.OPEN) {
return;
}
synchronized (stateLock) {
if (state != State.OPEN) {
return;
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("wsSession.doClose", id));
}
// This will trigger a flush of any batched messages.
try {
wsRemoteEndpoint.setBatchingAllowed(false);
} catch (IOException e) {
log.warn(sm.getString("wsSession.flushFailOnClose"), e);
fireEndpointOnError(e);
}
/*
* If the flush above fails the error handling could call this
* method recursively. Without this check, the close message and
* notifications could be sent multiple times.
*/
if (state != State.OUTPUT_CLOSED) {
state = State.OUTPUT_CLOSED;
sendCloseMessage(closeReasonMessage);
if (closeSocket) {
wsRemoteEndpoint.close();
}
fireEndpointOnClose(closeReasonLocal);
}
}
IOException ioe = new IOException(sm.getString("wsSession.messageFailed"));
SendResult sr = new SendResult(ioe);
for (FutureToSendHandler f2sh : futures.keySet()) {
f2sh.onResult(sr);
}
}
use of jakarta.websocket.SendResult in project tomcat by apache.
the class WsSession method registerFuture.
/**
* Make the session aware of a {@link FutureToSendHandler} that will need to
* be forcibly closed if the session closes before the
* {@link FutureToSendHandler} completes.
* @param f2sh The handler
*/
protected void registerFuture(FutureToSendHandler f2sh) {
// Ideally, this code should sync on stateLock so that the correct
// action is taken based on the current state of the connection.
// However, a sync on stateLock can't be used here as it will create the
// possibility of a dead-lock. See BZ 61183.
// Therefore, a slightly less efficient approach is used.
// Always register the future.
futures.put(f2sh, f2sh);
if (state == State.OPEN) {
// session. Normal processing continues.
return;
}
if (f2sh.isDone()) {
// doesn't matter which. There is nothing more to do here.
return;
}
// The session is closed. The Future had not completed when last checked.
// There is a small timing window that means the Future may have been
// completed since the last check. There is also the possibility that
// the Future was not registered in time to be cleaned up during session
// close.
// Attempt to complete the Future with an error result as this ensures
// that the Future completes and any client code waiting on it does not
// hang. It is slightly inefficient since the Future may have been
// completed in another thread or another thread may be about to
// complete the Future but knowing if this is the case requires the sync
// on stateLock (see above).
// Note: If multiple attempts are made to complete the Future, the
// second and subsequent attempts are ignored.
IOException ioe = new IOException(sm.getString("wsSession.messageFailed"));
SendResult sr = new SendResult(ioe);
f2sh.onResult(sr);
}
use of jakarta.websocket.SendResult in project tomcat by apache.
the class WsRemoteEndpointImplServer method clearHandler.
/**
* @param t The throwable associated with any error that
* occurred
* @param useDispatch Should {@link SendHandler#onResult(SendResult)} be
* called from a new thread, keeping in mind the
* requirements of
* {@link jakarta.websocket.RemoteEndpoint.Async}
*/
private void clearHandler(Throwable t, boolean useDispatch) {
// Setting the result marks this (partial) message as
// complete which means the next one may be sent which
// could update the value of the handler. Therefore, keep a
// local copy before signalling the end of the (partial)
// message.
SendHandler sh = handler;
handler = null;
buffers = null;
if (sh != null) {
if (useDispatch) {
OnResultRunnable r = new OnResultRunnable(sh, t);
try {
socketWrapper.execute(r);
} catch (RejectedExecutionException ree) {
// Can't use the executor so call the runnable directly.
// This may not be strictly specification compliant in all
// cases but during shutdown only close messages are going
// to be sent so there should not be the issue of nested
// calls leading to stack overflow as described in bug
// 55715. The issues with nested calls was the reason for
// the separate thread requirement in the specification.
r.run();
}
} else {
if (t == null) {
sh.onResult(new SendResult());
} else {
sh.onResult(new SendResult(t));
}
}
}
}
use of jakarta.websocket.SendResult in project tomcat by apache.
the class WsRemoteEndpointImplServer method doWrite.
@Override
protected void doWrite(SendHandler handler, long blockingWriteTimeoutExpiry, ByteBuffer... buffers) {
if (socketWrapper.hasAsyncIO()) {
final boolean block = (blockingWriteTimeoutExpiry != -1);
long timeout = -1;
if (block) {
timeout = blockingWriteTimeoutExpiry - System.currentTimeMillis();
if (timeout <= 0) {
SendResult sr = new SendResult(new SocketTimeoutException());
handler.onResult(sr);
return;
}
} else {
this.handler = handler;
timeout = getSendTimeout();
if (timeout > 0) {
// Register with timeout thread
timeoutExpiry = timeout + System.currentTimeMillis();
wsWriteTimeout.register(this);
}
}
socketWrapper.write(block ? BlockingMode.BLOCK : BlockingMode.SEMI_BLOCK, timeout, TimeUnit.MILLISECONDS, null, SocketWrapperBase.COMPLETE_WRITE_WITH_COMPLETION, new CompletionHandler<Long, Void>() {
@Override
public void completed(Long result, Void attachment) {
if (block) {
long timeout = blockingWriteTimeoutExpiry - System.currentTimeMillis();
if (timeout <= 0) {
failed(new SocketTimeoutException(), null);
} else {
handler.onResult(SENDRESULT_OK);
}
} else {
wsWriteTimeout.unregister(WsRemoteEndpointImplServer.this);
clearHandler(null, true);
}
}
@Override
public void failed(Throwable exc, Void attachment) {
if (block) {
SendResult sr = new SendResult(exc);
handler.onResult(sr);
} else {
wsWriteTimeout.unregister(WsRemoteEndpointImplServer.this);
clearHandler(exc, true);
close();
}
}
}, buffers);
} else {
if (blockingWriteTimeoutExpiry == -1) {
this.handler = handler;
this.buffers = buffers;
// This is definitely the same thread that triggered the write so a
// dispatch will be required.
onWritePossible(true);
} else {
// Blocking
try {
for (ByteBuffer buffer : buffers) {
long timeout = blockingWriteTimeoutExpiry - System.currentTimeMillis();
if (timeout <= 0) {
SendResult sr = new SendResult(new SocketTimeoutException());
handler.onResult(sr);
return;
}
socketWrapper.setWriteTimeout(timeout);
socketWrapper.write(true, buffer);
}
long timeout = blockingWriteTimeoutExpiry - System.currentTimeMillis();
if (timeout <= 0) {
SendResult sr = new SendResult(new SocketTimeoutException());
handler.onResult(sr);
return;
}
socketWrapper.setWriteTimeout(timeout);
socketWrapper.flush(true);
handler.onResult(SENDRESULT_OK);
} catch (IOException e) {
SendResult sr = new SendResult(e);
handler.onResult(sr);
}
}
}
}
Aggregations