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
53 import java.util.HashMap;
54 import java.util.Map;
55 import java.util.Map.Entry;
56 import java.util.List;
57 import java.util.ArrayList;
58 import java.util.Iterator;
59
60
61 /***
62 * Represents a dynamically expandable bean.
63 *
64 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
65 * @version $Revision: 1.3 $
66 */
67 public class Expando extends GroovyObjectSupport {
68
69 private Map expandoProperties;
70
71 public Expando() {
72 }
73
74 public Expando(Map expandoProperties) {
75 this.expandoProperties = expandoProperties;
76 }
77
78 /***
79 * @return the dynamically expanded properties
80 */
81 public Map getExpandoProperties() {
82 if (expandoProperties == null) {
83 expandoProperties = createMap();
84 }
85 return expandoProperties;
86 }
87
88 public List getProperties() {
89
90 List ret = new ArrayList();
91 Iterator itr = getExpandoProperties().entrySet().iterator();
92 while(itr.hasNext()) {
93 Entry entry = (Entry) itr.next();
94 ret.add(new MetaExpandoProperty(entry));
95 }
96
97 return ret;
98 }
99
100 public Object getProperty(String property) {
101 try {
102 return super.getProperty(property);
103 }
104 catch (GroovyRuntimeException e) {
105 return getExpandoProperties().get(property);
106 }
107 }
108
109 public void setProperty(String property, Object newValue) {
110 try {
111 super.setProperty(property, newValue);
112 }
113 catch (GroovyRuntimeException e) {
114 getExpandoProperties().put(property, newValue);
115 }
116 }
117
118 public Object invokeMethod(String name, Object args) {
119 try {
120 return super.invokeMethod(name, args);
121 }
122 catch (GroovyRuntimeException e) {
123
124 Object value = this.getProperty(name);
125 if (value instanceof Closure) {
126 Closure closure = (Closure) value;
127 closure.setDelegate(this);
128 return closure.call(args);
129 }
130 else {
131 throw e;
132 }
133 }
134
135 }
136
137 /***
138 * Factory method to create a new Map used to store the expando properties map
139 * @return a newly created Map implementation
140 */
141 protected Map createMap() {
142 return new HashMap();
143 }
144
145 }