1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package groovy.util;
47
48
49 import groovy.lang.Closure;
50 import groovy.lang.GroovyObjectSupport;
51
52 import java.util.List;
53 import java.util.Map;
54
55 import org.codehaus.groovy.runtime.InvokerHelper;
56
57 /***
58 * An abstract base class for creating arbitrary nested trees of objects
59 * or events
60 *
61 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
62 * @version $Revision: 1.6 $
63 */
64 public abstract class BuilderSupport extends GroovyObjectSupport {
65
66 private Object current;
67 private Closure nameMappingClosure;
68 private BuilderSupport proxyBuilder;
69
70 public BuilderSupport() {
71 this.proxyBuilder = this;
72 }
73
74 public BuilderSupport(BuilderSupport proxyBuilder) {
75 this(null, proxyBuilder);
76 }
77
78 public BuilderSupport(Closure nameMappingClosure, BuilderSupport proxyBuilder) {
79 this.nameMappingClosure = nameMappingClosure;
80 this.proxyBuilder = proxyBuilder;
81 }
82
83 public Object invokeMethod(String methodName, Object args) {
84 Object name = getName(methodName);
85 return doInvokeMethod(methodName, name, args);
86 }
87
88 protected Object doInvokeMethod(String methodName, Object name, Object args) {
89 Object node = null;
90 Closure closure = null;
91 List list = InvokerHelper.asList(args);
92
93
94
95 switch (list.size()) {
96 case 0:
97 break;
98 case 1:
99 {
100 Object object = list.get(0);
101 if (object instanceof Map) {
102 node = proxyBuilder.createNode(name, (Map) object);
103 } else if (object instanceof Closure) {
104 closure = (Closure) object;
105 node = proxyBuilder.createNode(name);
106 } else {
107 node = proxyBuilder.createNode(name, object);
108 }
109 }
110 break;
111 case 2:
112 {
113 Object object1 = list.get(0);
114 Object object2 = list.get(1);
115 if (object1 instanceof Map) {
116 if (object2 instanceof Closure) {
117 closure = (Closure) object2;
118 node = proxyBuilder.createNode(name, (Map) object1);
119 } else {
120 node = proxyBuilder.createNode(name, (Map) object1, object2);
121 }
122 } else {
123 if (object2 instanceof Closure) {
124 closure = (Closure) object2;
125 node = proxyBuilder.createNode(name, object1);
126 }
127 }
128 }
129 break;
130 case 3:
131 {
132 Object attributes = list.get(0);
133 Object value = list.get(1);
134 closure = (Closure) list.get(2);
135 node = proxyBuilder.createNode(name, (Map) attributes, value);
136 }
137 break;
138 }
139
140 if (node == null) {
141 node = proxyBuilder.createNode(name);
142 }
143
144 if (current != null) {
145 proxyBuilder.setParent(current, node);
146 }
147
148 if (closure != null) {
149
150 Object oldCurrent = current;
151 current = node;
152
153
154 closure.setDelegate(this);
155 closure.call();
156
157 current = oldCurrent;
158 }
159
160 proxyBuilder.nodeCompleted(current, node);
161 return node;
162 }
163
164 protected abstract void setParent(Object parent, Object child);
165 protected abstract Object createNode(Object name);
166 protected abstract Object createNode(Object name, Object value);
167 protected abstract Object createNode(Object name, Map attributes);
168 protected abstract Object createNode(Object name, Map attributes, Object value);
169
170 /***
171 * A hook to allow names to be converted into some other object
172 * such as a QName in XML or ObjectName in JMX
173 * @param methodName
174 * @return
175 */
176 protected Object getName(String methodName) {
177 if (nameMappingClosure != null) {
178 return nameMappingClosure.call(methodName);
179 }
180 return methodName;
181 }
182
183
184 /***
185 * A hook to allow nodes to be processed once they have had all of their
186 * children applied
187 */
188 protected void nodeCompleted(Object parent, Object node) {
189 }
190
191 protected Object getCurrent() {
192 return current;
193 }
194
195 protected void setCurrent(Object current) {
196 this.current = current;
197 }
198 }