org.zkoss.bind.proxy.BeanProxyHandler Maven / Gradle / Ivy
The newest version!
/** BeanProxyHandler.java.
Purpose:
Description:
History:
12:16:01 PM Dec 25, 2014, Created by jumperchen
Copyright (C) 2014 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.bind.proxy;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import org.zkoss.bind.BindContext;
import org.zkoss.bind.annotation.ImmutableFields;
import org.zkoss.bind.annotation.Transient;
import org.zkoss.bind.impl.AllocUtil;
import org.zkoss.bind.sys.SavePropertyBinding;
import org.zkoss.bind.xel.zel.BindELContext;
import org.zkoss.lang.Classes;
import org.zkoss.zk.ui.UiException;
/**
* A bean proxy handler
*
* @author jumperchen
* @since 8.0.0
*/
public class BeanProxyHandler implements MethodHandler, Serializable {
protected static MethodFilter BEAN_METHOD_FILTER = new MethodFilter() {
public boolean isHandled(Method m) {
if (m.isAnnotationPresent(Transient.class))
return false;
final String name = m.getName();
if ("hashCode".equals(name) || "equals".equals(name))
return true;
if (ProxyHelper.isAttribute(m)) {
if (name.startsWith("set"))
return isSetMethodHandled(m);
if (name.startsWith("get") || name.startsWith("is"))
return true;
}
try {
FormProxyObject.class.getMethod(name, m.getParameterTypes());
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
};
protected T _origin;
protected Map _cache;
protected Set _dirtyFieldNames; // field name that is dirty
//ZK-3185: Enable form validation with reference and collection binding
protected ProxyNode _node;
public BeanProxyHandler(T origin) {
_origin = origin;
}
protected static boolean isSetMethodHandled(Method m) {
try {
final String getter = ProxyHelper.toGetter(ProxyHelper.toAttrName(m));
final Method getMethod = Classes.getMethodByObject(m.getDeclaringClass(), getter, null);
if (getMethod.isAnnotationPresent(Transient.class))
return false;
} catch (NoSuchMethodException e) {
// ignore if no getter available
}
return true;
}
private void addCache(String key, Object value) {
_cache = AllocUtil.inst.putMap(_cache, key, value);
}
private void addDirtyField(String field) {
_dirtyFieldNames = AllocUtil.inst.addSet(_dirtyFieldNames, field);
}
//ZK-3185: Enable form validation with reference and collection binding
private void setPath(String property, ProxyNode parent) {
if (property == null && _node != null) // means update
_node.setParent(parent);
else
_node = new ProxyNodeImpl(property, parent);
}
public Object invoke(Object self, Method method, Method proceed, Object[] args) throws Exception {
try {
final String mname = method.getName();
if (mname.equals("hashCode")) {
int a = (_origin != null) ? (Integer) method.invoke(_origin, args) : 0;
return 37 * 31 + a;
}
if (mname.equals("equals")) {
if (_origin != null) {
if (_origin instanceof FormProxyObject) {
return method.invoke(((FormProxyObject) _origin).getOriginObject(), args);
} else if (args.length == 1 && args[0] instanceof FormProxyObject) {
return method.invoke(_origin, new Object[] { ((FormProxyObject) args[0]).getOriginObject() });
} else {
return method.invoke(_origin, args);
}
}
// check null value
return args.length == 1 && args[0] == null;
}
if (method.getDeclaringClass().isAssignableFrom(FormProxyObject.class)) {
if ("submitToOrigin".equals(mname)) {
if (_origin != null && _cache != null) {
for (Map.Entry me : _cache.entrySet()) {
final Object value = me.getValue();
if (value instanceof FormProxyObject) {
((FormProxyObject) value).submitToOrigin((BindContext) args[0]);
}
if (_dirtyFieldNames != null && _dirtyFieldNames.contains(me.getKey())) {
final String setter = ProxyHelper.toSetter(me.getKey());
try {
final Method m = Classes.getMethodByObject(_origin.getClass(), setter,
new Object[] { value });
m.invoke(_origin, Classes.coerce(m.getParameterTypes()[0], value));
BindELContext.addNotifys(m, _origin, me.getKey(), value, (BindContext) args[0]);
} catch (NoSuchMethodException e) {
throw UiException.Aide.wrap(e);
}
}
}
if (_dirtyFieldNames != null)
_dirtyFieldNames.clear();
}
} else if ("getOriginObject".equals(mname)) {
return _origin;
} else if ("resetFromOrigin".equals(mname)) {
if (_dirtyFieldNames != null)
_dirtyFieldNames.clear();
if (_cache != null)
_cache.clear();
} else if ("isFormDirty".equals(mname)) {
boolean dirty = false;
if (_cache != null) {
// If the dirty field is a form proxy object it may not be dirty.
// But once it contains a non-form proxy object, it must be dirty.
for (Map.Entry me : _cache.entrySet()) {
final Object value = me.getValue();
if (_dirtyFieldNames != null && _dirtyFieldNames.contains(me.getKey())) {
dirty = true;
break;
}
if (value instanceof FormProxyObject) {
if (((FormProxyObject) value).isFormDirty()) {
dirty = true;
break;
}
}
}
}
return dirty;
} else if ("setPath".equals(mname)) {
//ZK-3185: Enable form validation with reference and collection binding
setPath((String) args[0], (ProxyNode) args[1]);
} else if ("cacheSavePropertyBinding".equals(mname)) {
//ZK-3185: Enable form validation with reference and collection binding
ProxyHelper.cacheSavePropertyBinding(_node, _node.getProperty() + "." + (String) args[0], (SavePropertyBinding) args[1]);
return null;
} else {
throw new IllegalAccessError("Not implemented yet for FormProxyObject interface: [" + mname + "]");
}
} else {
if (mname.startsWith("get")) {
if (_origin == null)
return null;
final String attr = ProxyHelper.toAttrName(method);
if (_cache != null) {
if (_cache.containsKey(attr)) {
Object cacheData = _cache.get(attr);
if (_origin.getClass().getAnnotation(ImmutableFields.class) == null
&& !(self instanceof ImmutableFields)) {
// ZK-2736 Form proxy with Immutable values
Object proxyIfAny = ProxyHelper.createProxyIfAny(
cacheData, method.getAnnotations());
addCache(attr, proxyIfAny);
return proxyIfAny;
}
return cacheData;
}
}
Object value = method.invoke(_origin, args);
if (value != null) {
if (_origin.getClass().getAnnotation(ImmutableFields.class) == null
&& !(self instanceof ImmutableFields)) {
// ZK-2736 Form proxy with Immutable values
value = ProxyHelper.createProxyIfAny(value, method.getAnnotations());
}
addCache(attr, value);
if (value instanceof FormProxyObject) //ZK-3185: Enable form validation with reference and collection binding
((FormProxyObject) value).setPath(attr, _node);
}
return value;
} else if (mname.startsWith("is")) {
if (_origin == null)
return false;
final String attr = ProxyHelper.toAttrName(method, 2);
if (_cache != null) {
if (_cache.containsKey(attr)) {
return _cache.get(attr);
}
}
return method.invoke(_origin, args);
} else {
final String attrName = ProxyHelper.toAttrName(method);
addCache(attrName, args[0]);
addDirtyField(attrName);
ProxyHelper.callOnDataChange(_node, new Object[]{self, attrName});
ProxyHelper.callOnDirtyChange(_node);
}
}
} catch (Exception e) {
throw UiException.Aide.wrap(e);
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy