View Javadoc

1   /*
2    * $Id: Proxy.java,v 1.2 2004/01/28 18:19:11 jstrachan Exp $
3    * 
4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5    * 
6    * Redistribution and use of this software and associated documentation
7    * ("Software"), with or without modification, are permitted provided that the
8    * following conditions are met: 1. Redistributions of source code must retain
9    * copyright statements and notices. Redistributions must also contain a copy
10   * of this document. 2. Redistributions in binary form must reproduce the above
11   * copyright notice, this list of conditions and the following disclaimer in
12   * the documentation and/or other materials provided with the distribution. 3.
13   * The name "groovy" must not be used to endorse or promote products derived
14   * from this Software without prior written permission of The Codehaus. For
15   * written permission, please contact info@codehaus.org. 4. Products derived
16   * from this Software may not be called "groovy" nor may "groovy" appear in
17   * their names without prior written permission of The Codehaus. "groovy" is a
18   * registered trademark of The Codehaus. 5. Due credit should be given to The
19   * Codehaus - http://groovy.codehaus.org/
20   * 
21   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
22   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
25   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31   * DAMAGE.
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 }