package org.jboss.resteasy.client.core.extractors;
import org.jboss.resteasy.annotations.Body;
import org.jboss.resteasy.annotations.LinkHeaderParam;
import org.jboss.resteasy.annotations.Status;
import org.jboss.resteasy.client.ClientExecutor;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ProxyFactory;
import org.jboss.resteasy.spi.Link;
import org.jboss.resteasy.spi.LinkHeader;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.util.IsHttpMethod;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.core.Response;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Set;
/**
* This class represents the method level creation of a "rich response object"
* that has the @ResponseObject annotation. These EntityExtractors will be used
* to implment methods of ResponseObject via ResponseObjectEntityExtractor
*
* @author <a href="mailto:sduskis@gmail.com">Solomon Duskis</a>
* @version $Revision: 1 $
* @see EntityExtractor, ResponseObjectEntityExtractor
*/
public class ResponseObjectEntityExtractorFactory extends DefaultEntityExtractorFactory
{
@SuppressWarnings("unchecked")
public EntityExtractor createExtractor(final Method method)
{
final Class<?> returnType = method.getReturnType();
if (method.isAnnotationPresent(Status.class))
{
if (returnType == Integer.class || returnType == int.class)
{
return new EntityExtractor<Integer>()
{
public Integer extractEntity(ClientRequestContext context, Object... args)
{
return context.getClientResponse().getStatus();
}
};
}
else if (returnType == Response.Status.class)
{
return createStatusExtractor(false);
}
}
if (method.isAnnotationPresent(Body.class))
{
return new BodyEntityExtractor(method);
}
final HeaderParam headerParam = method.getAnnotation(HeaderParam.class);
if (headerParam != null)
{
return new EntityExtractor()
{
public Object extractEntity(ClientRequestContext context, Object... args)
{
return context.getClientResponse().getHeaders().getFirst(headerParam.value());
}
};
}
final LinkHeaderParam link = method.getAnnotation(LinkHeaderParam.class);
if (link != null)
{
return processLinkHeader(method, returnType, link);
}
if (returnType == ClientRequest.class)
{
return new EntityExtractor()
{
public Object extractEntity(ClientRequestContext context, Object... args)
{
return context.getRequest();
}
};
}
if (Response.class.isAssignableFrom(returnType))
{
return createResponseTypeEntityExtractor(method);
}
if (returnType == LinkHeader.class)
{
return new EntityExtractor()
{
public Object extractEntity(ClientRequestContext context, Object... args)
{
return context.getClientResponse().getLinkHeader();
}
};
}
return null;
}
private EntityExtractor processLinkHeader(final Method method, final Class<?> returnType,
final LinkHeaderParam link)
{
if ("".equals(link.rel()) && "".equals(link.title()))
{
throw new RuntimeException(String.format(
"You must set either LinkHeaderParam.rel() or LinkHeaderParam.title() for on %s.%s",
method.getClass().getName(), method.getName()));
}
if (!"".equals(link.rel()) && !"".equals(link.title()))
{
throw new RuntimeException(
String
.format(
"You can only set one of LinkHeaderParam.rel() and LinkHeaderParam.title() for on %s.%s",
method.getClass().getName(), method.getName()));
}
if (returnType == Link.class)
{
return new EntityExtractor()
{
public Object extractEntity(ClientRequestContext context, Object... args)
{
return getLink(link, context);
}
};
}
if (isInvokerMethod(method))
{
return new EntityExtractor()
{
public Object extractEntity(ClientRequestContext context, Object... args)
{
URI uri = getURI(method, link, context);
if (uri == null)
return null;
ClientRequest request = context.getRequest();
EntityExtractorFactory extractor = context.getExtractorFactory();
ResteasyProviderFactory provider = request.getProviderFactory();
ClientExecutor executor = request.getExecutor();
return ProxyFactory.createClientInvoker(method.getClass(), method, uri,
executor, provider, extractor).invoke(args);
}
};
}
if (returnType == String.class)
{
return new EntityExtractor<String>()
{
public String extractEntity(ClientRequestContext context, Object... args)
{
Link link2 = getLink(link, context);
return link2 == null ? null : link2.getHref();
}
};
}
if (returnType == URL.class)
{
return new EntityExtractor<URL>()
{
public URL extractEntity(ClientRequestContext context, Object... args)
{
return getURL(method, link, context);
}
};
}
if (returnType == URI.class)
{
return new EntityExtractor<URI>()
{
public URI extractEntity(ClientRequestContext context, Object... args)
{
return getURI(method, link, context);
}
};
}
if (returnType.equals(ClientRequest.class))
{
return new EntityExtractor<ClientRequest>()
{
public ClientRequest extractEntity(ClientRequestContext context, Object... args)
{
URI uri = getURI(method, link, context);
return uri == null ? null : context.getRequest().createSubsequentRequest(uri);
}
};
}
return null;
}
private static boolean isInvokerMethod(Method method)
{
Set<String> httpMethods = IsHttpMethod.getHttpMethods(method);
return httpMethods != null && httpMethods.size() == 1;
}
private Link getLink(final LinkHeaderParam link, ClientRequestContext context)
{
LinkHeader linkHeader = context.getClientResponse().getLinkHeader();
if (!"".equals(link.rel()))
return linkHeader.getLinkByRelationship(link.rel());
else
return linkHeader.getLinkByTitle(link.title());
}
private URI getURI(final Method method, Link link)
{
if (link == null)
{
return null;
}
try
{
return new URI(link.getHref());
}
catch (URISyntaxException e)
{
throw new RuntimeException(String.format("Could not create a URI for %s in %s.%s", link
.getHref(), method.getClass().getName(), method.getName()), e);
}
}
private URI getURI(final Method method, final LinkHeaderParam link, ClientRequestContext context)
{
return getURI(method, getLink(link, context));
}
private URL getURL(final Method method, final LinkHeaderParam link, ClientRequestContext context)
{
URI uri = getURI(method, link, context);
try
{
return uri == null ? null : uri.toURL();
}
catch (MalformedURLException e)
{
throw new RuntimeException(String.format("Could not create a URL for %s in %s.%s", uri
.toASCIIString(), method.getClass().getName(), method.getName()), e);
}
}
}