use of jakarta.servlet.WriteListener in project atmosphere by Atmosphere.
the class SSEAtmosphereInterceptorTest method testDataWriter.
@Test
public void testDataWriter() throws Exception {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ServletResponse resp = Mockito.mock(HttpServletResponse.class);
Mockito.when(resp.getOutputStream()).thenReturn(new ServletOutputStream() {
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener writeListener) {
}
@Override
public void write(int b) throws IOException {
baos.write(b);
}
@Override
public void write(byte[] b) throws IOException {
baos.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
baos.write(b, off, len);
}
});
AtmosphereRequest request = AtmosphereRequestImpl.newInstance();
request.header(HeaderConfig.X_ATMOSPHERE_TRANSPORT, "SSE");
AtmosphereResponse response = AtmosphereResponseImpl.newInstance(request);
response.request(request);
response.setResponse(resp);
AtmosphereResourceImpl resource = new AtmosphereResourceImpl();
resource.initialize(framework.getAtmosphereConfig(), framework.getBroadcasterFactory().get(), request, response, Mockito.mock(AsyncSupport.class), null);
resource.suspend();
SSEAtmosphereInterceptor interceptor = new SSEAtmosphereInterceptor();
interceptor.configure(config);
interceptor.inspect(resource);
// no newline
response.write("Good Morning".getBytes());
assertEquals(baos.toString(), "data:Good Morning\r\n\r\n");
baos.reset();
// \n
response.write("Hello World!\nHave a nice day!".getBytes());
assertEquals(baos.toString(), "data:Hello World!\r\ndata:Have a nice day!\r\n\r\n");
baos.reset();
// \r
response.write("Hello World!\rHave a nice day!".getBytes());
assertEquals(baos.toString(), "data:Hello World!\r\ndata:Have a nice day!\r\n\r\n");
baos.reset();
// \r\n
response.write("Hello World!\r\nHave a nice day!".getBytes());
assertEquals(baos.toString(), "data:Hello World!\r\ndata:Have a nice day!\r\n\r\n");
}
use of jakarta.servlet.WriteListener in project tomcat by apache.
the class CoyoteAdapter method asyncDispatch.
// -------------------------------------------------------- Adapter Methods
@Override
public boolean asyncDispatch(org.apache.coyote.Request req, org.apache.coyote.Response res, SocketEvent status) throws Exception {
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
if (request == null) {
throw new IllegalStateException(sm.getString("coyoteAdapter.nullRequest"));
}
boolean success = true;
AsyncContextImpl asyncConImpl = request.getAsyncContextInternal();
req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
req.setRequestThread();
try {
if (!request.isAsync()) {
// Error or timeout
// Lift any suspension (e.g. if sendError() was used by an async
// request) to allow the response to be written to the client
response.setSuspended(false);
}
if (status == SocketEvent.TIMEOUT) {
if (!asyncConImpl.timeout()) {
asyncConImpl.setErrorState(null, false);
}
} else if (status == SocketEvent.ERROR) {
// An I/O error occurred on a non-container thread which means
// that the socket needs to be closed so set success to false to
// trigger a close
success = false;
Throwable t = (Throwable) req.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
Context context = request.getContext();
ClassLoader oldCL = null;
try {
oldCL = context.bind(false, null);
if (req.getReadListener() != null) {
req.getReadListener().onError(t);
}
if (res.getWriteListener() != null) {
res.getWriteListener().onError(t);
}
res.action(ActionCode.CLOSE_NOW, t);
asyncConImpl.setErrorState(t, true);
} finally {
context.unbind(false, oldCL);
}
}
// Check to see if non-blocking writes or reads are being used
if (!request.isAsyncDispatching() && request.isAsync()) {
WriteListener writeListener = res.getWriteListener();
ReadListener readListener = req.getReadListener();
if (writeListener != null && status == SocketEvent.OPEN_WRITE) {
Context context = request.getContext();
ClassLoader oldCL = null;
try {
oldCL = context.bind(false, null);
res.onWritePossible();
if (request.isFinished() && req.sendAllDataReadEvent() && readListener != null) {
readListener.onAllDataRead();
}
// User code may have swallowed an IOException
if (response.getCoyoteResponse().isExceptionPresent()) {
throw response.getCoyoteResponse().getErrorException();
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// Need to trigger the call to AbstractProcessor.setErrorState()
// before the listener is called so the listener can call complete
// Therefore no need to set success=false as that would trigger a
// second call to AbstractProcessor.setErrorState()
// https://bz.apache.org/bugzilla/show_bug.cgi?id=65001
writeListener.onError(t);
res.action(ActionCode.CLOSE_NOW, t);
asyncConImpl.setErrorState(t, true);
} finally {
context.unbind(false, oldCL);
}
} else if (readListener != null && status == SocketEvent.OPEN_READ) {
Context context = request.getContext();
ClassLoader oldCL = null;
try {
oldCL = context.bind(false, null);
// onDataAvailable() is not called in this case.
if (!request.isFinished()) {
req.onDataAvailable();
}
if (request.isFinished() && req.sendAllDataReadEvent()) {
readListener.onAllDataRead();
}
// User code may have swallowed an IOException
if (request.getCoyoteRequest().isExceptionPresent()) {
throw request.getCoyoteRequest().getErrorException();
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// Need to trigger the call to AbstractProcessor.setErrorState()
// before the listener is called so the listener can call complete
// Therefore no need to set success=false as that would trigger a
// second call to AbstractProcessor.setErrorState()
// https://bz.apache.org/bugzilla/show_bug.cgi?id=65001
readListener.onError(t);
res.action(ActionCode.CLOSE_NOW, t);
asyncConImpl.setErrorState(t, true);
} finally {
context.unbind(false, oldCL);
}
}
}
// if the application doesn't define one)?
if (!request.isAsyncDispatching() && request.isAsync() && response.isErrorReportRequired()) {
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
}
if (request.isAsyncDispatching()) {
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
if (t != null) {
asyncConImpl.setErrorState(t, true);
}
}
if (!request.isAsync()) {
request.finishRequest();
response.finishResponse();
}
// Check to see if the processor is in an error state. If it is,
// bail out now.
AtomicBoolean error = new AtomicBoolean(false);
res.action(ActionCode.IS_ERROR, error);
if (error.get()) {
if (request.isAsyncCompleting()) {
// Connection will be forcibly closed which will prevent
// completion happening at the usual point. Need to trigger
// call to onComplete() here.
res.action(ActionCode.ASYNC_POST_PROCESS, null);
}
success = false;
}
} catch (IOException e) {
success = false;
// Ignore
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
success = false;
log.error(sm.getString("coyoteAdapter.asyncDispatch"), t);
} finally {
if (!success) {
res.setStatus(500);
}
// Access logging
if (!success || !request.isAsync()) {
long time = 0;
if (req.getStartTimeNanos() != -1) {
time = System.nanoTime() - req.getStartTimeNanos();
}
Context context = request.getContext();
if (context != null) {
context.logAccess(request, response, time, false);
} else {
log(req, res, time);
}
}
req.getRequestProcessor().setWorkerThreadName(null);
// Recycle the wrapper request and response
if (!success || !request.isAsync()) {
updateWrapperErrorCount(request, response);
request.recycle();
response.recycle();
}
}
return success;
}
Aggregations