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 package groovy.util;
35
36 import groovy.lang.GroovyObjectSupport;
37 import groovy.lang.MetaClass;
38 import groovy.lang.MissingPropertyException;
39 import groovy.lang.MissingMethodException;
40 import org.codehaus.groovy.runtime.InvokerHelper;
41
42 /***
43 * Dynamic groovy proxy for another object. All property accesses and method
44 * invocations get forwarded to actual object, unless the proxy overrides it.
45 * The calling order can be set to try the real or proxy first.
46 *
47 * @author Troy Heninger
48 */
49 public class Proxy extends GroovyObjectSupport {
50
51 private boolean tryRealFirst;
52 private Object realObject;
53 private MetaClass realMeta, first, second;
54
55 /***
56 * Constructor. Takes real object to be excapsulated and set's the order
57 * to the real object first.
58 *
59 * @param real the real object
60 */
61 public Proxy(Object real) {
62 this(real, true);
63 }
64
65 /***
66 * Constructor. Takes real object to be excapsulated and order.
67 *
68 * @param real the real object
69 * @param tryRealFirst call real object first if true
70 */
71 public Proxy(Object real, boolean tryRealFirst) {
72 this.tryRealFirst = tryRealFirst;
73 this.realObject = real;
74 setMetaClass(InvokerHelper.getMetaClass(real));
75 }
76
77 /***
78 * Get the property of this proxy, or the real object if property doesn't
79 * exist.
80 *
81 * @param property property to retrieve
82 * @return property's value
83 */
84 public Object getProperty(String property) {
85 try {
86 return first.getProperty(this, property);
87 }
88 catch (MissingPropertyException e) {
89 return second.getProperty(realObject, property);
90 }
91 }
92
93 /***
94 * Set the property of this proxy, or the real object if property doesn't
95 * exist.
96 *
97 * @param property property to set
98 * @param newValue value to store
99 */
100 public void setProperty(String property, Object newValue) {
101 try {
102 first.setProperty(this, property, newValue);
103 }
104 catch (MissingPropertyException e) {
105 second.setProperty(realObject, property, newValue);
106 }
107 }
108
109 /***
110 * Returns the MetaClass for the <b>real</b> object.
111 *
112 * @return MetaClass of real object
113 */
114 public MetaClass getMetaClass() {
115 return realMeta;
116 }
117
118 /***
119 * Returns the MetaClass for the <b>proxy </b> object.
120 *
121 * @return MetaClass of proxy object
122 */
123 public MetaClass getProxyMetaClass() {
124 return super.getMetaClass();
125 }
126
127 /***
128 * Returns the encapsulated object.
129 *
130 * @return the real object
131 */
132 public Object getRealObject() {
133 return realObject;
134 }
135
136 /***
137 * Call a method of this proxy, or the real object if method doesn't exist.
138 *
139 * @param name method to invoke
140 * @param args arguments to pass
141 * @return
142 */
143 public Object invokeMethod(String name, Object args) {
144 try {
145 return first.invokeMethod(this, name, args);
146 }
147 catch (MissingMethodException e) {
148 return second.invokeMethod(this, name, args);
149 }
150 }
151
152 /***
153 * Dynamically change the meta class to use for the <b>real</b> object.
154 *
155 * @param metaClass substitute real meta class
156 */
157 public void setMetaClass(MetaClass metaClass) {
158 realMeta = metaClass;
159 if (tryRealFirst) {
160 first = realMeta;
161 second = getMetaClass();
162 }
163 else {
164 first = getMetaClass();
165 second = realMeta;
166 }
167 }
168
169 /***
170 * Dynamically change the meta class to use for the <b>proxy</b> object.
171 *
172 * @param metaClass substitute meta class for the proxy object
173 */
174 public void setProxyMetaClass(MetaClass metaClass) {
175 super.setMetaClass(metaClass);
176 if (tryRealFirst) {
177 first = realMeta;
178 second = getMetaClass();
179 }
180 else {
181 first = getMetaClass();
182 second = realMeta;
183 }
184 }
185 }