package org.jboss.resteasy.core.interception.jaxrs;
import org.jboss.resteasy.core.SynchronousDispatcher;
import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages;
import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages;
import org.jboss.resteasy.spi.AsyncMessageBodyWriter;
import org.jboss.resteasy.spi.AsyncOutputStream;
import org.jboss.resteasy.spi.AsyncWriterInterceptor;
import org.jboss.resteasy.spi.AsyncWriterInterceptorContext;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.tracing.InterceptorTimestampPair;
import org.jboss.resteasy.tracing.RESTEasyTracingLogger;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
public abstract class AbstractWriterInterceptorContext implements WriterInterceptorContext, AsyncWriterInterceptorContext
{
protected RESTEasyTracingLogger tracingLogger;
protected WriterInterceptor[] interceptors;
protected boolean requireAsyncIO;
protected Object entity;
protected Class type;
protected Type genericType;
protected Annotation[] annotations;
protected MediaType mediaType;
protected MultivaluedMap<String, Object> ;
protected OutputStream outputStream;
public int getProcessedInterceptorCount() {
return index;
}
protected int index = 0;
protected ResteasyProviderFactory providerFactory;
private InterceptorTimestampPair<?> lastTracedInterceptor;
@Deprecated
public AbstractWriterInterceptorContext(final WriterInterceptor[] interceptors, final Annotation[] annotations, final Object entity, final Type genericType, final MediaType mediaType, final Class type, final OutputStream outputStream, final ResteasyProviderFactory providerFactory, final MultivaluedMap<String, Object> headers)
{
this.providerFactory = providerFactory;
this.interceptors = interceptors;
this.annotations = annotations;
this.entity = entity;
this.genericType = genericType;
this.mediaType = mediaType;
this.type = type;
this.outputStream = outputStream;
this.headers = headers;
this.tracingLogger = RESTEasyTracingLogger.empty();
}
public AbstractWriterInterceptorContext(final WriterInterceptor[] interceptors, final Annotation[] annotations, final Object entity, final Type genericType, final MediaType mediaType, final Class type, final OutputStream outputStream, final ResteasyProviderFactory providerFactory, final MultivaluedMap<String, Object> headers, final RESTEasyTracingLogger logger) {
this.providerFactory = providerFactory;
this.interceptors = interceptors;
this.annotations = annotations;
this.entity = entity;
this.genericType = genericType;
this.mediaType = mediaType;
this.type = type;
this.outputStream = outputStream;
this.headers = headers;
this.tracingLogger = logger;
if (logger == null) {
this.tracingLogger = RESTEasyTracingLogger.empty();
}
}
public Object getEntity()
{
return entity;
}
public void setEntity(Object entity)
{
this.entity = entity;
}
public Class getType()
{
return type;
}
public void setType(Class type)
{
this.type = type;
}
public Type getGenericType()
{
return genericType;
}
public void setGenericType(Type genericType)
{
this.genericType = genericType;
}
public Annotation[] getAnnotations()
{
return annotations;
}
public void setAnnotations(Annotation[] annotations)
{
if (annotations == null) throw new NullPointerException(Messages.MESSAGES.annotationsParamNull());
this.annotations = annotations;
}
public MediaType getMediaType()
{
return mediaType;
}
public void setMediaType(MediaType mediaType)
{
this.mediaType = mediaType;
}
public MultivaluedMap<String, Object> ()
{
return headers;
}
public OutputStream getOutputStream()
{
return outputStream;
}
public void setOutputStream(OutputStream outputStream)
{
this.outputStream = outputStream;
}
public void setAsyncOutputStream(AsyncOutputStream asyncOutputStream) {
this.outputStream = asyncOutputStream;
}
public AsyncOutputStream getAsyncOutputStream()
{
return (AsyncOutputStream) outputStream;
}
public CompletionStage<Void> getStarted() {
if(outputStream instanceof AsyncOutputStream
&& getWriter() instanceof AsyncMessageBodyWriter
&& interceptorsSupportAsyncIo()) {
requireAsyncIO = true;
return asyncProceed();
}
try
{
return syncProceed();
} catch (WebApplicationException | IOException e)
{
CompletableFuture<Void> ret = new CompletableFuture<>();
ret.completeExceptionally(e);
return ret;
}
}
private boolean ()
{
for (WriterInterceptor interceptor : interceptors)
{
if(interceptor instanceof AsyncWriterInterceptor == false)
return false;
}
return true;
}
protected boolean preferAsyncIo() {
return false;
}
public CompletionStage<Void> asyncProceed() {
LogMessages.LOGGER.debugf("Interceptor Context: %s, Method : proceed", getClass().getName());
if (interceptors == null || index >= interceptors.length)
{
AsyncMessageBodyWriter writer = (AsyncMessageBodyWriter)getWriter();
if (writer!=null) {
tracingLogger.log("MBW_WRITE_TO", writer.getClass().getName());
LogMessages.LOGGER.debugf("MessageBodyWriter: %s", writer.getClass().getName());
}
return writeTo(writer);
}
else
{
LogMessages.LOGGER.debugf("WriterInterceptor: %s", interceptors[index].getClass().getName());
int x = index;
traceBefore(interceptors[x]);
return ((AsyncWriterInterceptor) interceptors[index++]).asyncAroundWriteTo(this)
.whenComplete((v, t) -> traceAfter(interceptors[x]));
}
}
public void proceed() throws IOException, WebApplicationException
{
try
{
syncProceed().toCompletableFuture().get();
} catch (InterruptedException e)
{
SynchronousDispatcher.rethrow(e);
} catch (ExecutionException e)
{
SynchronousDispatcher.rethrow(e.getCause());
}
}
public CompletionStage<Void> syncProceed() throws IOException, WebApplicationException
{
LogMessages.LOGGER.debugf("Interceptor Context: %s, Method : proceed", getClass().getName());
if (interceptors == null || index >= interceptors.length)
{
MessageBodyWriter writer = getWriter();
if (writer!=null) {
tracingLogger.log("MBW_WRITE_TO", writer.getClass().getName());
LogMessages.LOGGER.debugf("MessageBodyWriter: %s", writer.getClass().getName());
}
return writeTo(writer);
}
else
{
LogMessages.LOGGER.debugf("WriterInterceptor: %s", interceptors[index].getClass().getName());
int x = index;
traceBefore(interceptors[x]);
try {
interceptors[index++].aroundWriteTo(this);
} finally {
traceAfter(interceptors[x]);
}
return CompletableFuture.completedFuture(null);
}
}
protected final void traceBefore(final WriterInterceptor interceptor) {
if (tracingLogger.isLogEnabled("WI_BEFORE")) {
if ((lastTracedInterceptor != null) && (interceptor != null)) {
tracingLogger.logDuration("WI_BEFORE", lastTracedInterceptor.getTimestamp(), lastTracedInterceptor.getInterceptor());
}
lastTracedInterceptor = new InterceptorTimestampPair<>(interceptor, System.nanoTime());
}
}
protected final void traceAfter(final WriterInterceptor interceptor) {
if (tracingLogger.isLogEnabled("WI_AFTER")) {
if ((lastTracedInterceptor != null) && (lastTracedInterceptor.getInterceptor() != null)) {
tracingLogger.logDuration("WI_AFTER", lastTracedInterceptor.getTimestamp(), interceptor);
}
lastTracedInterceptor = new InterceptorTimestampPair<>(interceptor, System.nanoTime());
}
}
@SuppressWarnings(value = "unchecked")
protected CompletionStage<Void> writeTo(MessageBodyWriter writer) throws IOException
{
writer.writeTo(entity, type, genericType, annotations, mediaType, headers, outputStream);
return CompletableFuture.completedFuture(null);
}
@SuppressWarnings(value = "unchecked")
protected CompletionStage<Void> writeTo(AsyncMessageBodyWriter writer)
{
return writer.asyncWriteTo(entity, type, genericType, annotations, mediaType, headers, (AsyncOutputStream) outputStream);
}
protected MessageBodyWriter getWriter()
{
MessageBodyWriter writer = resolveWriter();
if(requireAsyncIO && writer instanceof AsyncMessageBodyWriter == false)
throw new IllegalStateException("Cannot switch body writer from blocking to asynchronous during writer interceptor run");
if (writer == null)
{
throwWriterNotFoundException();
}
return writer;
}
protected abstract MessageBodyWriter resolveWriter();
abstract void throwWriterNotFoundException();
}