Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /* Binding.java
  
  {{IS_NOTE
  	Purpose:
  		
  	Description:
  		
  	History:
  		Thu Feb  1 17:13:40     2007, Created by Henri
 }}IS_NOTE
 
 Copyright (C) 2006 Potix Corporation. All Rights Reserved.
 
 {{IS_RIGHT
 }}IS_RIGHT
 */
 package org.zkoss.zkplus.databind;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static org.zkoss.lang.Generics.cast;
 
A Data Binding that associate component+attr to an bean expression.

Deprecated:
As of release 7.0.0, replace with new ZK binding.
Author(s):
Henri
Since:
3.0.0
 
 public class Binding implements java.io.Serializable {
 	private static final long serialVersionUID = 200808191512L;
 	private DataBinder _binder;
 	private Component _comp;
 	private String _attr;
 	private String _expression//the bean expression
 	private boolean _loadable = true;
 	private boolean _savable;
 	private String[] _paths//bean reference path (a.b.c)
 	private Map<ObjectObject_args//generic arguments
 	
Constructor to form a binding between UI component and backend data bean.

Parameters:
binder the associated Data Binder.
comp The concerned component
attr The component attribute
expr The bean expression.
loadWhenEvents The event set when to load data.
saveWhenEvents The event set when to save data.
access In the view of UI component: "load" load only, "both" load/save, "save" save only when doing data binding. null means using the default access natural of the component. e.g. Label.expr is "load", but Textbox.expr is "both".
converter The converter class used to convert classes between component attribute and the associated bean expression. null means using the default class conversion method.
 
 	/*package*/ Binding(DataBinder binderComponent compString attrString expr
 		LinkedHashSet<StringloadWhenEventsLinkedHashSet<StringsaveWhenEventsString accessString converter) {
 		this(bindercompattrexprloadWhenEventssaveWhenEventsaccessconverternullnullnull);
 	}

Constructor to form a binding between UI component and backend data bean.

Parameters:
binder the associated Data Binder.
comp The concerned component
attr The component attribute
expr The bean expression.
loadWhenEvents The event set when to load data.
saveWhenEvents The event set when to save data.
access In the view of UI component: "load" load only, "both" load/save, "save" save only when doing data binding. null means using the default access natural of the component. e.g. Label.expr is "load", but Textbox.expr is "both".
converter The converter class used to convert classes between component attribute and the associated bean expression. null means using the default class conversion method.
args generic arguments
Since:
3.1
 
 	/*package*/ Binding(DataBinder binderComponent compString attrString expr
		LinkedHashSet<StringloadWhenEventsLinkedHashSet<StringsaveWhenEventsString accessString converterMap<ObjectObjectargs) {
		this(bindercompattrexprloadWhenEventssaveWhenEventsaccessconverterargsnullnull);
	}

Constructor to form a binding between UI component and backend data bean.

Parameters:
binder the associated Data Binder.
comp The concerned component
attr The component attribute
expr The bean expression.
loadWhenEvents The event set when to load data.
saveWhenEvents The event set when to save data.
access In the view of UI component: "load" load only, "both" load/save, "save" save only when doing data binding. null means using the default access natural of the component. e.g. Label.expr is "load", but Textbox.expr is "both".
converter The converter class used to convert classes between component attribute and the associated bean expression. null means using the default class conversion method.
args generic arguments
loadAfterEvents the event set when to load data after
saveAfterEvents the event set when to save data after
Since:
3.6.1
	/*package*/ Binding(DataBinder binderComponent compString attrString expr
		LinkedHashSet<StringloadWhenEventsLinkedHashSet<StringsaveWhenEventsString accessString converterMap<ObjectObjectargs,
		LinkedHashSet<StringloadAfterEventsLinkedHashSet saveAfterEvents) {
		 = binder;
		 = comp;
		setAttr(attr);
		setLoadWhenEvents(loadWhenEvents);
		setLoadAfterEvents(loadAfterEvents);
		setSaveWhenEvents(saveWhenEvents);
		setSaveAfterEvents(saveAfterEvents);
		setAccess(access);
		setConverter(converter);
		setArgs(args);
	}

Gets the associated Data Binder of this Binding.
	public DataBinder getBinder() {
		return ;
	}

Gets the associated Component of this Binding.
	public Component getComponent() {
		return ;
	}

Set component attribute name.

Parameters:
attr component attribute.
	/*package*/void setAttr(String attr) {
		 = attr;
	}

Get component attribute name.
	public String getAttr() {
		return ;
	}
	/*package*/void setArgs(Map<ObjectObjectargs) {
		 = args;
	}

Get generic arguments.
	public Map<ObjectObjectgetArgs() {
		return ;
	}

Set bean expression (a.b.c).
	/*package*/ void setExpression(String expr) {
		 = expr;
	}
	//:TODO: handle function parsing	
	private String[] parseBeanExpression(String expr) {
		String[] paths = new String[1];
		paths[0] = expr;
		return paths;
	}

Get bean expression, e.g. a.b.c.
	public String getExpression() {
		return ;
	}

Internal methods. DO NOT USE THIS. Get bean reference paths.
	/*package*/ String[] getPaths() {
		return ;
	}

Set save-when event expression.

Parameters:
saveWhenEvents the save-when expression.
	/*package*/ void setSaveWhenEvents(LinkedHashSet<StringsaveWhenEvents) {
		 = saveWhenEvents;
	}

Get save-when event expression.
	}

Set save-after event expression.

Parameters:
saveAfterEvents the save-after expression.
	/*package*/ void setSaveAfterEvents(LinkedHashSet saveAfterEvents) {
		 = saveAfterEvents;
	}

Get save-after event expression.
	public Set getAfterWhenEvents() {
	}


Add load-when event expression.

Parameters:
loadWhenEvent the load-when expression.
	/*package*/ void setLoadWhenEvents(LinkedHashSet<StringloadWhenEvents) {
		 = loadWhenEvents;
	}

Get load-when event expression set.
	}

Add load-after event expression.

Parameters:
loadAfterEvents the load-after expression.
	/*package*/ void setLoadAfterEvents(LinkedHashSet<StringloadAfterEvents) {
		 = loadAfterEvents;
	}

Get load-after event expression set.
	}

Set accessibility.
	/*package*/ void setAccess(String access) {
		if (access == null) { //default access to none
			return;
		}
		if ("both".equals(access)) {
			 = true;
			 = true;
else if ("load".equals(access)) {
			 = true;
			 = false;
else if ("save".equals(access)) {
			 = false;
			 = true;
else if ("none".equals(access)) { 
			 = false;
			 = false;
else {//unknow access mode
			throw new UiException("Unknown DataBinder access mode. Should be \"both\", \"load\", \"save\", or \"none\": "+access);
		}
	}

Whether the binding is loadable.
	public boolean isLoadable() {
		return ;
	}

Whether the binding is savable.
	public boolean isSavable() {
		return ;
	}

Set the TypeConverter.

Parameters:
cvtClsName the converter class name.
	/*package*/ void setConverter(String cvtClsName) {
		if (cvtClsName != null) {
			//bug #2129992
			Class cls = null;
			if ( == null || .getPage() == null) {
				try {
					cls = Classes.forNameByThread(cvtClsName);
catch (ClassNotFoundException ex) {
					throw UiException.Aide.wrap(ex);
				}
else {
				try {
					cls = .getPage().resolveClass(cvtClsName); 
catch (ClassNotFoundException ex) {
					throw UiException.Aide.wrap(ex);
				}
			}
			try {
catch (Exception ex) {
				throw UiException.Aide.wrap(ex);
			}
		}
	}

Get the TypeConverter.
		return ;
	}

load bean value into the attribute of the specified component.

Parameters:
comp the component.
	public void loadAttribute(Component comp) {
		if (!isLoadable() 
				|| .startsWith("_"
				|| DataBinder.isTemplate(comp)
				|| comp == null //bug #1941947 Cannot find associated CollectionItem
				|| comp.getPage() == null) { 
			return//cannot load, a control attribute, or a detached component, skip!
		}
		myLoadAttribute(compbean);
	}

Returns the associated bean of this binding; e.g., for a binding to the bean "a.b.c", this will return the bean associated to "a.b" (and c is the property name).

Note if the expression is associated to a single variable; e.g. "a" only, this method returns null.

Parameters:
comp
Returns:
the associated bean of this binding.
Since:
5.0.7
	public Object getBean(Component comp) {
		if ( != null) {
			int j = .lastIndexOf('.');
			if (j >= 0) {
			}
		}
		return null;
	}

load bean value into the attribute of the specified component.

Parameters:
comp the component.
bean the bean value.
	public void loadAttribute(Component compObject bean) {
		if (!isLoadable() || .startsWith("_") || DataBinder.isTemplate(comp) || comp.getPage() == null) { 
			return//cannot load, a control attribute, or a detached component, skip!
		}
		myLoadAttribute(compbean);
	}
	private void myLoadAttribute(Component compObject bean) {
		try {
			//since 3.1, 20080416, support bindingArgs for non-supported tag
			//bug #2803575, merge bindingArgs together since a component can have
			//multiple bindings on different attributes.
			Map<ObjectObjectbindArgs = cast((Mapcomp.getAttribute(.));
			if (bindArgs == null) {
				bindArgs = new HashMap<ObjectObject>();
				comp.setAttribute(.bindArgs);
			}
			if ( != null) {
				bindArgs.putAll();
			}
			if ( != null) {
				bean = .coerceToUi(beancomp);
				if (bean == .)
					return//ignore, so don't do Fields.set()
			}
			//Bug #1876198 Error msg appears when load page (databind+CustomConstraint)
			//catching WrongValueException no longer works, check special case and 
			//use setRowValue() method directly
			if ((comp instanceof InputElement) && "value".equals()) {
				Object value = bean;
				Object oldv = null;
				try { //Bug 1879389
					final Method m = comp.getClass().getMethod("getValue");
					oldv = ((InputElement)comp).getRawValue();
					value = Classes.coerce(m.getReturnType(), bean);
catch (NoSuchMethodException ex) { //ignore it
				}
				//See both Bug 3000305 and 2874098
				Fields.set(comp"rawValue"value == null);
else {
				Fields.set(compbean == null);
			}
catch (ClassCastException ex) {
			throw UiException.Aide.wrap(ex);
catch (NoSuchMethodException ex) {
			//Bug #1813278, Annotations do not work with xhtml tags
			if (comp instanceof DynamicPropertied) {
				final DynamicPropertied dpcomp = (DynamicPropertiedcomp;
 				if (dpcomp.hasDynamicProperty()) {
					//no way to know destination type of the property, use bean as is
 					dpcomp.setDynamicProperty(bean);
 				} else {
 					throw UiException.Aide.wrap(ex);
 				}
else { //Feature# 2855116. Save into component custom-attribute(also a variable in ZK5).
				comp.setAttribute(bean);
			}
		//Bug #1876198 Error msg appears when load page (databind+CustomConstraint)
		//catching WrongValueException no longer works, so mark it out
		/*} catch (WrongValueException ex) {
			//Bug #1615371, try to use setRawValue()
			if ("value".equals(_attr)) {
				try {
					Fields.set(comp, "rawValue", bean, _converter == null);
				} catch (Exception ex1) {
					//exception
					throw ex;
				}
			} else {
				throw ex;
			}
		*/
		}
	}

save into bean value from the attribute of the specified component.

Parameters:
comp the component.
	public void saveAttribute(Component comp) {
		final Object[] vals = getAttributeValues(comp);
		if (vals != null)
			saveAttributeValue(compvalsnullnull);
	}
	private void saveAttributeValue(Component compObject[] valsList<ObjectloadOnSaveInfosString triggerEventName) {
		if (vals == nullreturn;
		final Object val = vals[0];
		final Object rawval = vals[1];
		.setBeanAndRegisterBeanSameNodes(compvalthis == nullrawvalloadOnSaveInfostriggerEventName);
	}		

Get converted value and original value of this Binding.
	private Object[] getAttributeValues(Component comp) {
		if (!isSavable() || .startsWith("_") || DataBinder.isTemplate(comp) || comp.getPage() == null) { 
			return null//cannot save, a control attribute, or a detached component, skip!
		}
		Object rawval = null;
		try {
			rawval = Fields.get(comp);
catch (NoSuchMethodException ex) {
			//Bug #1813278, Annotations do not work with xhtml tags
			if (comp instanceof DynamicPropertied) {
				final DynamicPropertied dpcomp = (DynamicPropertiedcomp;
 				if (dpcomp.hasDynamicProperty()) {
 					rawval = dpcomp.getDynamicProperty();
 				} else {
 					throw UiException.Aide.wrap(ex);
 				}
else if (comp.getAttributes().containsKey()) { //Feature #2855116. Get value from component custom-attribute(also a variable in ZK5).
				rawval = comp.getAttribute();
else {
				throw UiException.Aide.wrap(ex);
			}
		}
		try {
			final Object val = ( == null) ? rawval : .coerceToBean(rawvalcomp);
			return val == . ? null : new Object[] {valrawval};
catch (ClassCastException ex) {
			throw UiException.Aide.wrap(ex);
		}
	}		
	/*package*/ void registerSaveEvents(Component comp) {
		if (isSavable()) { //bug 1804356
			if ( != null) { 
				for(String expr) {
					final Object[] objs =
						ComponentsCtrl.parseEventExpression(compexprcompfalse);
					//objs[0] component, objs[1] event name
					final Component target = (Componentobjs[0];
					final String evtname = (Stringobjs[1];
						target.getAttribute("zk.SaveEventListener."+evtname);
					if (listener == null) {
						listener = new SaveEventListener();
						target.setAttribute("zk.SaveEventListener."+evtnamelistener);
						target.addEventListener(1000, evtnamelistener);
					}
					listener.addDataTarget(thiscomp);
				}
			}
			if ( != null) {
				for(final Iterator it = .iterator(); it.hasNext(); ) {
					final String expr = (Stringit.next();
					final Object[] objs =
						ComponentsCtrl.parseEventExpression(compexprcompfalse);
					//objs[0] component, objs[1] event name
					final Component target = (Componentobjs[0];
					final String evtname = (Stringobjs[1];
						target.getAttribute("zk.SaveAfterEventListener."+evtname);
					if (listener == null) {
						listener = new SaveAfterEventListener();
						target.setAttribute("zk.SaveAfterEventListener."+evtnamelistener);
						target.addEventListener(evtnamelistener);
						target.addEventListener(evtname+"SaveAfter"listener);
					}
					listener.addDataTarget(thiscomp);
				}
			}
		}
	}
	/*package*/ void registerLoadEvents(Component comp) {
		if (isLoadable()) { //bug 1804356
			if ( != null) {
				for(String expr) {
					final Object[] objs =
						ComponentsCtrl.parseEventExpression(compexprcompfalse);
					//objs[0] component, objs[1] event name
					final Component target = (Componentobjs[0];
					final String evtname = (Stringobjs[1];
					if(target==null){
						throw new NullPointerException("component not found , expr is "+expr);
					}
						target.getAttribute("zk.LoadEventListener."+evtname);
					if (listener == null) {
						listener = new LoadEventListener();
						target.setAttribute("zk.LoadEventListener."+evtnamelistener);
						target.addEventListener(1000, evtnamelistener);
					}
					listener.addDataTarget(thiscomp);
				}
			if ( != null) {
				for(String expr) {
					final Object[] objs =
						ComponentsCtrl.parseEventExpression(compexprcompfalse);
					//objs[0] component, objs[1] event name
					final Component target = (Componentobjs[0];
					final String evtname = (Stringobjs[1];
						target.getAttribute("zk.LoadAfterEventListener."+evtname);
					if (listener == null) {
						listener = new LoadAfterEventListener();
						target.setAttribute("zk.LoadAfterEventListener."+evtnamelistener);
						target.addEventListener(evtnamelistener);
						target.addEventListener(evtname+"LoadAfter"listener);
					}
					listener.addDataTarget(thiscomp);
				}
			}
		}
	}
	//-- Object --//
	public String toString() {
		return "[binder:"++", comp:"++", attr:"++", expr:"+
			+", load-when:"++", save-when:"+
			+", load-after:"++", save-after:"+
			+", load:"++", save:"++", converter:"++"]";
	}
	private static class BindingInfo implements Serializable {
		private static final long serialVersionUID = 200808191315L;
		private Binding _binding;
		private Component _comp;
		private Object[] _vals;
		public BindingInfo(Binding bindingComponent compObject[] vals) {
			 = binding;
			 = comp;
			 = vals;
		}
		public Component getComponent() {
			return ;
		}
		public Binding getBinding() {
			return ;
		}
		public Object[] getAttributeValues() {
			return ;
		}
	}
	private static abstract class BaseEventListener implements EventListener<Event>, java.io.Serializable {
		public BaseEventListener() {
		}
		public void addDataTarget(Binding bindingComponent comp) {
			.add(new BindingInfo(bindingcompnull));
		}
	}
	private abstract static class BaseLoadEventListener extends BaseEventListener {
			super();
		}
		protected void handleEvent(Event event) {
				final Component dt = bi.getComponent();
				final Binding binding = bi.getBinding();
				final DataBinder binder = binding.getBinder();
				final Component dataTarget = DataBinder.isTemplate(dt) ? 
					DataBinder.lookupClone(event.getTarget(), dt) : dt;
				if (dataTarget != null) {
					binding.loadAttribute(dataTarget);
else { //#bug 2897202
					final List<Componentclones = scanClones(binderdt);
					for (final Component dataTarget1clones) {
						binding.loadAttribute(dataTarget1);
					}
				}
			}
		}
	}
	private static class LoadEventListener extends BaseLoadEventListener {
		private static final long serialVersionUID = 200808191313L;
		public LoadEventListener() {
		}
		public void onEvent(Event event) {
		}
	}
	//since 3.6.1
	private static class LoadAfterEventListener extends BaseLoadEventListener {
		private static final long serialVersionUID = 20090423120513L;
			super();
		}
		public void onEvent(Event event) {
			if (event instanceof AfterEvent) {
else { //post AfterEvent to make sure it is called after
				//enforce the event is the last processed
				Events.postEvent(-10100, new AfterEvent(event.getName()+"LoadAfter"event));
			}
		}
	}
	//since 3.6.1
	private static class AfterEvent extends Event {
		public AfterEvent(String evtnmEvent event) {
			super(evtnmevent.getTarget(), event);
		}
	}
	//since 3.6.1
	private static class SaveAfterEventListener extends BaseSaveEventListener {
		private static final long serialVersionUID = 20090423143051L;
			super();
		}
		public void onEvent(Event event) {
			if (event instanceof AfterEvent) {
else { //post AfterEvent to make sure it is called after
				//enforce the event is the last processed
				Events.postEvent(-10100, new AfterEvent(event.getName()+"SaveAfter"event));
			}
		}
	}
	private static class SaveEventListener extends BaseSaveEventListener {
		private static final long serialVersionUID = 200808191313L;
		public SaveEventListener() {
		}
		public void onEvent(Event event) {
		}
	}
	private static abstract class BaseSaveEventListener extends BaseEventListener {
			super();
		}
		protected void handleEvent(Event event) {
			final Component target = event.getTarget();
			final String triggerEventName = event.getName();
			final List<BindingInfotmplist = new ArrayList<BindingInfo>(.size());
			final List<Objectvalues = new LinkedList<Object>();
			final List<Componentrefs = new LinkedList<Component>();
			final List<Bindingbindings = new LinkedList<Binding>();
			//fire onSave for each binding
				final Component dt = bi.getComponent();
				final Binding binding = bi.getBinding();
				final DataBinder binder = binding.getBinder();
				final Component dataTarget = DataBinder.isTemplate(dt) ? 
					DataBinder.lookupClone(targetdt) : dt;
				//bug# 1904389: NullPointerException if save-when in collection binding
				//event.getTarget() might not inside the collection item (i.e. row, listitem, etc.)
				//then binder.lookupClone() will return null dataTarget.
				if (dataTarget != null) {
					final Object[] vals = binding.getAttributeValues(dataTarget);
					if (vals != null) {
						tmplist.add(new BindingInfo(bindingdataTargetvals));
						values.add(vals[0]);
						refs.add(dataTarget);
						bindings.add(binding);
						Events.sendEvent(new BindingSaveEvent("onBindingSave"dataTargettargetbindingvals[0]));
					}
else {
					//bi.getComponent a template and a null dataTarget, meaning all collection items has to
					//be handled. Search the owner to iterate all cloned items.
					final List<Componentclones = scanClones(binderdt);
					for (Component dataTarget1clones) {
						final Object[] vals = binding.getAttributeValues(dataTarget1);
						if (vals != null) {
							tmplist.add(new BindingInfo(bindingdataTarget1vals));
							values.add(vals[0]);
							refs.add(dataTarget1);
							bindings.add(binding);
							Events.sendEvent(new BindingSaveEvent("onBindingSave"dataTarget1targetbindingvals[0]));
						}
					}
				}
			}
			//fire onValidate for target component
			Events.sendEvent(new BindingValidateEvent("onBindingValidate"targetrefsbindingsvalues));
			//saveAttribute for each binding
			Component loadOnSaveProxy = null;
			Component dataTarget = null;
			DataBinder binder = null;
			final List<ObjectloadOnSaveInfos = new ArrayList<Object>(tmplist.size());
			for(BindingInfo bitmplist) {
				dataTarget = bi.getComponent();
				final Binding binding = bi.getBinding();
				if (binder == null) {
					binder = binding.getBinder();
				}
				final Object[] vals = bi.getAttributeValues();
				binding.saveAttributeValue(dataTargetvalsloadOnSaveInfostriggerEventName);
				if (loadOnSaveProxy == null && dataTarget.isListenerAvailable("onLoadOnSave"true)) {
					loadOnSaveProxy = dataTarget;
				}
			}
			//bug #1895856 : data binding LoadOnSave works only on the last save-when component
			//do loadOnSave
			//if (dataTarget != null) {
			//		Events.postEvent(new Event("onLoadOnSave", dataTarget, loadOnSaveInfos));
			//	}
			// (use first working dataTarget as proxy)
			//feature#2990932, allow disable load-on-save mechanism
			if (loadOnSaveProxy != null && binder.isLoadOnSave()) {
				Events.postEvent(new Event("onLoadOnSave"loadOnSaveProxyloadOnSaveInfos));
			}
		}
	}
	//scan up the component hierarchy until the real owner is found and collect all cloned components.
	private static List<ComponentscanClones(DataBinder binderComponent comp) {
		if (DataBinder.isTemplate(comp)) {
			final List<Componentowners = scanClones(binderbinder.getCollectionOwner(comp)); //recursive
			final List<Componentkidowners = new LinkedList<Component>();
			for (Component ownerowners) {
				final CollectionItem decor = binder.getCollectionItemByOwner(owner);
				//backward compatible, CollectionItemEx.getItems() is faster
				if (decor instanceof CollectionItemExt) {
					final CollectionItemExt decorex = (CollectionItemExtdecor;
					for (final Iterator iti = decorex.getItems(owner).iterator(); iti.hasNext();) {
						final Component item = (Componentiti.next();
						kidowners.add(DataBinder.lookupClone(itemcomp));
					}
else {
					try {
						for (int j = 0; true; ++j) { //iterate until out of bound
							final Component item = decor.getComponentAtIndexByOwner(ownerj);
							kidowners.add(DataBinder.lookupClone(itemcomp));
						}
catch (IndexOutOfBoundsException ex) {
						//ignore, iterate until out of bound
					}
				}
			}
			return kidowners;
else {
			final List<Componentowners = new ArrayList<Component>();
			owners.add(comp);
			return owners;
		}
	}
New to GrepCode? Check out our FAQ X