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 }