package org.jboss.resteasy.client.jaxrs.internal.proxy.processors;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.Stack;
import javax.ws.rs.BeanParam;
import javax.ws.rs.CookieParam;
import javax.ws.rs.Encoded;
import javax.ws.rs.FormParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.annotations.Form;
import org.jboss.resteasy.annotations.ClientURI;
import org.jboss.resteasy.client.jaxrs.i18n.Messages;
import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.invocation.CookieParamProcessor;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.invocation.FormParamProcessor;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.invocation.HeaderParamProcessor;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.invocation.MessageBodyParameterProcessor;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.invocation.URIParamProcessor;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.webtarget.MatrixParamProcessor;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.webtarget.PathParamProcessor;
import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.webtarget.QueryParamProcessor;
import org.jboss.resteasy.util.FindAnnotation;
import org.jboss.resteasy.util.MediaTypeHelper;
public class ProcessorFactory
{
public static Object[] createProcessors(Class declaringClass, Method method, ClientConfiguration configuration)
{
return createProcessors(declaringClass, method, configuration, null);
}
public static Object[] createProcessors(Class declaringClass, Method method, ClientConfiguration configuration, MediaType defaultConsumes)
{
Object[] params = new Object[method.getParameterTypes().length];
for (int i = 0; i < method.getParameterTypes().length; i++)
{
Class<?> type = method.getParameterTypes()[i];
Annotation[] annotations = method.getParameterAnnotations()[i];
Type genericType = method.getGenericParameterTypes()[i];
if (TypeVariable.class.isInstance(genericType) && declaringClass.isInterface() && !declaringClass.equals(method.getDeclaringClass())) {
genericType = getTypeArgument((TypeVariable)genericType, declaringClass, method.getDeclaringClass());
}
AccessibleObject target = method;
params[i] = ProcessorFactory.createProcessor(declaringClass, configuration, type, annotations, genericType, target, defaultConsumes, false);
}
return params;
}
public static Object createProcessor(Class<?> declaring,
ClientConfiguration configuration, Class<?> type,
Annotation[] annotations, Type genericType, AccessibleObject target,
boolean ignoreBody)
{
return createProcessor(declaring, configuration, type, annotations, genericType, target, null, ignoreBody);
}
public static Object createProcessor(Class<?> declaring,
ClientConfiguration configuration, Class<?> type,
Annotation[] annotations, Type genericType, AccessibleObject target, MediaType defaultConsumes,
boolean ignoreBody)
{
Object processor = null;
QueryParam query;
HeaderParam header;
MatrixParam matrix;
PathParam uriParam;
CookieParam cookie;
FormParam formParam;
// Form form;
boolean isEncoded = FindAnnotation.findAnnotation(annotations,
Encoded.class) != null;
if ((query = FindAnnotation.findAnnotation(annotations, QueryParam.class)) != null)
{
processor = new QueryParamProcessor(query.value());
}
else if ((header = FindAnnotation.findAnnotation(annotations,
HeaderParam.class)) != null)
{
processor = new HeaderParamProcessor(header.value());
}
else if ((cookie = FindAnnotation.findAnnotation(annotations,
CookieParam.class)) != null)
{
processor = new CookieParamProcessor(cookie.value());
}
else if ((uriParam = FindAnnotation.findAnnotation(annotations,
PathParam.class)) != null)
{
processor = new PathParamProcessor(uriParam.value(), !isEncoded);
}
else if ((matrix = FindAnnotation.findAnnotation(annotations,
MatrixParam.class)) != null)
{
processor = new MatrixParamProcessor(matrix.value());
}
else if ((formParam = FindAnnotation.findAnnotation(annotations,
FormParam.class)) != null)
{
processor = new FormParamProcessor(formParam.value());
}
else if ((/* form = */FindAnnotation.findAnnotation(annotations,
Form.class)) != null)
{
processor = new FormProcessor(type, configuration);
}
else if ((/* form = */FindAnnotation.findAnnotation(annotations,
BeanParam.class)) != null)
{
processor = new FormProcessor(type, configuration);
}
else if ((FindAnnotation.findAnnotation(annotations,
Context.class)) != null)
{
processor = null;
}
else if (type.equals(Cookie.class))
{
processor = new CookieParamProcessor(null);
}
// this is for HATEAOS clients
//look for old (resteasy-legacy) annotation too for runtime backward compatibility
else if (FindAnnotation.findAnnotation(annotations, ClientURI.class.getName(), "org.jboss.resteasy.client.ClientURI") != null)
{
processor = new URIParamProcessor();
}
else if (!ignoreBody)
{
MediaType mediaType = MediaTypeHelper.getConsumes(declaring, target);
if(mediaType == null)
mediaType = defaultConsumes;
if (mediaType == null)
{
throw new RuntimeException(Messages.MESSAGES.mustDefineConsumesType());
}
processor = new MessageBodyParameterProcessor(mediaType, type,
genericType, annotations);
}
return processor;
}
static Type getTypeArgument(TypeVariable<?> var, Class<?> clazz, Class<?> baseInterface) {
TypeVariable<?> tv = var;
// collect superinterfaces
Stack<Type> superinterfaces = new Stack<Type>();
Type currentType;
Class<?> currentClass = clazz;
recursivePush(currentClass, baseInterface, superinterfaces);
while (!superinterfaces.isEmpty()) {
currentType = superinterfaces.pop();
if (currentType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) currentType;
Class<?> rawType = (Class) pt.getRawType();
int argIndex = Arrays.asList(rawType.getTypeParameters()).indexOf(tv);
if (argIndex > -1) {
Type typeArg = pt.getActualTypeArguments()[argIndex];
if (typeArg instanceof TypeVariable) {
// type argument is another type variable - look for the value of that
// variable in subclasses
tv = (TypeVariable<?>) typeArg;
continue;
} else {
// found the value - return it
return typeArg;
}
}
}
// needed type argument not supplied - break and throw exception
break;
}
throw new IllegalArgumentException(Messages.MESSAGES.doesNotSpecifyTypeParameter(var));
}
static void recursivePush(Type t, Class<?> baseInterface, Stack<Type> superinterfaces) {
Class<?> currentClass = null;
if (t instanceof Class) {
currentClass = (Class) t;
} else if (t instanceof ParameterizedType) {
currentClass = (Class) ((ParameterizedType) t).getRawType();
}
if (baseInterface.isAssignableFrom(currentClass)) {
superinterfaces.push(t);
for (Type otherType : currentClass.getGenericInterfaces()) {
recursivePush(otherType, baseInterface, superinterfaces);
}
}
}
}