001: /* BindingNode.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Thu Feb 1 16:16:54 2007, Created by Henri
010: }}IS_NOTE
011:
012: Copyright (C) 2006 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: }}IS_RIGHT
016: */
017: package org.zkoss.zkplus.databind;
018:
019: import org.zkoss.zk.ui.UiException;
020: import org.zkoss.zk.ui.Component;
021:
022: import java.util.Map;
023: import java.util.Set;
024: import java.util.List;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.ArrayList;
028: import java.util.Collection;
029: import java.util.LinkedHashSet;
030: import java.util.LinkedHashMap;
031:
032: /**
033: * BindingNode that forms a databinding bean path dependant tree.
034: *
035: * @author Henri
036: */
037: /*package*/class BindingNode {
038: private LinkedHashSet _bindingSet = new LinkedHashSet(); //(Binding set of this expression BindingNode)
039: private Map _kids = new LinkedHashMap(7); //(nodeid, BindingNode)
040: private String _path; //path of this BindingNode
041: private Set _sameNodes = new HashSet(); //BindingNode Set that refer to the same object
042: private boolean _var; //a var node
043: private String _nodeId; //node id of this BindingNode
044: private boolean _root; //whether root node of a path
045: private boolean _innerCollectionNode; //whether a collection in collection item node
046:
047: /** Constructor.
048: * @param path the path of this node in the expression dependant tree.
049: * @param var whether a _var variable binding node.
050: */
051: public BindingNode(String path, boolean var, String id, boolean root) {
052: _path = path;
053: _sameNodes.add(this );
054: _var = var;
055: _nodeId = id;
056: _root = root;
057: }
058:
059: public LinkedHashSet getBindings() {
060: return _bindingSet;
061: }
062:
063: /** Get all Bindings below the given nodes (deepth first traverse).
064: */
065: public LinkedHashSet getAllBindings() {
066: Set walkedNodes = new HashSet(23);
067: LinkedHashSet all = new LinkedHashSet(23 * 2);
068: myGetAllBindings(all, walkedNodes);
069:
070: return all;
071: }
072:
073: private void myGetAllBindings(LinkedHashSet all, Set walkedNodes) {
074: if (walkedNodes.contains(this )) {
075: return; //already walked, skip
076: }
077:
078: //mark as walked already
079: walkedNodes.add(this );
080:
081: for (final Iterator it = _kids.values().iterator(); it
082: .hasNext();) {
083: ((BindingNode) it.next())
084: .myGetAllBindings(all, walkedNodes); //recursive
085: }
086:
087: for (final Iterator it = _sameNodes.iterator(); it.hasNext();) {
088: final Object obj = it.next();
089: if (obj instanceof BindingNode) {
090: ((BindingNode) obj).myGetAllBindings(all, walkedNodes); //recursive
091: }
092: }
093:
094: all.addAll(getBindings());
095: }
096:
097: public String getPath() {
098: return _path;
099: }
100:
101: public String getNodeId() {
102: return _nodeId;
103: }
104:
105: public boolean isVar() {
106: return _var;
107: }
108:
109: public boolean isRoot() {
110: return _root;
111: }
112:
113: /** Add a binding in the BindingNode of the specified path.
114: * @param path the path of the specified BindingNode in the tree.
115: * @param binding the binding to be added to the specified BindingNode.
116: * @param varnameSet set with all _var names
117: */
118: public void addBinding(String path, Binding binding, Set varnameSet) {
119: final List nodeids = DataBinder.parseExpression(path, ".");
120: if (nodeids.size() <= 0) {
121: throw new UiException("Incorrect bean expression: " + path);
122: }
123: boolean var = varnameSet.contains(nodeids.get(0));
124: BindingNode currentNode = this ;
125: for (final Iterator it = nodeids.iterator(); it.hasNext();) {
126: final String nodeid = (String) it.next();
127: if (nodeid == null) {
128: throw new UiException("Incorrect bean expression: "
129: + path);
130: }
131: BindingNode kidNode = (BindingNode) currentNode
132: .getKidNode(nodeid);
133: if (kidNode == null) { //if not found, then add one
134: if ("/".equals(currentNode._path)) {
135: kidNode = new BindingNode(nodeid, var, nodeid, true);
136: } else {
137: kidNode = new BindingNode(currentNode._path + "."
138: + nodeid, var, nodeid, false);
139: }
140: currentNode.addKidNode(nodeid, kidNode);
141: } else {
142: var = var || kidNode._var;
143: }
144: currentNode = kidNode;
145: }
146: if (currentNode == this ) {
147: throw new UiException("Incorrect bean expression: " + path);
148: }
149: currentNode.addBinding(binding);
150: if ("_var".equals(binding.getAttr())) {
151: currentNode._innerCollectionNode = DataBinder
152: .hasTemplateOwner(binding.getComponent());
153: }
154: }
155:
156: public boolean isInnerCollectionNode() {
157: return _innerCollectionNode;
158: }
159:
160: /** Add a binding to this BindingNode.
161: * @param binding the binding to be added to this node.
162: */
163: public void addBinding(Binding binding) {
164: _bindingSet.add(binding);
165: }
166:
167: /** Locate the BindingNode of the specified path.
168: * @param path the path of the specified BindingNode in the tree.
169: */
170: public BindingNode locate(String path) {
171: BindingNode currentNode = this ;
172: final List nodeids = DataBinder.parseExpression(path, ".");
173: for (final Iterator it = nodeids.iterator(); it.hasNext();) {
174: final String nodeid = (String) it.next();
175: if (nodeid == null) {
176: throw new UiException(
177: "Incorrect format of bean expression: " + path);
178: }
179: currentNode = (BindingNode) currentNode.getKidNode(nodeid);
180: if (currentNode == null) {
181: return null;
182: }
183: }
184: return currentNode == this ? null : currentNode;
185: }
186:
187: /** Get root node of this node.
188: */
189: public BindingNode getRootNode(BindingNode super Node) {
190: if (isRoot()) {
191: return this ;
192: }
193: final int j = getPath().indexOf(".");
194: final String path = (j < 0) ? getPath() : getPath().substring(
195: 0, j);
196: return super Node.locate(path);
197: }
198:
199: /** get the sameNodes of this BindingNode.
200: */
201: public Set getSameNodes() {
202: return _sameNodes;
203: }
204:
205: /** merge and set the given other sameNodes as sameNodes of this BindingNode.
206: */
207: public void mergeAndSetSameNodes(Set other) {
208: if (other == _sameNodes) { //same set, no need to merge
209: return;
210: }
211: if (_sameNodes != null) {
212: other.addAll(_sameNodes);
213: }
214: _sameNodes = other;
215: }
216:
217: public String toString() {
218: return _path;
219: }
220:
221: // Get kid nodes
222: /*package*/Collection getKidNodes() {
223: return _kids.values();
224: }
225:
226: // Get kid nodes of the specified nodeid.
227: /*package*/BindingNode getKidNode(String nodeid) {
228: return (BindingNode) _kids.get(nodeid);
229: }
230:
231: private void addKidNode(String nodeid, BindingNode kid) {
232: _kids.put(nodeid, kid);
233: }
234:
235: }
|