/** * */ package org.hivedb.util.classgen; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.hivedb.HiveRuntimeException; import org.hivedb.annotations.AnnotationHelper; import org.hivedb.annotations.EntityId; import org.hivedb.util.DeepHashCode; import org.hivedb.util.PropertyAccessor; import org.hivedb.util.PropertyChangeListenerRegistrar; import org.hivedb.util.classgen.ReflectionTools; import org.hivedb.util.functional.Amass; import org.hivedb.util.functional.Atom; import org.hivedb.util.functional.DebugMap; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.reflect.Method; import java.util.Hashtable; import java.util.Map; public class GeneratedInstanceInterceptor implements MethodInterceptor { private Class clazz; private Map map = new Hashtable(); private PropertyChangeSupport propertySupport; public GeneratedInstanceInterceptor(Class clazz) { this.clazz = clazz; } public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { String name = method.getName(); Implementor implementor = new Implementor(obj); // Fake setters if( name.startsWith("set") && args.length == 1 && method.getReturnType() == Void.TYPE ) { char propName[] = name.substring("set".length()).toCharArray(); propName[0] = Character.toLowerCase( propName[0] ); implementor.set(new String( propName ), args[0]); return null; } else if( name.startsWith("get") && args.length == 0 ) { char propName[] = name.substring("get".length()).toCharArray(); propName[0] = Character.toLowerCase( propName[0] ); return implementor.get(new String( propName )); } else return method.invoke(implementor, args); } /** * Sets the property of an instance by using the setter if it exists or * by using the PropertySetter interface for generated classes * @param instance * @param property * @param value */ public static void setProperty(Object instance, String property, Object value) { if (ReflectionTools.doesRealSetterExist(ReflectionTools.getGetterOfProperty(instance.getClass(), property))) ReflectionTools.invokeSetter(instance, property, value); else if (instance instanceof PropertyAccessor) ((PropertyAccessor)instance).set(property, value); else throw new HiveRuntimeException(String.format("No way to inoke setter of class %s, property %s", instance.getClass(), property)); } private class Implementor implements GeneratedImplementation, PropertyAccessor, PropertyChangeListenerRegistrar, DeepHashCode { Object obj = null; public Implementor(Object obj) { this.obj = obj; } public boolean equals(Object argument) { return argument == null ? false : new Integer(shallowHashCode(obj)).equals(new Integer(shallowHashCode(argument))); } public void set(String propertyName, Object value) { if (value != null) map.put(propertyName, value); } public Object get(String property) { return map.get(property); } @Override public int hashCode() { return shallowHashCode(obj); } @SuppressWarnings("unchecked") public int shallowHashCode(Object obj) { Method idGetter = Atom.getFirstOrNull(AnnotationHelper.getAllMethodsWithAnnotation(clazz, EntityId.class)); if (idGetter != null) try { return Amass.makeHashCode(new Object[]{idGetter.invoke(obj, new Object[] {})}); } catch (Exception e) { throw new RuntimeException(e); } return Amass.makeHashCode(ReflectionTools.invokeGetters(obj, clazz)); } public int deepHashCode(Object obj) { return Amass.makeHashCode(ReflectionTools.invokeGetters(obj, clazz)); } public void addPropertyChangeListener(PropertyChangeListener listener) { propertySupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertySupport.removePropertyChangeListener(listener); } public Map retrieveMap() { return map; } public Class retrieveUnderlyingInterface() { return clazz; } public String toString() { return new DebugMap<Object, Object>(map, true).toString(); } } }