org.jpu.patterns.proxy
Class ProxyBean

java.lang.Object
  extended byorg.jpu.patterns.proxy.JPUInvocationHandler
      extended byorg.jpu.patterns.proxy.ProxyBean
All Implemented Interfaces:
java.lang.reflect.InvocationHandler, java.io.Serializable
Direct Known Subclasses:
AccountImpl, ProxyTransferObject

public class ProxyBean
extends JPUInvocationHandler
implements java.io.Serializable

Change-tracking invocation handler intended for use in implementing JavaBean's that are referenced through one or more interfaces. Automatically provides implementations of simple getter and setter methods, reducing the burden associated with maintaining large numbers of such methods.

While simple getters and setters are implemented automatically, more complex methods ("business" methods, for instance) can be explicitly defined. When the caller calls a method on the interface, this class will first attempt to delegate the method call to "this". If no such method exists in this.getClass() or any of its superclasses, then it will determine if the method is a getter or setter and, if so, query or update an internal Map of attributes; if not it will cause a UnhandledMethodCallException (unchecked) to be thrown.

If you wish to provide your own implementation of a method, add it to your ProxyBean subclass (making sure it has the same signature as the version in the interface). The proxy instance can be obtained via JPUInvocationHandler.getProxy() and you are free to call whichever methods on it you wish through the interface. To illustrate, suppose I have a class AccountImpl and interface Account defined as follows:

 
      public interface Account {
          public String getId();
          public void setId(String id);
          public double getBalance();
          public void setBalance(double bal);
          public void deposit(double amt);
      }

      // ...

      public class AccountImpl extends ProxyBean {
          public void initializeProxy(Object newProxy) {
              super.initializeProxy(newProxy);
              Account acct = (Account)newProxy;
              acct.setBalance(0.0);
          }
          public void deposit(double amt) {
              Account acct = (Account)getProxy();
              acct.setBalance( acct.getBalance() + amt );
          }
      }
 
 
Then the "id" attribute will be maintained automatically (getters and setters implemented automatically) while calls to deposit() will be delegated to AccountImpl's deposit() method. Note the initial balance is set in initializeProxy(); without this the balance would start out null.

The internal Map that holds the attributes is made accessible to users of ProxyBean both for query and update. This facilitates convenient and efficient access to all the object's attributes for wholesale copying and other sorts of manipulation.

This class can also maintain changed flags on each of the attributes. By default this feature is disabled but can be enabled by overriding trackChanges() and having it return true. If changes are tracked, then the public methods getChangedAttributes() and isAttributeChanged(String) can be used to query the flags and setChangedFlag(String), clearChangedFlag(String), and clearChangedFlags() to change them. If you wish for the subclass to be notified of any changes, you may override the valueChanged(JPUBeanUtils.MethodDescriptor, Object, Object) subclass hook. If you want to change the definition of equality of objects (default is org.apache.commons.lang.ObjectUtils.equals()), you can override areValuesEqual(JPUBeanUtils.MethodDescriptor , Object , Object ).

This class inherits from JPUInvocationHandler, so if you wish to add additional logic to the invocation handler, override doInvoke(Object, Method, Object[], Object[]) and add the following lines at the top your implementation:

 
      if ( super.doInvoke(proxy, method, args, result) ) {
          return true;
      }
 
 
Definitions of "getter" and "setter" used here are the same ones defined by the JavaBeans specification; that is, a method is considered a getter if it starts with "get" and takes zero parameters; or if it starts with "is", takes zero parameters, and returns boolean or Boolean; while a method is considered a setter if it starts with "set" and takes one parameter.

ProxyBean can be quite useful in J2EE environments that use the Transfer Object pattern to pass data between tiers. The change-tracking feature can be used to determine which items have been altered by the presentation tier and hence require persisting to the database. The JPU toolkit provides a class called ProxyTransferObject which is intended for this purpose; it extends ProxyBean and adds serializability to the invocation handler (which of course is necessary for passing such objects between tiers).

See Also:
Serialized Form

Nested Class Summary
 
Nested classes inherited from class org.jpu.patterns.proxy.JPUInvocationHandler
JPUInvocationHandler.DelegationCacheValue, JPUInvocationHandler.DelegationState
 
Constructor Summary
ProxyBean()
           
 
Method Summary
 boolean areAnyAttributesChanged()
          Convenience alias for " ! getChangedAttributes().isEmpty()".
protected  boolean areValuesEqual(JPUBeanUtils.MethodDescriptor method, java.lang.Object oldValue, java.lang.Object newValue)
          Returns whether the two given values are considered equal.
protected  boolean autoDelegateToMap()
          Returns whether implementations of getters and setters are automatically provided.
 void clearChangedFlag(java.lang.String attributeName)
          Clears the changed flag for the named attribute.
 void clearChangedFlags()
          Clears all changed flas.
 java.util.Map copyChangesTo(java.lang.Object dest)
          Convenience alias for "copyChangesTo(dest, null)".
 java.util.Map copyChangesTo(java.lang.Object dest, CopyOptions options)
          Copies all attributes from this object to dest using the given options.
 java.util.Map copyTo(java.lang.Object dest)
          Convenience alias for "copyTo(dest,null)".
 java.util.Map copyTo(java.lang.Object dest, CopyOptions options)
          Copies all attributes to "dest" (which needn't be backed by a ProxyBean) with the given CopyOptions using JPUBeanUtils.copy(java.lang.Object, java.lang.Object).
protected  boolean delegateToMap(java.lang.Object proxy, java.lang.reflect.Method method, java.lang.Object[] args, java.lang.Object[] result)
           
protected  boolean delegateToMap(java.lang.Object proxy, java.lang.Object[] args, java.lang.Object[] result)
          Convenience alias for "delegateToMap(proxy, null, args, result)".
protected  boolean doInvoke(java.lang.Object proxy, java.lang.reflect.Method method, java.lang.Object[] args, java.lang.Object[] result)
          Overrides the corresponding method of JPUInvocationHandler.
protected  java.lang.Object getAttribute(JPUBeanUtils.MethodDescriptor method)
          Returns the value of the attribute associated with the given getter method.
 java.lang.Object getAttribute(java.lang.String attName)
          Returns the value of the named attribute, or null if that attribute is not present.
 java.util.Map getAttributes()
          Returns a Map containing all the attributes.
 java.util.Set getChangedAttributes()
          Returns the names of all attributes that have changed since the last call to clearChangedFlags() (or since the object's creation).
protected  JPUBeanUtils.MethodDescriptor getDescriptor(java.lang.reflect.Method method)
           
 boolean isAttributeChanged(java.lang.String attributeName)
          Convenience alias for "getChangedAttributes().contains(attributeName)".
protected  void setAttribute(JPUBeanUtils.MethodDescriptor method, java.lang.Object[] args)
           
 void setChangedFlag(java.lang.String attributeName)
          Sets the changed flag for the named attribute.
 boolean trackChanges()
          Returns whether changes are being tracked.
protected  void valueChanged(JPUBeanUtils.MethodDescriptor method, java.lang.Object oldValue, java.lang.Object newValue)
          Hook that is invoked if change tracking is enabled and the value of an attribute has changed as a result of a setter invocation.
 
Methods inherited from class org.jpu.patterns.proxy.JPUInvocationHandler
autoDelegateToSelf, delegate, doGetImplementedInterfaces, getCacheHits, getCacheMisses, getCurrentInterfaceMethod, getDefaultClassLoader, getDelegationMethod, getDelegationState, getDelegationTargetMethod, getInterfaces, getProxy, initializeProxy, invoke, newProxy, newProxy, newProxy, resetCacheCounters, rethrow, setDelegationState, throwUnhandledException, throwUnlistedException, wouldDelegationInfinitelyRecurse
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

ProxyBean

public ProxyBean()
Method Detail

getAttributes

public java.util.Map getAttributes()
Returns a Map containing all the attributes. The map is modifiable and the caller is free to change it as required.


getAttribute

public java.lang.Object getAttribute(java.lang.String attName)
Returns the value of the named attribute, or null if that attribute is not present.


getChangedAttributes

public java.util.Set getChangedAttributes()
Returns the names of all attributes that have changed since the last call to clearChangedFlags() (or since the object's creation). If trackChanges() returns false (the default), the returned Set will be empty.

The returned Set is modifiable and the caller is free to change it as required.


areAnyAttributesChanged

public boolean areAnyAttributesChanged()
Convenience alias for " ! getChangedAttributes().isEmpty()".


isAttributeChanged

public boolean isAttributeChanged(java.lang.String attributeName)
Convenience alias for "getChangedAttributes().contains(attributeName)".


copyChangesTo

public java.util.Map copyChangesTo(java.lang.Object dest)
                            throws CopyException
Convenience alias for "copyChangesTo(dest, null)".

Throws:
CopyException

copyChangesTo

public java.util.Map copyChangesTo(java.lang.Object dest,
                                   CopyOptions options)
                            throws CopyException
Copies all attributes from this object to dest using the given options. The implementation uses JPUBeanUtils.copy(java.lang.Object, java.lang.Object).

Throws:
CopyException

copyTo

public java.util.Map copyTo(java.lang.Object dest)
                     throws CopyException
Convenience alias for "copyTo(dest,null)".

Throws:
CopyException

copyTo

public java.util.Map copyTo(java.lang.Object dest,
                            CopyOptions options)
                     throws CopyException
Copies all attributes to "dest" (which needn't be backed by a ProxyBean) with the given CopyOptions using JPUBeanUtils.copy(java.lang.Object, java.lang.Object). If "options.sourceClasses" is null, it is populated with an array containing all interfaces implemented by the proxy prior to the call to JPUBeanUtils.copy(java.lang.Object, java.lang.Object).

Throws:
CopyException

setChangedFlag

public void setChangedFlag(java.lang.String attributeName)
Sets the changed flag for the named attribute.


clearChangedFlag

public void clearChangedFlag(java.lang.String attributeName)
Clears the changed flag for the named attribute.


clearChangedFlags

public void clearChangedFlags()
Clears all changed flas.


doInvoke

protected boolean doInvoke(java.lang.Object proxy,
                           java.lang.reflect.Method method,
                           java.lang.Object[] args,
                           java.lang.Object[] result)
                    throws java.lang.Throwable
Overrides the corresponding method of JPUInvocationHandler. Calls super.doInvoke() and, if its return value is false, calls autoDelegateToMap(). If that method returns true, calls delegateToMap(Object,Method,Object[],Object[]) and returns the result; else returns false.

Overrides:
doInvoke in class JPUInvocationHandler
Throws:
java.lang.Throwable

autoDelegateToMap

protected boolean autoDelegateToMap()
Returns whether implementations of getters and setters are automatically provided. The default implementation returns true, but subclasses are free to override. If false is returned, the subclass may still invoke the "Map delegation" feature by calling delegateToMap(Object,Method,Object[],Object[]).


trackChanges

public boolean trackChanges()
Returns whether changes are being tracked. Default is false, but subclasses are free to override.


delegateToMap

protected boolean delegateToMap(java.lang.Object proxy,
                                java.lang.Object[] args,
                                java.lang.Object[] result)
                         throws java.lang.Throwable
Convenience alias for "delegateToMap(proxy, null, args, result)".

Throws:
java.lang.Throwable

delegateToMap

protected boolean delegateToMap(java.lang.Object proxy,
                                java.lang.reflect.Method method,
                                java.lang.Object[] args,
                                java.lang.Object[] result)
                         throws java.lang.Throwable
Throws:
java.lang.Throwable

getDescriptor

protected JPUBeanUtils.MethodDescriptor getDescriptor(java.lang.reflect.Method method)

setAttribute

protected void setAttribute(JPUBeanUtils.MethodDescriptor method,
                            java.lang.Object[] args)
                     throws java.lang.Throwable
Throws:
java.lang.Throwable

valueChanged

protected void valueChanged(JPUBeanUtils.MethodDescriptor method,
                            java.lang.Object oldValue,
                            java.lang.Object newValue)
Hook that is invoked if change tracking is enabled and the value of an attribute has changed as a result of a setter invocation. The old and new values are passed, along with the invoked setter's JPUBeanUtils.MethodDescriptor.


areValuesEqual

protected boolean areValuesEqual(JPUBeanUtils.MethodDescriptor method,
                                 java.lang.Object oldValue,
                                 java.lang.Object newValue)
Returns whether the two given values are considered equal. "method" is the JPUBeanUtils.MethodDescriptor of the invoked setter.


getAttribute

protected java.lang.Object getAttribute(JPUBeanUtils.MethodDescriptor method)
                                 throws java.lang.Throwable
Returns the value of the attribute associated with the given getter method. The default implementation simply returns "getAttributes().get(method.attributeName)", but subclasses are free to override.

Throws:
java.lang.Throwable


Copyright (c) 2001-2003 - Apache Software Foundation