package io.anyway.hera.jdbc;
import javax.naming.Referenceable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.*;
final public class JdbcWrapperHelper {
private static final Map<Class<?>, Constructor<?>> PROXY_CACHE = Collections
.synchronizedMap(new WeakHashMap<Class<?>, Constructor<?>>());
private JdbcWrapperHelper() {
super();
}
static <T> T createProxy(T object, InvocationHandler invocationHandler,
List<Class<?>> interfaces) {
final Class<? extends Object> objectClass = object.getClass();
Constructor<?> constructor = PROXY_CACHE.get(objectClass);
if (constructor == null) {
final Class<?>[] interfacesArray = getObjectInterfaces(objectClass, interfaces);
constructor = getProxyConstructor(objectClass, interfacesArray);
if (interfaces == null) {
PROXY_CACHE.put(objectClass, constructor);
}
}
try {
return (T) constructor.newInstance(new Object[] { invocationHandler });
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
private static Constructor<?> getProxyConstructor(Class<? extends Object> objectClass,
Class<?>[] interfacesArray) {
final ClassLoader classLoader = objectClass.getClassLoader(); // NOPMD
try {
final Constructor<?> constructor = Proxy.getProxyClass(classLoader, interfacesArray)
.getConstructor(new Class[] { InvocationHandler.class });
constructor.setAccessible(true);
return constructor;
} catch (final NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
private static Class<?>[] getObjectInterfaces(Class<?> objectClass, List<Class<?>> interfaces) {
final List<Class<?>> myInterfaces;
if (interfaces == null) {
myInterfaces = new ArrayList<Class<?>>(Arrays.asList(objectClass.getInterfaces()));
Class<?> classe = objectClass.getSuperclass();
while (classe != null) {
final Class<?>[] classInterfaces = classe.getInterfaces();
if (classInterfaces.length > 0) {
final List<Class<?>> superInterfaces = Arrays.asList(classInterfaces);
// removeAll d'abord car il ne faut pas de doublon dans la liste
myInterfaces.removeAll(superInterfaces);
myInterfaces.addAll(superInterfaces);
}
classe = classe.getSuperclass();
}
myInterfaces.remove(Referenceable.class);
} else {
myInterfaces = interfaces;
}
return myInterfaces.toArray(new Class<?>[myInterfaces.size()]);
}
}