package org.jboss.resteasy.specimpl;

import org.jboss.resteasy.core.Headers;
import org.jboss.resteasy.core.interception.jaxrs.AbstractReaderInterceptorContext;
import org.jboss.resteasy.core.interception.jaxrs.ClientReaderInterceptorContext;
import org.jboss.resteasy.plugins.providers.sse.EventInput;
import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages;
import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages;
import org.jboss.resteasy.spi.HttpResponseCodes;
import org.jboss.resteasy.spi.MarshalledEntity;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.util.Types;
import org.jboss.resteasy.util.InputStreamToByteArray;
import org.jboss.resteasy.util.ReadFromStream;
import org.reactivestreams.Publisher;

import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ReaderInterceptor;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;

A response object not attached to a client or server invocation.
Author:Bill Burke
Version:$Revision: 1 $
/** * A response object not attached to a client or server invocation. * * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */
public class BuiltResponse extends AbstractBuiltResponse { public BuiltResponse() { super(); } public BuiltResponse(final int status, final Headers<Object> metadata, final Object entity, final Annotation[] entityAnnotations) { this(status, null, metadata, entity, entityAnnotations); } public BuiltResponse(final int status, final String reason, final Headers<Object> metadata, final Object entity, final Annotation[] entityAnnotations) { super(status, reason, metadata, entity, entityAnnotations); } @SuppressWarnings("unchecked") @Override public <T> T readEntity(Class<T> type, Type genericType, Annotation[] anns) { abortIfClosed(); if (entity != null) { if (type.isInstance((this.entity))) { return (T)entity; } else if (entity instanceof InputStream) { setInputStream((InputStream)entity); entity = null; } else if (bufferedEntity == null) { throw new RuntimeException(Messages.MESSAGES.entityAlreadyRead(entity.getClass())); } else { entity = null; } } if (entity == null) { if (status == HttpResponseCodes.SC_NO_CONTENT) return null; try { entity = readFrom(type, genericType, getMediaType(), anns); if (entity == null || (entity != null && !InputStream.class.isInstance(entity) && !Reader.class.isInstance(entity) && bufferedEntity == null)) { try { if (!Publisher.class.isInstance(entity) && !EventInput.class.isInstance(entity)) { close(); } } catch (Exception ignored) { } } } catch (RuntimeException e) { try { close(); } catch (Exception ignored) { } LogMessages.LOGGER.clientReceiveProcessingFailure(e); throw e; } } return (T) entity; } // this is synchronized in conjunction with finalize to protect against premature finalize called by the GC protected synchronized <T> Object readFrom(Class<T> type, Type genericType, MediaType media, Annotation[] annotations) { Type useGeneric = genericType == null ? type : genericType; Class<?> useType = type; media = media == null ? MediaType.WILDCARD_TYPE : media; annotations = annotations == null ? this.annotations : annotations; boolean isMarshalledEntity = false; if (type.equals(MarshalledEntity.class)) { isMarshalledEntity = true; ParameterizedType param = (ParameterizedType) useGeneric; useGeneric = param.getActualTypeArguments()[0]; useType = Types.getRawType(useGeneric); } try { InputStream is = getEntityStream(); if (is == null) { throw new IllegalStateException(Messages.MESSAGES.inputStreamWasEmpty()); } if (isMarshalledEntity) { is = new InputStreamToByteArray(is); } ResteasyProviderFactory providerFactory = ResteasyProviderFactory.getInstance(); ReaderInterceptor[] readerInterceptors = providerFactory .getServerReaderInterceptorRegistry() .postMatch(null, null); final Object finalObj; AbstractReaderInterceptorContext context = new ClientReaderInterceptorContext( readerInterceptors, providerFactory, useType, useGeneric, annotations, media, getStringHeaders(), is, new HashMap<String, Object>(), null); finalObj = context.proceed(); if (isMarshalledEntity) { InputStreamToByteArray isba = (InputStreamToByteArray) is; final byte[] bytes = isba.toByteArray(); return new MarshalledEntity<Object>() { @Override public byte[] getMarshalledBytes() { return bytes; } @Override public Object getEntity() { return finalObj; } }; } else { return finalObj; } } catch (ProcessingException pe) { throw pe; } catch (Exception ex) { throw new ProcessingException(ex); } } protected InputStream getEntityStream() { if (bufferedEntity != null) { return new ByteArrayInputStream(bufferedEntity); } if (isClosed()) { throw new ProcessingException(Messages.MESSAGES.streamIsClosed()); } InputStream is = getInputStream(); return is != null ? new AbstractBuiltResponse.InputStreamWrapper<BuiltResponse>(is, this) : null; } protected void setInputStream(InputStream is) { this.is = is; resetEntity(); } protected InputStream getInputStream() { if (is == null && entity != null && entity instanceof InputStream) { is = (InputStream) entity; } return is; } @Override public void releaseConnection() throws IOException { releaseConnection(false); } @Override public void releaseConnection(boolean consumeInputStream) throws IOException { try { if (is != null) { if (consumeInputStream) { while (is.read() > 0) { } } is.close(); is = null; } } catch (IOException e) { } } @Override public boolean bufferEntity() { abortIfClosed(); if (bufferedEntity != null) return true; if (streamRead) return false; InputStream is = getInputStream(); if (is == null) return false; try { bufferedEntity = ReadFromStream.readFromStream(1024, is); } catch (IOException e) { throw new ProcessingException(e); } finally { try { releaseConnection(); } catch (IOException e) { throw new ProcessingException(e); } } return true; } }