package org.jboss.resteasy.springmvc;
import org.jboss.resteasy.core.ServerResponseWriter;
import org.jboss.resteasy.core.SynchronousDispatcher;
import org.jboss.resteasy.specimpl.BuiltResponse;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.util.HttpHeaderNames;
import org.jboss.resteasy.util.MediaTypeHelper;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:sduskis@gmail.com">Solomon Duskis</a>
* @version $Revision: 1 $
*/
@SuppressWarnings("rawtypes")
public class ResteasyView implements View
{
private MediaType contentType = null;
private List<MediaType> potentialContentTypes = null;
private ResteasyDeployment deployment;
public ResteasyView(String contentType, ResteasyDeployment deployment)
{
setContentType(contentType);
this.deployment = deployment;
}
public ResteasyView()
{
}
public ResteasyDeployment getDeployment()
{
return deployment;
}
public void setDeployment(ResteasyDeployment deployment)
{
this.deployment = deployment;
}
public String getContentType()
{
return contentType.toString();
}
public List<String> getPotentialContentTypes()
{
List<String> contentTypes = new ArrayList<String>(potentialContentTypes.size());
for (MediaType mediaType : potentialContentTypes)
{
contentTypes.add(mediaType.toString());
}
return contentTypes;
}
public void setPotentialContentTypes(List<String> potentialContentTypes)
{
this.potentialContentTypes = new ArrayList<MediaType>();
for (String type : potentialContentTypes)
{
this.potentialContentTypes.add(MediaType.valueOf(type));
}
}
public void render(final Map model, final HttpServletRequest servletRequest,
final HttpServletResponse servletResponse) throws Exception
{
final SynchronousDispatcher dispatcher = (SynchronousDispatcher)deployment.getDispatcher();
ResteasyWebHandlerTemplate template = new ResteasyWebHandlerTemplate<Void>(dispatcher.getProviderFactory())
{
protected Void handle(ResteasyRequestWrapper requestWrapper,
HttpResponse response) throws Exception
{
HttpRequest httpRequest = requestWrapper.getHttpRequest();
dispatcher.pushContextObjects(httpRequest, response);
try
{
try
{
MediaType resolvedContentType = resolveContentType(httpRequest,
httpRequest.getHttpHeaders().getMediaType());
BuiltResponse responseInvoker = getResponse(model, resolvedContentType);
if (responseInvoker != null)
{
ServerResponseWriter.writeNomapResponse(responseInvoker, httpRequest, response, dispatcher.getProviderFactory());
}
}
catch (Exception e)
{
dispatcher.writeException(httpRequest, response, e);
}
return null;
}
finally
{
dispatcher.clearContextData();
}
}
};
ResteasyRequestWrapper requestWrapper = RequestUtil.getRequestWrapper(servletRequest);
template.handle(requestWrapper, servletResponse);
}
private MediaType resolveContentType(HttpRequest jaxrsRequest, MediaType mt)
{
if (mt == null || MediaType.MEDIA_TYPE_WILDCARD.equals(mt.getType()))
{
List<MediaType> acceptableMediaTypes = jaxrsRequest.getHttpHeaders()
.getAcceptableMediaTypes();
if (contentType != null && isAcceptable(acceptableMediaTypes, contentType))
{
return contentType;
}
return MediaTypeHelper.getBestMatch(potentialContentTypes, acceptableMediaTypes);
}
return mt;
}
private boolean isAcceptable(List<MediaType> acceptableMediaTypes,
MediaType potentialContentType)
{
boolean isAcceptable = false;
for (MediaType acceptableMediaType : acceptableMediaTypes)
{
if (acceptableMediaType.isCompatible(potentialContentType))
{
isAcceptable = true;
break;
}
}
return isAcceptable;
}
protected BuiltResponse getResponse(Map model, MediaType mt)
{
Collection modelValues = model.values();
for (Object value : modelValues)
{
if (value instanceof BuiltResponse)
{
return (BuiltResponse) value;
}
}
if (model.size() == 1)
{
return createResponse(modelValues.iterator().next(), mt);
}
if (model.size() == 2)
{
for (Object value : modelValues)
{
if (!(value instanceof BindingResult))
{
return createResponse(value, mt);
}
}
}
return null;
}
private BuiltResponse createResponse(Object value, MediaType contentType)
{
BuiltResponse responseImpl = new BuiltResponse();
responseImpl.setEntity(value);
if (contentType != null)
responseImpl.getMetadata().putSingle(HttpHeaderNames.CONTENT_TYPE, contentType);
return responseImpl;
}
public void setContentType(String contentType)
{
this.contentType = MediaType.valueOf(contentType);
}
}