package com.ctp.cdi.query.handler;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import org.jboss.solder.logging.Logger;
import com.ctp.cdi.query.builder.QueryBuilder;
import com.ctp.cdi.query.builder.QueryBuilderFactory;
import com.ctp.cdi.query.meta.DaoComponent;
import com.ctp.cdi.query.meta.DaoComponents;
import com.ctp.cdi.query.meta.DaoMethod;
import com.ctp.cdi.query.meta.Initialized;
/**
* Entry point for query processing.
*
* @author thomashug
*/
public class QueryHandler implements Serializable {
private static final long serialVersionUID = 1L;
private final Logger log = Logger.getLogger(getClass());
@Inject @Any
private Instance<EntityManager> entityManager;
@Inject
private QueryBuilderFactory queryBuilder;
@Inject @Initialized
private DaoComponents components;
@Inject
private Event<CdiQueryInvocationContext> contextCreated;
@AroundInvoke
public Object handle(InvocationContext context) {
CdiQueryInvocationContext queryContext = null;
try {
Class<?> daoClass = extractFromProxy(context);
DaoComponent dao = components.lookupComponent(daoClass);
DaoMethod method = components.lookupMethod(daoClass, context.getMethod());
queryContext = createContext(context, dao, method);
QueryBuilder builder = queryBuilder.build(method);
return builder.execute(queryContext);
} catch (Exception e) {
log.error("Query execution error", e);
if (queryContext != null) {
throw new QueryInvocationException(e, queryContext);
}
throw new QueryInvocationException(e, context);
}
}
private CdiQueryInvocationContext createContext(InvocationContext context, DaoComponent dao, DaoMethod method) {
CdiQueryInvocationContext queryContext = new CdiQueryInvocationContext(context, method, resolveEntityManager(dao));
contextCreated.fire(queryContext);
return queryContext;
}
protected Class<?> extractFromProxy(InvocationContext ctx) {
Class<?> proxyClass = ctx.getTarget().getClass();
if (ProxyFactory.isProxyClass(proxyClass)) {
if (isInterfaceProxy(proxyClass)) {
return extractFromInterface(proxyClass);
} else {
return proxyClass.getSuperclass();
}
}
return proxyClass;
}
private boolean isInterfaceProxy(Class<?> proxyClass) {
Class<?>[] interfaces = proxyClass.getInterfaces();
return Object.class.equals(proxyClass.getSuperclass()) &&
interfaces != null && interfaces.length > 0;
}
private Class<?> extractFromInterface(Class<?> proxyClass) {
for (Class<?> interFace : proxyClass.getInterfaces()) {
if (!ProxyObject.class.equals(interFace)) {
return interFace;
}
}
return null;
}
private EntityManager resolveEntityManager(DaoComponent dao) {
Annotation[] qualifiers = extractFromTarget(dao.getDaoClass());
if (qualifiers == null || qualifiers.length == 0) {
qualifiers = dao.getEntityManagerQualifiers();
}
if (qualifiers == null || qualifiers.length == 0) {
return entityManager.get();
}
return entityManager.select(qualifiers).get();
}
private Annotation[] extractFromTarget(Class<?> target) {
try {
Method method = target.getDeclaredMethod("getEntityManager");
return method.getAnnotations();
} catch (Exception e) {
return null;
}
}
}