package com.aggrepoint.dao; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import javax.persistence.EntityManager; import org.hibernate.SessionFactory; import org.springframework.cache.CacheManager; import org.springframework.core.convert.ConversionService; import com.aggrepoint.dao.annotation.Cache; import com.aggrepoint.dao.annotation.Delete; import com.aggrepoint.dao.annotation.Deletes; import com.aggrepoint.dao.annotation.Find; import com.aggrepoint.dao.annotation.Finds; import com.aggrepoint.dao.annotation.Load; import com.aggrepoint.dao.annotation.Update; import com.aggrepoint.dao.annotation.Updates; /** * * @author Jiangming Yang (yangjm@gmail.com) * */ public class DaoInvocationHandler<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = 1L; EntityManager entityManager; SessionFactory sessionFactory; CacheManager cacheManager; Class<T> clz; Hashtable<Method, ArrayList<DaoMethod<T>>> htDaoMethods = new Hashtable<Method, ArrayList<DaoMethod<T>>>(); void addDaoMethod(Method method, DaoMethod<T> daoMethod) { ArrayList<DaoMethod<T>> arr = htDaoMethods.get(method); if (arr == null) { arr = new ArrayList<DaoMethod<T>>(); htDaoMethods.put(method, arr); } arr.add(daoMethod); } public DaoInvocationHandler(EntityManager entityManager, SessionFactory factory, CacheManager cacheManager, ConversionService cs, Class<?> daoInterface, Class<T> clz, List<IFunc> funcs) { this.entityManager = entityManager; this.sessionFactory = factory; this.cacheManager = cacheManager; this.clz = clz; for (Method method : daoInterface.getMethods()) { boolean found = false; for (Method m : DaoService.class.getMethods()) { if (method.equals(m)) { addDaoMethod(method, new DaoBaseMethod<T>(clz, method, entityManager, sessionFactory)); found = true; break; } } if (!found) for (Method m : HibernateDao.class.getMethods()) { if (method.equals(m)) { addDaoMethod(method, new DaoBaseMethod<T>(clz, method, entityManager, sessionFactory)); found = true; break; } } if (!found) for (Annotation ann : method.getDeclaredAnnotations()) { Class<?> t = ann.annotationType(); if (t == Find.class || t == Cache.class || t == Update.class || t == Delete.class || t == Load.class) { addDaoMethod(method, new DaoAnnotationMethod<T>(clz, method, ann, funcs, entityManager, sessionFactory, cacheManager, cs)); found = true; } else if (t == Finds.class) { for (Annotation a : ((Finds) ann).value()) addDaoMethod(method, new DaoAnnotationMethod<T>( clz, method, a, funcs, entityManager, sessionFactory, cacheManager, cs)); found = true; } else if (t == Updates.class) { for (Annotation a : ((Updates) ann).value()) addDaoMethod(method, new DaoAnnotationMethod<T>( clz, method, a, funcs, entityManager, sessionFactory, cacheManager, cs)); found = true; } else if (t == Deletes.class) { for (Annotation a : ((Deletes) ann).value()) addDaoMethod(method, new DaoAnnotationMethod<T>( clz, method, a, funcs, entityManager, sessionFactory, cacheManager, cs)); found = true; } } if (!found && !method.isDefault()) throw new IllegalArgumentException("Unsupported method " + daoInterface.getName() + "." + method.getName() + "."); } } static Method equals; static Method hashCode; static Method toString; static { try { equals = Object.class.getMethod("equals", Object.class); hashCode = Object.class.getMethod("hashCode"); toString = Object.class.getMethod("toString"); } catch (Exception e) { e.printStackTrace(); } } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { ArrayList<DaoMethod<T>> arr = htDaoMethods.get(method); if (arr != null) { Object ret = null; for (DaoMethod<T> hdm : arr) { if (hdm.match(args)) ret = hdm.invoke(proxy, method, args); } return ret; } if (equals.equals(method)) { return proxy == args[0]; } else if (hashCode.equals(method)) { return proxy.getClass().hashCode(); } else if (toString.equals(method)) { return proxy.getClass().toString(); } else if (method.isDefault()) { Class<?> declaringClass = method.getDeclaringClass(); return DaoAnnotationMethod.CONSTRUCTOR .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) .unreflectSpecial(method, declaringClass).bindTo(proxy) .invokeWithArguments(args); } return null; } catch (Throwable t) { throw t; } } }