package org.jboss.resteasy.core;
import org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext;
import org.jboss.resteasy.core.interception.ContainerResponseContextImpl;
import org.jboss.resteasy.core.interception.ResponseContainerRequestContext;
import org.jboss.resteasy.core.interception.ServerWriterInterceptorContext;
import org.jboss.resteasy.core.registry.SegmentNode;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.specimpl.BuiltResponse;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.util.CommitHeaderOutputStream;
import org.jboss.resteasy.util.HttpHeaderNames;
import javax.ws.rs.NotAcceptableException;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.WriterInterceptor;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ServerResponseWriter
{
private final static Logger logger = Logger.getLogger(ServerResponseWriter.class);
public static void writeNomapResponse(BuiltResponse jaxrsResponse, final HttpRequest request, final HttpResponse response, final ResteasyProviderFactory providerFactory) throws IOException
{
ResourceMethodInvoker method =(ResourceMethodInvoker) request.getAttribute(ResourceMethodInvoker.class.getName());
if (jaxrsResponse.getEntity() != null && jaxrsResponse.getMediaType() == null)
{
setDefaultContentType(request, jaxrsResponse, providerFactory, method);
}
executeFilters(jaxrsResponse, request, response, providerFactory, method);
if (jaxrsResponse.getEntity() == null || request.getHttpMethod().equalsIgnoreCase("HEAD"))
{
response.setStatus(jaxrsResponse.getStatus());
commitHeaders(jaxrsResponse, response);
return;
}
Class type = jaxrsResponse.getEntityClass();
Object ent = jaxrsResponse.getEntity();
Type generic = jaxrsResponse.getGenericType();
Annotation[] annotations = jaxrsResponse.getAnnotations();
MessageBodyWriter writer = providerFactory.getMessageBodyWriter(
type, generic, annotations, jaxrsResponse.getMediaType());
if (writer == null)
{
throw new NoMessageBodyWriterFoundFailure(type, jaxrsResponse.getMediaType());
}
response.setStatus(jaxrsResponse.getStatus());
final BuiltResponse built = jaxrsResponse;
CommitHeaderOutputStream.CommitCallback callback = new CommitHeaderOutputStream.CommitCallback()
{
private boolean committed;
@Override
public void commit()
{
if (committed) return;
committed = true;
commitHeaders(built, response);
}
};
OutputStream os = new CommitHeaderOutputStream(response.getOutputStream(), callback);
WriterInterceptor[] writerInterceptors = null;
if (method != null)
{
writerInterceptors = method.getWriterInterceptors();
}
else
{
writerInterceptors = providerFactory.getServerWriterInterceptorRegistry().postMatch(null, null);
}
AbstractWriterInterceptorContext writerContext = new ServerWriterInterceptorContext(writerInterceptors,
providerFactory, ent, type, generic, annotations, jaxrsResponse.getMediaType(),
jaxrsResponse.getMetadata(), os, request);
writerContext.proceed();
callback.commit(); // just in case the output stream is never used
}
private static void executeFilters(BuiltResponse jaxrsResponse, HttpRequest request, HttpResponse response, ResteasyProviderFactory providerFactory, ResourceMethodInvoker method) throws IOException
{
ContainerResponseFilter[] responseFilters = null;
if (method != null)
{
responseFilters = method.getResponseFilters();
}
else
{
responseFilters = providerFactory.getContainerResponseFilterRegistry().postMatch(null, null);
}
if (responseFilters != null)
{
ResponseContainerRequestContext requestContext = new ResponseContainerRequestContext(request);
ContainerResponseContextImpl responseContext = new ContainerResponseContextImpl(request, response, jaxrsResponse);
for (ContainerResponseFilter filter : responseFilters)
{
filter.filter(requestContext, responseContext);
}
}
}
protected static void setDefaultContentType(HttpRequest request, BuiltResponse jaxrsResponse, ResteasyProviderFactory providerFactory, ResourceMethodInvoker method)
{
MediaType chosen = (MediaType)request.getAttribute(SegmentNode.RESTEASY_CHOSEN_ACCEPT);
if (chosen != null && chosen.isWildcardSubtype()) chosen = null;
if (chosen == null)
{
if (method != null)
{
// pick most specific
for (MediaType produce : method.getProduces())
{
if (!produce.isWildcardType())
{
chosen = produce;
if (!produce.isWildcardSubtype())
{
break;
}
}
}
}
}
if (chosen == null)
{
chosen = MediaType.WILDCARD_TYPE;
Class type = jaxrsResponse.getEntityClass();
Object ent = jaxrsResponse.getEntity();
Type generic = jaxrsResponse.getGenericType();
if (generic == null)
{
if (method != null && !Response.class.isAssignableFrom(method.getMethod().getReturnType())) generic = method.getGenericReturnType();
else generic = type;
}
Annotation[] annotations = jaxrsResponse.getAnnotations();
if (annotations == null && method != null)
{
annotations = method.getMethodAnnotations();
}
MediaType mt = providerFactory.getConcreteMediaTypeFromMessageBodyWriters(type, generic, annotations, chosen);
if (mt != null)
{
jaxrsResponse.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, mt);
return;
}
}
if (chosen.isWildcardType())
{
chosen = MediaType.APPLICATION_OCTET_STREAM_TYPE;
}
else if (chosen.isWildcardSubtype() && chosen.getSubtype().equals("application"))
{
chosen = MediaType.APPLICATION_OCTET_STREAM_TYPE;
}
else if (chosen.isWildcardSubtype())
{
throw new NotAcceptableException("Illegal response media type: " + chosen.toString());
}
jaxrsResponse.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, chosen);
}
public static MediaType resolveContentType(BuiltResponse response)
{
MediaType responseContentType = null;
Object type = response.getMetadata().getFirst(HttpHeaderNames.CONTENT_TYPE);
if (type == null)
{
return MediaType.WILDCARD_TYPE;
}
if (type instanceof MediaType)
{
responseContentType = (MediaType) type;
}
else
{
responseContentType = MediaType.valueOf(type.toString());
}
return responseContentType;
}
public static void commitHeaders(BuiltResponse jaxrsResponse, HttpResponse response)
{
if (jaxrsResponse.getMetadata() != null)
{
List<Object> cookies = jaxrsResponse.getMetadata().get(
HttpHeaderNames.SET_COOKIE);
if (cookies != null)
{
Iterator<Object> it = cookies.iterator();
while (it.hasNext())
{
Object next = it.next();
if (next instanceof NewCookie)
{
NewCookie cookie = (NewCookie) next;
response.addNewCookie(cookie);
it.remove();
}
}
if (cookies.size() < 1)
jaxrsResponse.getMetadata().remove(HttpHeaderNames.SET_COOKIE);
}
}
if (jaxrsResponse.getMetadata() != null
&& jaxrsResponse.getMetadata().size() > 0)
{
response.getOutputHeaders().putAll(jaxrsResponse.getMetadata());
}
}
}