mandala.util
Class SingletonGiver

java.lang.Object
  extended bymandala.util.SingletonGiver

public class SingletonGiver
extends java.lang.Object

This class provides a general purpose singleton implementation.

Each instance of this class is associated with:

The method getInstance(Object, Object[] args) returns the singleton mapped to the specified object in the cache or the one returned by the factory. In this latter case, the singleton is also mapped to the specified object in the cache using the register(Object singleton, Object object) method.

Users must be aware of the mapping they want for their singletons. Default mapping is done by a IdentityHashMap which provides the "natural behavior": two objects share the same singleton if and only if they are the same objects (in the sense of the '==' operator). Note that it is possible to use a "traditionnal" Map implementation such as HashMap for the mapping. In this case, two objects share the same singleton if and only if they are equals (in the sense of Object.equals(Object)).

The method unregister(Object) allows mapping to be removed from the cache. This implementation uses a WeakValuesMap wrapper so registered objects don't have to use theirObject.finalize() method to ensure they are unregistered when garbage collected. This means, singletons may be garbage collected when they are not strongly referenced. Hence, multiple call to getInstance(Object) may occurs for the same object when a singleton has already been mapped in the cache but has been garbage collected. Singleton implementation must define a readResolve() method in order to behave as singleton on deserialization. The general schema for a singleton implementation is given by the following code:


public class MyClass {

   private key; // The key for which this instance stand for a singleton.  

   // Do not provide a public constructor
   protected MyClass(Object key, Param1 param1, ..., ParamN paramN) {
       this.key = key;
       ...
   }

   private static final SingletonGiver singletonGiver =     
       new SingletonGiver(new SingletonGiver.Factory() {
           // Implements my singleton policy
               public Object newInstance(Object key, Object[] args) {
                   // if args.length == 1 it means singleton is used in
                   // deserialization (see readResolve() below) and that
                   // args[0] contains the reference to return.
                   if (args.length == 1) {
                       return args[0];
                   }

                    if (args.length == N) {
                        return new MyClass(object, param1, ..., paramN);
                    }

                    throw new Error("Wrong number of arguments!");
                }
       });

    // Singleton instance are given by the following method
    public static MyClass getInstance(Object key, 
                                      Param1 param1,
                                      ..., 
                                      ParamN paramN) {

    return (MyClass) singletonGiver.getInstance(key, 
                                                new Object[]{param1,
                                                             ...
                                                             paramN});
    }

    // Warning : Singleton must be respected! readResolve() help us in this way!
    private Object readResolve() throws ObjectStreamException {

        // Do not create a MyClass instance with 'new' as in getInstance(), use
        // 'this' instead
        return singletonGiver.getInstance(key, 
                                          new Object[]{this});
    }
   

Version:
1.0
Author:
eipi

Nested Class Summary
static interface SingletonGiver.Factory
          Interface that define how singleton are created.
 
Field Summary
protected  java.util.Map cache
          References cache.
protected  SingletonGiver.Factory factory
          The factory used to create singletons.
protected static Syslog syslog
          Message logger.
 
Constructor Summary
SingletonGiver(SingletonGiver.Factory factory)
          Creates a new SingletonGiver instance.
SingletonGiver(SingletonGiver.Factory factory, java.util.Map cache)
          Creates a new SingletonGiver instance.
 
Method Summary
 java.lang.Object getInstance(java.lang.Object object)
          Equivalent to getInstance(object, null).
 java.lang.Object getInstance(java.lang.Object object, java.lang.Object[] args)
          Returns the singleton to which the specified object is mapped to.
static Syslog getSyslog()
          Returns the logger.
 void register(java.lang.Object object, java.lang.Object singleton)
          Register a mapping.
static void setSyslog(Syslog syslog)
          Sets the logger.
 void unregister(java.lang.Object object)
          Unregister a mapping.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

syslog

protected static Syslog syslog

Message logger.

Each message (debug, log, warning, error, ...) are wrote to this message logger.

See Also:
Syslog

factory

protected final SingletonGiver.Factory factory

The factory used to create singletons.


cache

protected final java.util.Map cache

References cache.

Constructor Detail

SingletonGiver

public SingletonGiver(SingletonGiver.Factory factory)

Creates a new SingletonGiver instance.

Use the default IdentityHashMap implementation for the cache.

Parameters:
factory - the factory used to create new singleton
See Also:
SingletonGiver.Factory

SingletonGiver

public SingletonGiver(SingletonGiver.Factory factory,
                      java.util.Map cache)

Creates a new SingletonGiver instance.

Parameters:
factory - the factory used to create new singleton
cache - the map implementation to use as a cache
Method Detail

getSyslog

public static Syslog getSyslog()

Returns the logger.

Returns:
the logger

setSyslog

public static void setSyslog(Syslog syslog)

Sets the logger.

Parameters:
syslog - the logger to set

register

public void register(java.lang.Object object,
                     java.lang.Object singleton)

Register a mapping.

Parameters:
object - the object mapped to the given singleton
singleton - the singleton

unregister

public void unregister(java.lang.Object object)

Unregister a mapping.

Parameters:
object - the object previously mapped to a singleton

getInstance

public java.lang.Object getInstance(java.lang.Object object)

Equivalent to getInstance(object, null).

See Also:
getInstance(Object, Object[])

getInstance

public java.lang.Object getInstance(java.lang.Object object,
                                    java.lang.Object[] args)

Returns the singleton to which the specified object is mapped to.

If a mapping has already been registered for the given object, the mapped singleton is returned, otherwise a new one is created using the current factory SingletonGiver.Factory.newInstance(Object, Object[]), and returned after having registered its mapping.

Notice that the mapping depends on the cache implementation: if the mapping is based on the '==' operator (such as the IdentityHashMap class), then:

       getInstance(a) == getInstance(b) <=> a == b 
       
Otherwise, if the mapping is based on the Object.equals(Object), (as documented by the Map interface and as implemented by HashMap), then:
       getInstance(a) == getInstance(b) <=> a.equals(b) 
       

Parameters:
object - the object to get a singleton from
args - the arguments to use to create the mapped singleton for the sepcified object
Returns:
the mapped singleton
See Also:
SingletonGiver.Factory


Mandala help mailing list