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 import groovy.lang.Closure;
49 import groovy.lang.GroovyObjectSupport;
50 import groovy.lang.GroovyRuntimeException;
51 import groovy.lang.MetaExpandoProperty;
52 import groovy.lang.MissingPropertyException;
53
54 import java.util.HashMap;
55 import java.util.Map;
56 import java.util.Map.Entry;
57 import java.util.List;
58 import java.util.ArrayList;
59 import java.util.Iterator;
60
61
62 /***
63 * Represents a dynamically expandable bean.
64 *
65 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
66 * @author Hein Meling
67 * @author Pilho Kim
68 * @version $Revision: 4578 $
69 */
70 public class Expando extends GroovyObjectSupport {
71
72 private Map expandoProperties;
73
74 public Expando() {
75 }
76
77 public Expando(Map expandoProperties) {
78 this.expandoProperties = expandoProperties;
79 }
80
81 /***
82 * @return the dynamically expanded properties
83 */
84 public Map getProperties() {
85 if (expandoProperties == null) {
86 expandoProperties = createMap();
87 }
88 return expandoProperties;
89 }
90
91 public List getMetaPropertyValues() {
92
93 List ret = new ArrayList();
94 Iterator itr = getProperties().entrySet().iterator();
95 while(itr.hasNext()) {
96 Entry entry = (Entry) itr.next();
97 ret.add(new MetaExpandoProperty(entry));
98 }
99
100 return ret;
101 }
102
103 public Object getProperty(String property) {
104
105 Object result = getProperties().get(property);
106 if (result!=null) return result;
107 try {
108 return super.getProperty(property);
109 }
110 catch (MissingPropertyException e) {}
111 return null;
112 }
113
114 public void setProperty(String property, Object newValue) {
115
116 getProperties().put(property, newValue);
117 }
118
119 public Object invokeMethod(String name, Object args) {
120 try {
121 return super.invokeMethod(name, args);
122 }
123 catch (GroovyRuntimeException e) {
124
125 Object value = this.getProperty(name);
126 if (value instanceof Closure) {
127 Closure closure = (Closure) value;
128 closure.setDelegate(this);
129 return closure.call((Object[]) args);
130 }
131 else {
132 throw e;
133 }
134 }
135
136 }
137
138 /***
139 * This allows toString to be overridden by a closure <i>field</i> method attached
140 * to the expando object.
141 *
142 * @see java.lang.Object#toString()
143 */
144 public String toString() {
145 Object method = getProperties().get("toString");
146 if (method != null && method instanceof Closure) {
147
148 Closure closure = (Closure) method;
149 closure.setDelegate(this);
150 return closure.call().toString();
151 } else {
152 return expandoProperties.toString();
153 }
154 }
155
156 /***
157 * This allows equals to be overridden by a closure <i>field</i> method attached
158 * to the expando object.
159 *
160 * @see java.lang.Object#equals(java.lang.Object)
161 */
162 public boolean equals(Object obj) {
163 Object method = getProperties().get("equals");
164 if (method != null && method instanceof Closure) {
165
166 Closure closure = (Closure) method;
167 closure.setDelegate(this);
168 Boolean ret = (Boolean) closure.call(obj);
169 return ret.booleanValue();
170 } else {
171 return super.equals(obj);
172 }
173 }
174
175 /***
176 * This allows hashCode to be overridden by a closure <i>field</i> method attached
177 * to the expando object.
178 *
179 * @see java.lang.Object#hashCode()
180 */
181 public int hashCode() {
182 Object method = getProperties().get("hashCode");
183 if (method != null && method instanceof Closure) {
184
185 Closure closure = (Closure) method;
186 closure.setDelegate(this);
187 Integer ret = (Integer) closure.call();
188 return ret.intValue();
189 } else {
190 return super.hashCode();
191 }
192 }
193
194 /***
195 * Factory method to create a new Map used to store the expando properties map
196 * @return a newly created Map implementation
197 */
198 protected Map createMap() {
199 return new HashMap();
200 }
201
202 }