package com.ctp.cdi.query.builder;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.interceptor.InvocationContext;
import com.ctp.cdi.query.handler.CdiQueryInvocationContext;
import com.ctp.cdi.query.handler.QueryInvocationException;
import com.ctp.cdi.query.meta.MethodType;
import com.ctp.cdi.query.meta.QueryInvocation;
import com.ctp.cdi.query.spi.DelegateQueryHandler;
@QueryInvocation(MethodType.DELEGATE)
public class DelegateQueryBuilder extends QueryBuilder {
@Inject @Any
private Instance<DelegateQueryHandler> delegates;
@Override
public Object execute(CdiQueryInvocationContext context) {
try {
InvocationContext invocation = context.getInvocation();
DelegateQueryHandler delegate = selectDelegate(context.getMethod());
if (delegate != null) {
return invoke(delegate, context);
}
return invocation.proceed();
} catch (Exception e) {
throw new QueryInvocationException(e, context);
}
}
private DelegateQueryHandler selectDelegate(Method method) {
for (Iterator<DelegateQueryHandler> it = delegates.iterator(); it.hasNext();) {
DelegateQueryHandler delegate = it.next();
if (contains(delegate, method)) {
return delegate;
}
}
return null;
}
private boolean contains(Object obj, Method method) {
return extract(obj, method) != null;
}
private Method extract(Object obj, Method method) {
try {
String name = method.getName();
return obj.getClass().getMethod(name, method.getParameterTypes());
} catch (NoSuchMethodException e) {
return null;
}
}
private Object invoke(DelegateQueryHandler delegate, CdiQueryInvocationContext context) {
InvocationContext invocation = context.getInvocation();
try {
return invoke(delegate, invocation.getMethod(), invocation.getParameters());
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
protected Object invoke(Object target, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
Method extract = extract(target, method);
return extract.invoke(target, args);
}
}