use of org.jboss.resteasy.spi.AsyncOutputStream in project resteasy by resteasy.
the class DigitalSigningInterceptor method asyncAroundWriteTo.
@Override
public CompletionStage<Void> asyncAroundWriteTo(AsyncWriterInterceptorContext context) {
LogMessages.LOGGER.debugf("Interceptor : %s, Method : aroundWriteTo", getClass().getName());
MultivaluedMap<String, Object> headers = context.getHeaders();
List<DKIMSignature> list = getHeaders(headers);
if (list.isEmpty()) {
return context.asyncProceed();
}
// System.out.println("TRACE: Found ContentSignatures");
AsyncOutputStream old = context.getAsyncOutputStream();
// store body in a byte array so we can use it to calculate signature
ByteArrayOutputStream baos = new ByteArrayOutputStream();
context.setAsyncOutputStream(new BlockingAsyncOutputStream(baos));
return context.asyncProceed().thenCompose(v -> {
byte[] body = baos.toByteArray();
try {
for (DKIMSignature dosetaSignature : list) {
KeyRepository repository = (KeyRepository) context.getProperty(KeyRepository.class.getName());
sign(repository, headers, body, dosetaSignature);
}
} catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException | UnsupportedEncodingException e) {
CompletableFuture<Void> ret = new CompletableFuture<>();
ret.completeExceptionally(e);
return ret;
}
return old.asyncWrite(body);
}).whenComplete((v, t) -> {
context.setAsyncOutputStream(old);
if (t != null)
throw new RuntimeException(Messages.MESSAGES.failedToSign(), t);
});
}
use of org.jboss.resteasy.spi.AsyncOutputStream in project resteasy by resteasy.
the class SseEventOutputImpl method close.
private void close(final boolean flushBeforeClose, final Throwable error) {
// avoid even attempting to get a lock if someone else has closed it or is closing it
if (state.getAndSet(CLOSED) != CLOSED) {
if (error != null) {
drainQueue(error);
} else {
synchronized (lock) {
events.clear();
}
}
if (flushBeforeClose && responseFlushed) {
try (CloseableContext c = ResteasyContext.addCloseableContextDataLevel(contextDataMap)) {
// make sure we flush to await for any queued data being sent
AsyncOutputStream aos = response.getAsyncOutputStream();
aos.asyncFlush().toCompletableFuture().get();
} catch (IOException | InterruptedException | ExecutionException x) {
// ignore it and let's just close
}
}
if (asyncContext.isSuspended()) {
ResteasyAsynchronousResponse asyncResponse = asyncContext.getAsyncResponse();
if (asyncResponse != null) {
try {
asyncResponse.complete();
} catch (RuntimeException x) {
Throwable cause = x;
while (cause.getCause() != null && cause.getCause() != cause) cause = cause.getCause();
if (cause instanceof IOException) {
// ignore it, we're closed now
} else {
LOG.debug(cause.getMessage());
return;
}
}
}
}
clearContextData();
}
}
use of org.jboss.resteasy.spi.AsyncOutputStream in project resteasy by resteasy.
the class SseEventOutputImpl method internalWriteEvent.
private CompletionStage<Void> internalWriteEvent(final OutboundSseEvent event) {
synchronized (lock) {
try (CloseableContext c = ResteasyContext.addCloseableContextDataLevel(contextDataMap)) {
if (event != null) {
// // Check media type?
ByteArrayOutputStream bout = new ByteArrayOutputStream();
MediaType mediaType = event.getMediaType();
boolean mediaTypeSet = !(event instanceof OutboundSseEventImpl) || ((OutboundSseEventImpl) event).isMediaTypeSet();
if (mediaType == null || !mediaTypeSet) {
Object o = response.getOutputHeaders().getFirst("Content-Type");
if (o != null) {
if (o instanceof MediaType) {
MediaType mt = (MediaType) o;
String s = mt.getParameters().get(SseConstants.SSE_ELEMENT_MEDIA_TYPE);
if (s != null) {
mediaType = MediaType.valueOf(s);
}
} else if (o instanceof String) {
MediaType mt = MediaType.valueOf((String) o);
String s = mt.getParameters().get(SseConstants.SSE_ELEMENT_MEDIA_TYPE);
if (s != null) {
mediaType = MediaType.valueOf(s);
}
} else {
throw new RuntimeException(Messages.MESSAGES.expectedStringOrMediaType(o));
}
}
}
if (mediaType == null) {
mediaType = MediaType.TEXT_PLAIN_TYPE;
}
if (event instanceof OutboundSseEventImpl) {
((OutboundSseEventImpl) event).setMediaType(mediaType);
}
writer.writeTo(event, event.getClass(), null, new Annotation[] {}, mediaType, null, bout);
AsyncOutputStream aos = response.getAsyncOutputStream();
// eager composition to guarantee ordering
return aos.asyncWrite(bout.toByteArray()).thenCompose(v -> aos.asyncFlush()).exceptionally(e -> {
if (e instanceof CompletionException)
e = e.getCause();
if (e instanceof IOException)
close(false, e);
LogMessages.LOGGER.failedToWriteSseEvent(event.toString(), e);
SynchronousDispatcher.rethrow(e);
// never reached
return null;
});
}
} catch (IOException e) {
// The connection could be broken or closed. whenever IO error happens, mark closed to true to
// stop event writing
close(false, e);
LogMessages.LOGGER.failedToWriteSseEvent(event.toString(), e);
CompletableFuture<Void> ret = new CompletableFuture<>();
ret.completeExceptionally(e);
return ret;
} catch (Exception e) {
LogMessages.LOGGER.failedToWriteSseEvent(event.toString(), e);
CompletableFuture<Void> ret = new CompletableFuture<>();
ret.completeExceptionally(new ProcessingException(e));
return ret;
}
}
return CompletableFuture.completedFuture(null);
}
use of org.jboss.resteasy.spi.AsyncOutputStream in project resteasy by resteasy.
the class SseEventOutputImpl method internalFlushResponseToClient.
private CompletionStage<Void> internalFlushResponseToClient(boolean throwIOException) {
synchronized (lock) {
if (!responseFlushed) {
final BuiltResponse jaxrsResponse = createResponse();
try {
CompletableFuture<Void> ret = new CompletableFuture<>();
ServerResponseWriter.writeNomapResponse(jaxrsResponse, request, response, providerFactory, t -> {
AsyncOutputStream aos;
try {
aos = response.getAsyncOutputStream();
} catch (IOException x) {
close(false, x);
ret.completeExceptionally(x);
return;
}
// eager composition to guarantee ordering
CompletionStage<Void> a = aos.asyncWrite(SseConstants.DOUBLE_EOL).thenCompose(v -> aos.asyncFlush());
// we've queued a response flush, so avoid a second one being queued
responseFlushed = true;
a.thenAccept(v -> {
ret.complete(null);
}).exceptionally(e -> {
if (e instanceof CompletionException)
e = e.getCause();
if (e instanceof IOException)
close(false, e);
if (throwIOException)
ret.completeExceptionally(e);
else
ret.completeExceptionally(new ProcessingException(Messages.MESSAGES.failedToCreateSseEventOutput(), e));
return null;
});
}, true);
return ret;
} catch (IOException e) {
close(false, e);
CompletableFuture<Void> ret = new CompletableFuture<>();
if (throwIOException) {
ret.completeExceptionally(e);
} else {
ret.completeExceptionally(new ProcessingException(Messages.MESSAGES.failedToCreateSseEventOutput(), e));
}
return ret;
}
}
}
return CompletableFuture.completedFuture(null);
}
use of org.jboss.resteasy.spi.AsyncOutputStream in project resteasy by resteasy.
the class SseEventProvider method asyncWriteTo.
@Override
@SuppressWarnings({ "unchecked" })
public CompletionStage<Void> asyncWriteTo(OutboundSseEvent event, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, AsyncOutputStream entityStream) {
Charset charset = StandardCharsets.UTF_8;
boolean textLike = MediaTypeHelper.isTextLike(mediaType);
boolean escape = event instanceof OutboundSseEventImpl ? ((OutboundSseEventImpl) event).isEscape() : false;
CompletionStage<Void> ret = CompletableFuture.completedFuture(null);
if (event.getComment() != null) {
for (final String comment : event.getComment().split("\n")) {
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.COMMENT_LEAD));
ret = ret.thenCompose(v -> entityStream.asyncWrite(comment.getBytes(charset)));
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.EOL));
}
}
if (event.getType() != null) {
if (event.getName() != null) {
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.NAME_LEAD));
ret = ret.thenCompose(v -> entityStream.asyncWrite(event.getName().getBytes(charset)));
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.EOL));
}
if (event.getId() != null) {
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.ID_LEAD));
ret = ret.thenCompose(v -> entityStream.asyncWrite(event.getId().getBytes(charset)));
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.EOL));
}
if (event.getReconnectDelay() > -1) {
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.RETRY_LEAD));
ret = ret.thenCompose(v -> entityStream.asyncWrite(Long.toString(event.getReconnectDelay()).getBytes(StandardCharsets.UTF_8)));
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.EOL));
}
if (event.getData() != null) {
Class<?> payloadClass = event.getType();
Type payloadType = event.getGenericType();
if (payloadType == null) {
payloadType = payloadClass;
}
if (payloadType == null && payloadClass == null) {
payloadType = Object.class;
payloadClass = Object.class;
}
Class<?> finalPayloadClass = payloadClass;
Type finalPayloadType = payloadType;
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.DATA_LEAD));
@SuppressWarnings("rawtypes") AsyncMessageBodyWriter writer = (AsyncMessageBodyWriter) providers.getMessageBodyWriter(payloadClass, payloadType, annotations, event.getMediaType());
if (writer == null) {
throw new ServerErrorException(Messages.MESSAGES.notFoundMBW(payloadClass.getName()), Response.Status.INTERNAL_SERVER_ERROR);
}
ret = ret.thenCompose(v -> writer.asyncWriteTo(event.getData(), finalPayloadClass, finalPayloadType, annotations, event.getMediaType(), httpHeaders, new AsyncOutputStream() {
boolean isNewLine = false;
@Override
public CompletionStage<Void> asyncFlush() {
return entityStream.asyncFlush();
}
@Override
public CompletionStage<Void> asyncWrite(byte[] bytes, int offset, int length) {
return entityStream.asyncWrite(escape(textLike, escape, bytes, offset, length));
}
private byte[] escape(boolean textLike, boolean escape, byte[] data, int offset, int length) {
ByteArrayOutputStream os = new ByteArrayOutputStream(data.length);
for (int i = 0; i < length; i++) {
byte b = data[i + offset];
if (textLike) {
if (b == '\n' || b == '\r') {
if (!isNewLine) {
try {
os.write(SseConstants.EOL);
} catch (IOException e) {
// cannot happen
throw new RuntimeException(e);
}
}
isNewLine = true;
} else {
if (isNewLine) {
try {
os.write(SseConstants.DATA_LEAD);
} catch (IOException e) {
// cannot happen
throw new RuntimeException(e);
}
}
os.write(b);
isNewLine = false;
}
} else {
if (escape && (b == '\n' || b == '\r' || b == '\\')) {
os.write('\\');
os.write(b);
} else {
os.write(b);
}
}
}
return os.toByteArray();
}
@Override
public void write(int b) throws IOException {
throw new IllegalStateException("Not supported");
}
}));
ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.EOL));
}
}
return ret = ret.thenCompose(v -> entityStream.asyncWrite(SseConstants.EOL));
}
Aggregations