/** FormProxyHandler.java. Purpose: Description: History: 11:39:08 AM Jan 9, 2015, Created by jumperchen Copyright (C) 2015 Potix Corporation. All Rights Reserved. */ package org.zkoss.bind.proxy; import java.io.Serializable; import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javassist.util.proxy.MethodFilter; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.Proxy; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyFactoryX; import javassist.util.proxy.ProxyObject; import javassist.util.proxy.SerializedProxyX; import org.zkoss.bind.BindContext; import org.zkoss.bind.Form; import org.zkoss.bind.FormStatus; import org.zkoss.bind.sys.BinderCtrl; import org.zkoss.bind.sys.FormBinding; import org.zkoss.bind.sys.SavePropertyBinding; import org.zkoss.lang.Strings; import org.zkoss.util.Pair; import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.util.Callback; /** * A form proxy handler * @author jumperchen */ public class FormProxyHandler<T> extends BeanProxyHandler<T> { private static final long serialVersionUID = 20150109113926L; protected static MethodFilter FORM_METHOD_FILTER = new MethodFilter() { public boolean isHandled(Method m) { if (m.getName().startsWith("set") || m.getName().startsWith("get") || m.getName().startsWith("is") || m.getName().equals("hashCode")) return true; try { FormProxyObject.class.getMethod(m.getName(), m.getParameterTypes()); return true; } catch (NoSuchMethodException e) { try { Form.class.getMethod(m.getName(), m.getParameterTypes()); return true; } catch (NoSuchMethodException ex) { return false; } } } }; private static final Map<String, Object> _defaultValues = new HashMap<String, Object>(10); static { _defaultValues.put("getResetEmptyStringValue", Strings.EMPTY); _defaultValues.put("getResetNullValue", null); _defaultValues.put("getResetByteValue", (byte) 0); _defaultValues.put("getResetShortValue", (short) 0); _defaultValues.put("getResetIntValue", (int) 0); _defaultValues.put("getResetLongValue", 0L); _defaultValues.put("getResetFloatValue", 0.0f); _defaultValues.put("getResetDoubleValue", 0.0d); _defaultValues.put("getResetBooleanValue", false); _defaultValues.put("getResetCharValue", '\u0000'); } private FormBinding _binding; FormStatusImpl _status; public FormProxyHandler(T origin) { super(origin); _status = new FormStatusImpl(); _node = new ProxyNodeImpl("", null); } private class FormStatusImpl implements FormStatus, Serializable { private static final long serialVersionUID = 1L; private transient FormProxyObject self; public FormStatusImpl() { } public void setOwner(FormProxyObject self) { this.self = self; } public boolean isDirty() { return self.isFormDirty(); } public void reset() { self.resetFromOrigin(); } public void submit(BindContext ctx) { self.submitToOrigin(ctx); } public Object getOrigin() { return self; } // Fix an issue for javassist - https://issues.jboss.org/browse/JASSIST-247 private synchronized void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); Class clazz = self.getClass(); MethodHandler methodHandler = null; if (self instanceof ProxyObject) methodHandler = ((ProxyObject) self).getHandler(); else if (self instanceof Proxy) methodHandler = ProxyFactory.getHandler((Proxy) self); s.writeObject(new SerializedProxyX(clazz, ProxyFactoryX.getFilterSignature(clazz), methodHandler)); } //Fix an issue for javassist - https://issues.jboss.org/browse/JASSIST-247 @SuppressWarnings("rawtypes") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); Object read = s.readObject(); if (read instanceof FormProxyObject) self = (FormProxyObject) read; else if (self instanceof SerializedProxyX) { try { self = (FormProxyObject) ((SerializedProxyX) self).readResolve(); } catch (Exception e) { throw UiException.Aide.wrap(e); } } } } public Object invoke(Object self, Method method, Method proceed, Object[] args) throws Exception { try { final String mname = method.getName(); Class<?> declaringClass = method.getDeclaringClass(); if (declaringClass.equals(FormFieldCleaner.class)) { return _defaultValues.get(mname); } else { if ("setFormOwner".equals(mname)) { //F80: formProxyObject support notifyChange with Form.isDirty addCallbacks(); if (_binding != null) { BinderCtrl binder = (BinderCtrl) _binding.getBinder(); Set<String> saveFormFieldNames = binder.removeSaveFormFieldNames((Form) self); _origin = ProxyHelper.getOriginObject((T) args[0]); _binding = (FormBinding) args[1]; if (!saveFormFieldNames.isEmpty()) binder.addSaveFormFieldName((Form) self, saveFormFieldNames); } else { _origin = ProxyHelper.getOriginObject((T) args[0]); _binding = (FormBinding) args[1]; } return null; } else if ("cacheSavePropertyBinding".equals(mname)) { //ZK-3185: Enable form validation with reference and collection binding ProxyHelper.cacheSavePropertyBinding(_node, (String) args[0], (SavePropertyBinding) args[1]); return null; } else if ("getFormStatus".equals(mname)) { _status.setOwner((FormProxyObject) self); return _status; } else if ("collectCachedSavePropertyBinding".equals(mname)) { //ZK-3185: Enable form validation with reference and collection binding Set<Pair<String, SavePropertyBinding>> sBindings = new HashSet<Pair<String, SavePropertyBinding>>(_node.getCachedSavePropertyBinding()); _node.getCachedSavePropertyBinding().clear(); return sBindings; } return super.invoke(self, method, proceed, args); } } catch (Exception e) { throw UiException.Aide.wrap(e); } } private void addCallbacks() { _node.setOnDataChangeCallback(new Callback() { public void call(Object data) { _binding.getBinder().notifyChange(data, "."); } }); _node.setOnDirtyChangeCallback(new Callback() { public void call(Object data) { _binding.getBinder().notifyChange(_binding.getFormBean().getFormStatus(), "."); } }); } //F80: formProxyObject support notifyChange with Form.isDirty private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); addCallbacks(); } }