Evaluating Software Design Patterns
— the "Gang of Four" patterns implemented in Java 6

dk.rode.thesis.meta.reflect.proxy
Class ProxyFactory

java.lang.Object
  extended by dk.rode.thesis.meta.reflect.proxy.ProxyFactory

public class ProxyFactory
extends Object

A proxy factory creates dynamic proxies, which can also be used for duck typing.

The proxy objects are based on the java.lang.reflect.Proxy class, and must therefore adhere to the rules set forth by that class. For example, an implication of this is that even if a specific instance is supplied as the object argument to the getProxy(Object, InvocationHandler, Class...) method, i.e. a specific class, the returned (proxy) object cannot be cast back into that type (the specific type information is "lost" as the class returned is an anonymous Proxy class).

Per default, the class loader used to load this class is used as the class loader to define the created proxies, but a specific class loader can be supplied at construction time.

This class defines four specific proxy methods:

  1. getLoggableObject(Object, Class...): returns a proxy that will record and time all access to the proxied object if and only if all access is through the proxy only.

  2. getSynchronisedObject(Object, Object, Class...): returns a proxy that guarantees thread-safe access to the proxied object if and only if all access is through the proxy only.

  3. getSharedObject(Object, String, Class[], String...): returns a proxy of a given object that can be shared until a mutator method is invoked, causing the original referenced object to be copied (smart reference), if and only if all access is through the proxy or copies of it only.

  4. getNullObject(Class): returns a to this factory unique null object of the type specified as the argument. Only a single instance of the type in question will be created, and the type may be either an interface or class. This can be used to mask null where null is not allowed.

A proxy factory only maintain weak references to proxied objects, though individual handlers may store strong references!

A proxy factory is open for sub-classing.

Please refer to the JavaDoc of the java.lang.reflect.Proxy class for in-depth semantics regarding proxies. The JavaDoc for the three methods described above contains examples on general usage of Proxy objects as well.

Implementation notes:
The nested classes defined in this class represent applications of the Adapter and Decorator patterns, while this factory itself is an application of the Proxy pattern.

Author:
Gunni Rode / rode.dk

Nested Class Summary
private  class ProxyFactory.Handler
          A handler is used to decorate all invocation handlers used by proxies created by any proxy factory.
private static class ProxyFactory.Key
          A key adapts a proxy to ensure consistent hashCode() and equals(Object) behaviour when proxies are stored internally by proxy factories, because proxies may override hashCode and equals(Object) in unpredictable ways.
private static interface ProxyFactory.Proxy
          All proxies created by a proxy factory will be tagged with this adapter interface, allowing for later retrieval of the actual proxy factory that created the proxy as well as the unique handler associated with it.
 
Field Summary
private  ClassLoader classLoader
          The class loader to use when creating the proxy objects.
private static Method factoryMethod
          Reference to the ProxyFactory.Proxy.getProxyFactory() method defined in the ProxyFactory.Proxy interface.
private static Method handlerMethod
          Reference to the ProxyFactory.Proxy.getHandler() method defined in the ProxyFactory.Proxy interface.
private  Map<Class<?>,Object> nulls
          A map containing all unique null objects created by this factory.
private  Map<ProxyFactory.Key,WeakReference<Object>> proxies
          A map containing the proxies created by this factory.
 
Constructor Summary
ProxyFactory()
          No-arg constructor, which creates this proxy factory to use the class loader that loaded this factory.
ProxyFactory(ClassLoader classLoader)
          Constructor, which creates this factory to use the class loader supplied as classLoader when creating new proxy objects.
 
Method Summary
private
<T> T
create(T object, Set<Class<?>> interfaces, InvocationHandler handler)
          Factory method used to create a new proxy object implementing the interfaces supplied as interfaces, in order, based on the object to proxy supplied as object, if any.
 boolean equals(Object object)
          Returns true if object is the same factory instance as this factory, false if not.
protected static Set<Class<?>> getInterfaces(Object object, Class<?>... interfaces)
          Returns a set containing the interfaces to use for the proxied object supplied as object.
<T> T
getLoggableObject(T object, Class<? super T>... interfaces)
          Returns a (proxy) version of object that will record all access to object when accessed (via the proxy) through one of the interfaces supplied in interfaces.
<T> T
getNullObject(Class<T> type)
          Returns a to this factory unique null object of the type supplied as type.
 Object getObject(Object proxy)
          Returns the actual object proxied by proxy, or null if no such proxy is handled by this proxy factory or if garbage collected.
 List<?> getProxies(Object object)
          Returns all proxy objects for the object supplied as object, if any.
 Object getProxy(InvocationHandler handler, Class<?>... interfaces)
          Creates a new proxy object implementing the interfaces supplied as interfaces, in order.
<T> T
getProxy(T object, InvocationHandler handler, Class<?>... interfaces)
          Creates a new proxy object implementing the interfaces supplied as interfaces, in order.
protected static ProxyFactory getProxyFactory(Object proxy)
          Returns the proxy factory that created the proxy supplied as proxy, or null if proxy is not a proxy created by a proxy factory.
<T> T
getSharedObject(T object, String copyMethod, Class<?>[] parameterTypes, String... mutatorMethods)
          Returns a (proxy) reference to object that can be shared and copied by different contexts until a given mutator method is invoked on it, forcing the original object to be copied.
<T> T
getSynchronisedObject(T object, Class<? super T>... interfaces)
          Returns a synchronised (proxy) version of object that can be viewed as any of the interfaces supplied in interfaces.
<T> T
getSynchronisedObject(T object, Object lock, Class<? super T>... interfaces)
          Returns a synchronised (proxy) version of object that can be viewed as any of the interfaces supplied in interfaces, synchronised on the object supplied as lock.
 int hashCode()
          Returns the hash code of this factory.
 boolean isProxied(Object object)
          Returns true if the object supplied as object is proxied by a proxy created by this factory, false if not.
 boolean isProxy(Object object)
          Returns true if object is a proxy created by this proxy factory, false if not.
protected  void register(Object proxy, Object object)
          Registers the proxied object supplied as object for the proxy supplied as proxy.
 String toString()
          Return the string representation of this factory.
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

classLoader

private final ClassLoader classLoader
The class loader to use when creating the proxy objects.

Never null.


factoryMethod

private static final Method factoryMethod
Reference to the ProxyFactory.Proxy.getProxyFactory() method defined in the ProxyFactory.Proxy interface.

Never null.


handlerMethod

private static final Method handlerMethod
Reference to the ProxyFactory.Proxy.getHandler() method defined in the ProxyFactory.Proxy interface.

Never null.


nulls

private Map<Class<?>,Object> nulls
A map containing all unique null objects created by this factory.

A null object (value) is a unique object based on identity for its type (key), which can be used to mask null where null is not allowed. Hence, at most one instance of a given type will be created by this factory.

Will be null if no such null objects have been created.


proxies

private final Map<ProxyFactory.Key,WeakReference<Object>> proxies
A map containing the proxies created by this factory.

The actual proxied objects are stored as weak references, so this factory will not keep a reference to them. Individual handlers may still keep references to the proxied objects, however.

Never null, but can be empty.

Implementation notes:
The keys, i.e. proxies, should be stored as weak references as well, but this is tricky as weak references compare on identity in equals(Object). A WeakHashMap wraps any type of key as a weak reference, and hence creating new keys to look-up existing proxies will fail if such a map is used!

Constructor Detail

ProxyFactory

public ProxyFactory()
No-arg constructor, which creates this proxy factory to use the class loader that loaded this factory.


ProxyFactory

public ProxyFactory(ClassLoader classLoader)
Constructor, which creates this factory to use the class loader supplied as classLoader when creating new proxy objects.

Parameters:
classLoader - The class loader; cannot be null.
Throws:
NullPointerException - If classLoader is null.
Method Detail

create

private <T> T create(T object,
                     Set<Class<?>> interfaces,
                     InvocationHandler handler)
Factory method used to create a new proxy object implementing the interfaces supplied as interfaces, in order, based on the object to proxy supplied as object, if any.

If object is not null, the returned proxy will be registered with object as the associated proxied object using the register(Object, Object) method.

Type Parameters:
T - The type of object.
Parameters:
object - The object to proxy; can be null.
interfaces - The interfaces to implement by the returned proxy; cannot be null, or contain null entries or non-interface classes. Annotations are ignored.
handler - The invocation handler to use by the proxy; cannot be null.
Returns:
A new proxy instance; never null.
Throws:
NullPointerException - If interfaces or handler are null, or if interfaces contain a null entry.
IllegalArgumentException - If interfaces contain a non-interface class.

equals

public final boolean equals(Object object)
Returns true if object is the same factory instance as this factory, false if not.

Overrides:
equals in class Object
Parameters:
object - The object to test; can be null.
Returns:
True if same instance, false if not.

getInterfaces

protected static final Set<Class<?>> getInterfaces(Object object,
                                                   Class<?>... interfaces)
Returns a set containing the interfaces to use for the proxied object supplied as object.

If interfaces is not null, the contained interfaces will be used in that order. If null, each interface implemented by object will be used, in the order implemented by object.

Parameters:
object - The proxied object; cannot be null.
interfaces - The list of specified interfaces, if any; can be empty.
Returns:
An ordered set containing the interfaces to use; never null, but can be empty.
Throws:
NullPointerException - If object is null, or interfaces contains a null entry.

getLoggableObject

public <T> T getLoggableObject(T object,
                               Class<? super T>... interfaces)
Returns a (proxy) version of object that will record all access to object when accessed (via the proxy) through one of the interfaces supplied in interfaces. The access is recorded to the log associated with the original class of object.

All access to object via the methods defined in one of the types in interfaces will be logged if and only if object is accessed through the returned proxy object only. If object is accessed directly, logging cannot be guaranteed!

If no interfaces are supplied, all interfaces implemented by object, directly or indirectly (for example via a super-class), will be used.

Since the returned object is a java.lang.reflect.Proxy instance, the normal rules for Proxy objects apply! An implication of this is that even if a specific instance is supplied as object, i.e. a specific class, the returned (proxy) object cannot be cast back into that type (the specific type information is "lost").

Example:

   // Interfaces...
   public interface Foo {
     public String foo();
   }

   public interface Bar {
     public String bar();
   }

   ..
   
   // Implementation...
   public class FooBar implements Foo, Bar {
     public String foo() {
       return "foo";
     }     
     public String bar() {
       return "bar";
     }     
   }
   
   ..
   
   FooBar foobar = new FooBar();
   
   ProxyFactory factory = new ProxyFactory();
   
   // No class casting needed, since we only use a single interface...
   Foo foo = factory.getLoggableObject(foobar, Foo.class);
          
   // All access to the methods defined in Foo will now be 
   // logged when accessing through "foo":
   
   String s = foobar.foo() // *not* logged
          s = foo.foo();   // logged
   
   // Will throw a class cast exception! 
   FooBar goo = (FooBar)foo;
   
   ..
   
   // A class cast is now required, since more than one interface
   // is implemented by the returned proxy. A cast to either type
   // is valid...
   foo = (Foo)factory.getLoggableObject(foobar, Foo.class, Bar.class);
          
   // All access to the methods defined in Foo *and* Bar will now
   // be logged accessing through "foo" and "bar":
   
   String s = foobar.foo(); // *not* logged
          s = foobar.bar(); // *not* logged
          s = foo.foo();    // logged
          
   // Must cast to access "bar"...          
   Bar bar = (Bar)foo;       
          s = bar.bar();    // logged 
                           
   // Will throw a class cast exception! 
   FooBar goo = (FooBar)bar;
   
   // Default - all interfaces implemented by FooBar (including 
   // those from super-classes) - no class casting is required, 
   // but the returned proxy can simply be assigned to a proper type:
   
   foo = factory.getLoggableObject(foobar); // Foo.class & Bar.class
   bar = factory.getLoggableObject(foobar); // Foo.class & Bar.class
 
Proxies can be supplied as the object parameter, which allows for nested logging.

Type Parameters:
T - The type of object.
Parameters:
object - The actual object to be used; cannot be null, and must implement all the interfaces supplied as interfaces.
interfaces - The interfaces to supply the methods to be logged; can be null, in which case all interfaces implemented by the class of object will be used.
Returns:
A proxy object, where all access on all methods defined in interfaces will be logged; never null.
Throws:
NullPointerException - If object is null.
IllegalArgumentException - If interfaces contain an non-interface type.
See Also:
getSynchronisedObject(Object, Class...), getSynchronisedObject(Object, Object, Class...), getSharedObject(Object, String, Class[], String...)

getNullObject

public <T> T getNullObject(Class<T> type)
                throws Exception
Returns a to this factory unique null object of the type supplied as type.

A null object is a unique object based on identity for its type, which can be used to mask null where null is not allowed. Hence, at most one instance of type will be created by this factory.

Properties for returned null objects:

Type Parameters:
T - The type of the null object.
Parameters:
type - The type as a class literal; cannot be null.
Returns:
The unique null object of the type supplied as type; never null.
Throws:
Exception - If type represents a class, which is neither a primitive type nor a primitive wrapper class, without a public no-arg constructor; or if type is an abstract class.

getObject

public Object getObject(Object proxy)
Returns the actual object proxied by proxy, or null if no such proxy is handled by this proxy factory or if garbage collected.

Parameters:
proxy - The proxy; cannot be null.
Returns:
The actual object, or null if garbage collected.
Throws:
NullPointerException - If proxy is null.
IllegalArgumentException - If proxy does not represent a proxy.

getProxies

public List<?> getProxies(Object object)
Returns all proxy objects for the object supplied as object, if any.

Parameters:
object - The object; cannot be null.
Returns:
A list containing the created proxies in no particular order; never null, but can be empty.
Throws:
NullPointerException - If object is null.

getProxy

public Object getProxy(InvocationHandler handler,
                       Class<?>... interfaces)
Creates a new proxy object implementing the interfaces supplied as interfaces, in order.

The proxy object is not registered to any real object.

Parameters:
handler - The invocation handler to use by the proxy; cannot be null.
interfaces - The interfaces to implement by the returned proxy; cannot be null, empty, or contain null entries or non-interface classes.
Returns:
A new proxy instance; never null.
Throws:
NullPointerException - If either argument is null, or if interfaces contains a null entry.
IllegalArgumentException - If interfaces contain a non-interface class.
ClassCastException - If the returned proxy is cast to a non-interface class, or an interface not implemented by the proxy.

getProxy

public <T> T getProxy(T object,
                      InvocationHandler handler,
                      Class<?>... interfaces)
Creates a new proxy object implementing the interfaces supplied as interfaces, in order.

The proxy object is registered as a proxy object for the object supplied as object, if any. Also, if interfaces is empty, all interfaces implemented by object will be used for the returned proxy.

Proxies can be supplied as the object parameter, which allows for nested proxies.

Type Parameters:
T - The type of object.
Parameters:
object - The object to proxy; can be null.
handler - The invocation handler to use by the proxy; cannot be null.
interfaces - The interfaces to implement by the returned proxy; cannot contain null entries or non-interface classes.
Returns:
A new proxy instance; never null.
Throws:
NullPointerException - If handler or interfaces are null, or if interfaces contains a null entry.
IllegalArgumentException - If interfaces contain a non-interface class.
ClassCastException - If the returned proxy is cast to a non-interface class, or an interface not implemented by the proxy.

getProxyFactory

protected static final ProxyFactory getProxyFactory(Object proxy)
Returns the proxy factory that created the proxy supplied as proxy, or null if proxy is not a proxy created by a proxy factory.

Parameters:
proxy - The proxy object; cannot be null.
Returns:
The proxy factory, or null.
Throws:
NullPointerException - If proxy is null.
UnsupportedOperationException - If this method is invoked from a non sub-class context.

getSharedObject

public <T> T getSharedObject(T object,
                             String copyMethod,
                             Class<?>[] parameterTypes,
                             String... mutatorMethods)
                  throws Exception
Returns a (proxy) reference to object that can be shared and copied by different contexts until a given mutator method is invoked on it, forcing the original object to be copied. Both copy and mutator methods are supplied as arguments to this method.

All access to object is via the interfaces the class of it implements. All access to object should be though the returned proxy.

Since the returned object is a java.lang.reflect.Proxy instance, the normal rules for Proxy objects apply! An implication of this is that even if a specific instance is supplied as object, i.e. a specific class, the returned (proxy) object cannot be cast back into that type (the specific type information is "lost").

Example:

   // Interface of objects to be shared...
   public interface Foo {
     // Normal methods that can be shared...
     public int getFooCount();
     
     public String toString();
     ..
     
     // Mutator methods, which when invoked may cause a copy...
     public void setFooCount(int count);
     
     public void resetFooCount();
     .. 
     
     // Copy method to perform the actual copying...
     public Foo copy(boolean deep);
   }

   // Implementation...
   public class FooBar implements Foo {
     ..
   }

   ..
   
   // Specify copy method...
   String copyMethod = "copy";
   // "boolean" formal parameter (primitive types are ignored)...
   Class<?> parameterTypes = {Boolean.class}; // or Boolean.TYPE
   // Mutator methods, based on name only...
   String[] mutators = {"getFooCount", "resetFooCount"};
      
   // "foo" is the instance to be shared (originally)...
   Foo foo = new FooBar();
   
   ProxyFactory factory = new ProxyFactory();
   
   // No class casting needed...
   Foo foobar = factory.getSharedObject(foo, copyMethod, parameterTypes, mutatorMethods); // Can also use varargs for mutators
   
   // Create a copy using the normal copy method. This will increase the 
   // reference count to "foo"...
   Foo foofoo = foobar.copy(true);
   
   // Access to non-mutator methods will not cause a copy...
   System.out.println(foobar.getFooCount());
   System.out.println(foofoo); // toString()
   ..
   
   // Access to a mutator method in any copy will force "foo" to
   // be copied because more than one reference. The value 42 will
   // be set in a copy of "foo" used by "foofoo", not in other
   // references (here, "foobar")...
   foofoo.setFooCount(42);
   
   // Only one reference, so if "foobar" accesses mutator methods,
   // no copy will be made (until copied again)...
   foobar.resetFooCount();
   .. 
 

Type Parameters:
T - The type of object.
Parameters:
object - The actual object to be shared; cannot be null.
copyMethod - The name of the copy method to use; cannot be null. Must be declared in the class of object, but will be made accessible if not already.
parameterTypes - The formal parameter types of copyMethod, if any, ignoring primitive types; can be null.
mutatorMethods - The names of the mutator methods that will force a copy of object before executed; cannot be null or empty.
Returns:
A proxy representing the shared object; never null.
Throws:
NullPointerException - If object or copyMethod are null.
IllegalArgumentException - If mutatorMethods is empty, or if the copy method is a vararg method.
Exception - If no such copy method exists.
See Also:
Reference, getSynchronisedObject(Object, Class...), getSynchronisedObject(Object, Object, Class...), getLoggableObject(Object, Class...)

getSynchronisedObject

public <T> T getSynchronisedObject(T object,
                                   Class<? super T>... interfaces)
Returns a synchronised (proxy) version of object that can be viewed as any of the interfaces supplied in interfaces. The synchronisation lock used is object itself.

All access to object via the methods defined in one of the types in interfaces will be synchronised on object itself if and only if object is accessed through the returned proxy object only. If object is accessed directly, synchronisation cannot be guaranteed!

If no interfaces are supplied, all interfaces implemented by object, directly or indirectly (for example via a super-class), will be used.

Since the returned object is a java.lang.reflect.Proxy instance, the normal rules for Proxy objects apply! An implication of this is that even if a specific instance is supplied as object, i.e. a specific class, the returned (proxy) object cannot be cast back into that type (the specific type information is "lost" as the class returned is an anonymous Proxy class).

Example:

   // Interfaces...
   public interface Foo {
     public String foo();
   }

   public interface Bar {
     public String bar();
   }

   ..
   
   // Implementation...
   public class FooBar implements Foo, Bar {
     public String foo() {
       return "foo";
     }     
     public String bar() {
       return "bar";
     }     
   }
   
   ..
   
   FooBar foobar = new FooBar();
   
   ProxyFactory factory = new ProxyFactory();
   
   // No class casting needed, since we only use a single interface...
   Foo foo = factory.getSynchronisedObject(foobar, Foo.class);
          
   // All access to the methods defined in Foo will now be 
   // synchronised on "foobar" when accessing through "foo":
   
   String s = foobar.foo() // *not* synchronised
          s = foo.foo();   // synchronised
   
   // Will throw a class cast exception! 
   FooBar goo = (FooBar)foo;
   
   ..
   
   // A class cast is now required, since more than one interface
   // is implemented by the returned proxy. A cast to either type
   // is valid...
   foo = (Foo)factory.getSynchronisedObject(foobar, Foo.class, Bar.class);
          
   // All access to the methods defined in Foo *and* Bar will now
   // be synchronised on "foobar" when accessing through "foo" and "bar":
   
   String s = foobar.foo(); // *not* synchronised
          s = foobar.bar(); // *not* synchronised
          s = foo.foo();    // synchronised
          
   // Must cast to access "bar"...          
   Bar bar = (Bar)foo;       
          s = bar.bar();    // synchronised 
                           
   // Will throw a class cast exception! 
   FooBar goo = (FooBar)bar;
   
   // Default - all interfaces implemented by FooBar (including 
   // those from super-classes) - no class casting is required, 
   // but the returned proxy can simply be assigned to a proper type:
   
   foo = factory.getSynchronisedObject(foobar); // Foo.class & Bar.class
   bar = factory.getSynchronisedObject(foobar); // Foo.class & Bar.class
 
Proxies can be supplied as the object parameter, which allows for nested synchronisation.

Type Parameters:
T - The type of object.
Parameters:
object - The actual object to be used; cannot be null, and must implement all the interfaces supplied as interfaces.
interfaces - The interfaces to supply the methods to be synchronised; can be null, in which case all interfaces implemented by the class of object will be used.
Returns:
A proxy object, synchronised on all methods defined in interfaces; never null.
Throws:
NullPointerException - If object is null.
IllegalArgumentException - If interfaces contain an non-interface type.
See Also:
getSynchronisedObject(Object, Object, Class...), getLoggableObject(Object, Class...), getSharedObject(Object, String, Class[], String...)

getSynchronisedObject

public <T> T getSynchronisedObject(T object,
                                   Object lock,
                                   Class<? super T>... interfaces)
Returns a synchronised (proxy) version of object that can be viewed as any of the interfaces supplied in interfaces, synchronised on the object supplied as lock.

All access to object via the methods defined in one of the types in interfaces will be synchronised on lock if and only if object is accessed through the returned proxy object only. If object is accessed directly, synchronisation cannot be guaranteed!

If no interfaces are supplied, all interfaces implemented by object, directly or indirectly (for example via a super-class), will be used.

Since the returned object is a java.lang.reflect.Proxy instance, the normal rules for Proxy objects apply! An implication of this is that even if a specific instance is supplied as object, the returned (proxy) object cannot be cast back into that type (the specific type information is "lost" as the class returned is an anonymous Proxy class).

Example:

   // Interfaces...
   public interface Foo {
     public String foo();
   }
 
   public interface Bar {
     public String bar();
   }

   ..
   
   // Implementation...
   public class FooBar implements Foo, Bar {
     public String foo() {
       return "foo";
     }     
      public String bar() {
       return "bar";
     }     
   }
   
   ..
   
   Object lock = new Object();
   FooBar foobar = new FooBar();
   
   ProxyFactory factory = new ProxyFactory();
   
   // No class casting needed, since we only use a single interface...
   Foo foo = factory.getSynchronisedObject(foobar, lock, Foo.class);
           
   // All access to the methods defined in Foo will now be 
   // synchronised on "lock" when accessing through "foo":
   
   String s = foobar.foo() // *not* synchronised
          s = foo.foo();   // synchronised
   
   // Will throw a class cast exception! 
   FooBar goo = (FooBar)foo;
   
   ..
   
   // A class cast is now required, since more than one interface
   // is implemented by the returned proxy. A cast to either type
   // is valid...
   foo = (Foo)factory.getSynchronisedObject(foobar, lock, Foo.class, Bar.class);
          
   // All access to the methods defined in Foo *and* Bar will now
   // be synchronised on "lock" when accessing through "foo" and "bar":
   
   String s = foobar.foo(); // *not* synchronised
          s = foobar.bar(); // *not* synchronised
          s = foo.foo();    // synchronised
          
   // Must cast to access "bar"...          
   Bar bar = (Bar)foo;       
          s = bar.bar();    // synchronised 
                           
   // Will throw a class cast exception! 
   FooBar goo = (FooBar)bar;
   
   // Default - all interfaces implemented by FooBar (including 
   // those from super-classes) - no class casting is required, 
   // but the returned proxy can simply be assigned to a proper type:
   
   foo = factory.getSynchronisedObject(foobar, lock); // Foo.class & Bar.class
   bar = factory.getSynchronisedObject(foobar, lock); // Foo.class & Bar.class
 
Proxies can be supplied as the object parameter, which allows nested synchronisation.

Type Parameters:
T - The type of object.
Parameters:
object - The actual object to be used; cannot be null, and must implement all the interfaces supplied as interfaces.
lock - The object to synchronise on; cannot be null.
interfaces - The interfaces to supply the methods to be synchronised; can be null, in which case all interfaces implemented by the class of object will be used.
Returns:
A proxy object, synchronised on all methods defined in interfaces; never null.
Throws:
NullPointerException - If object or lock are null.
IllegalArgumentException - If interfaces contain an non-interface type.
See Also:
getSynchronisedObject(Object, Object, Class...), getLoggableObject(Object, Class...), getSharedObject(Object, String, Class[], String...)

hashCode

public final int hashCode()
Returns the hash code of this factory.

Overrides:
hashCode in class Object
Returns:
The hash code.

isProxied

public boolean isProxied(Object object)
Returns true if the object supplied as object is proxied by a proxy created by this factory, false if not.

Parameters:
object - The object to test; cannot be null.
Returns:
True if proxied, false if not.
Throws:
NullPointerException - If object is null.

isProxy

public boolean isProxy(Object object)
Returns true if object is a proxy created by this proxy factory, false if not.

Parameters:
object - The object to test; cannot be null.
Returns:
True if a proxy created by this factory, false if not.
Throws:
NullPointerException - If object is null.

register

protected void register(Object proxy,
                        Object object)
Registers the proxied object supplied as object for the proxy supplied as proxy.

Parameters:
proxy - The proxy; cannot be null.
object - The proxied object; cannot be null.
Throws:
NullPointerException - If either argument is null.
IllegalArgumentException - If proxy already has an associated proxied object.
UnsupportedOperationException - If this method is invoked from a non sub-class context.

toString

public String toString()
Return the string representation of this factory.

Overrides:
toString in class Object
Returns:
The string representation; never null.

Gunni Rode / rode.dk

Feel free to use and/or modify the Java 6 source code developed for this thesis AT YOUR OWN RISK, but note that the source code comes WITHOUT ANY — and I do mean WITHOUT ANY — form of warranty WHAT SO EVER!

The original thesis and source code are available at rode.dk/thesis.