package org.jboss.resteasy.core.interception.jaxrs;

import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages;
import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.tracing.InterceptorTimestampPair;
import org.jboss.resteasy.tracing.RESTEasyTracingLogger;

import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

Author:Bill Burke
Version:$Revision: 1 $
/** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */
public abstract class AbstractReaderInterceptorContext implements ReaderInterceptorContext { protected RESTEasyTracingLogger tracingLogger; private InterceptorTimestampPair<ReaderInterceptor> lastTracedInterceptor; protected ReaderInterceptor[] interceptors; protected ResteasyProviderFactory providerFactory; protected Class type; protected Type genericType; protected Annotation[] annotations; protected MediaType mediaType; protected MultivaluedMap<String, String> headers; protected InputStream inputStream; protected int index = 0; @Deprecated public AbstractReaderInterceptorContext(final MediaType mediaType, final ResteasyProviderFactory providerFactory, final Annotation[] annotations, final ReaderInterceptor[] interceptors, final MultivaluedMap<String, String> headers, final Type genericType, final Class type, final InputStream inputStream) { this.mediaType = mediaType; this.annotations = annotations; this.interceptors = interceptors; this.headers = headers; this.genericType = genericType; this.type = type; this.inputStream = inputStream; this.providerFactory = providerFactory; this.tracingLogger = RESTEasyTracingLogger.empty(); } public AbstractReaderInterceptorContext(final MediaType mediaType, final ResteasyProviderFactory providerFactory, final Annotation[] annotations, final ReaderInterceptor[] interceptors, final MultivaluedMap<String, String> headers, final Type genericType, final Class type, final InputStream inputStream, final RESTEasyTracingLogger logger) { this.mediaType = mediaType; this.annotations = annotations; this.interceptors = interceptors; this.headers = headers; this.genericType = genericType; this.type = type; this.inputStream = inputStream; this.providerFactory = providerFactory; this.tracingLogger = logger; if (logger == null) { this.tracingLogger = RESTEasyTracingLogger.empty(); } } @Override public Object proceed() throws IOException { LogMessages.LOGGER.debugf("Interceptor Context: %s, Method : proceed", getClass().getName()); if (interceptors == null || index >= interceptors.length) { MessageBodyReader reader = getReader(); if (reader!=null) { tracingLogger.log("MBR_READ_FROM", reader.getClass().getName()); LogMessages.LOGGER.debugf("MessageBodyReader: %s", reader.getClass().getName()); } return readFrom(reader); } LogMessages.LOGGER.debugf("ReaderInterceptor: %s", interceptors[index].getClass().getName()); int x = index; traceBefore(interceptors[x]); try { return interceptors[index++].aroundReadFrom(this); } finally { traceAfter(interceptors[x]); } // index--; we used to pop the index, but the TCK does not like this } @SuppressWarnings(value = "unchecked") protected Object readFrom(MessageBodyReader reader) throws IOException { return reader.readFrom(type, genericType, annotations, mediaType, headers, inputStream); } protected final void traceBefore(final ReaderInterceptor interceptor) { if (tracingLogger.isLogEnabled("RI_BEFORE")) { if ((lastTracedInterceptor != null) && (interceptor != null)) { tracingLogger.logDuration("RI_BEFORE", lastTracedInterceptor.getTimestamp(), lastTracedInterceptor.getInterceptor()); } lastTracedInterceptor = new InterceptorTimestampPair<>(interceptor, System.nanoTime()); } } protected final void traceAfter(final ReaderInterceptor interceptor) { if (tracingLogger.isLogEnabled("RI_AFTER")) { if ((lastTracedInterceptor != null) && (lastTracedInterceptor.getInterceptor() != null)) { tracingLogger.logDuration("RI_AFTER", lastTracedInterceptor.getTimestamp(), interceptor); } lastTracedInterceptor = new InterceptorTimestampPair<>(interceptor, System.nanoTime()); } } protected MessageBodyReader getReader() { MediaType mediaType = this.mediaType; // spec says set to octet stream if (getHeaders() != null && getHeaders().getFirst(HttpHeaders.CONTENT_TYPE) == null && mediaType.isWildcardType()) { mediaType = MediaType.APPLICATION_OCTET_STREAM_TYPE; } MessageBodyReader reader = resolveReader(mediaType); if (reader == null) { throwReaderNotFound(); } return reader; } protected abstract MessageBodyReader resolveReader(MediaType mediaType); protected abstract void throwReaderNotFound(); @Override public InputStream getInputStream() { return inputStream; } @Override public void setInputStream(InputStream is) { this.inputStream = is; } @Override public MultivaluedMap<String, String> getHeaders() { return headers; } @Override public Annotation[] getAnnotations() { return annotations; } @Override public void setAnnotations(Annotation[] annotations) { if (annotations == null) throw new NullPointerException(Messages.MESSAGES.annotationsParamNull()); this.annotations = annotations; } @Override public Class getType() { return type; } @Override public void setType(Class type) { this.type = type; } @Override public Type getGenericType() { return genericType; } @Override public void setGenericType(Type genericType) { this.genericType = genericType; } @Override public MediaType getMediaType() { return mediaType; } @Override public void setMediaType(MediaType mediaType) { this.mediaType = mediaType; } public Object getProcessedInterceptorCount() { return index; } }