FileDocCategorySizeDatePackage
IndirectSet.javaAPI DocGlassfish v2 API17964Tue May 22 16:54:20 BST 2007oracle.toplink.essentials.indirection

IndirectSet

public class IndirectSet extends Object implements Serializable, Set, IndirectContainer, Cloneable
IndirectSet is an example implementation of the Set protocol that allows a domain class to take advantage of TopLink Indirection without having to declare its instance variable as a ValueHolderInterface.

To use an IndirectSet:

  • Declare the appropriate instance variable with type Set (or Collection).
  • Send the message #useTransparentCollection() to the appropriate CollectionMapping.
  • Send the message #useCollectionClass(IndirectSet.class) to the same CollectionMapping. (The order of these two message sends is significant.)
TopLink will place an IndirectSet in the instance variable when the containing domain object is read from the datatabase. With the first message sent to the IndirectSet, the contents are fetched from the database and normal Set behavior is resumed.

Implementation notes:

  • The Set interface is implemented by delegating nearly every message to the Set held on to by the 'delegate' instance variable. (The 'delegate' will be either a HashSet or yet another IndirectSet.)
  • The IndirectContainer interface is implemented in a straightforward fashion:
    • #get- and #setValueHolder() are implemented as simple accessors for the 'valueHolder' instance variable. (Note that #setValueHolder() clears out the 'delegate' instance variable, since its contents are invalidated by the arrival of a new value holder.)
    • #isInstantiated() is simply delegated to the value holder.
  • TopLink requires that the Cloneable interface be implemented. The #clone() method must clone the 'delegate'. (The implementation here uses reflection to invoke the #clone() method because it is not included in the common interface shared by IndirectSet and its base delegate class, HashSet; namely, Set.)
  • TopLink requires that the Serializable interface be implemented.
  • The database read is ultimately triggered when one of the "delegated" methods makes the first call to #getDelegate(), which in turn calls #buildDelegate(), which sends the message #getValue() to the value holder. The value holder performs the database read.
  • For debugging purposes, #toString() will not trigger a database read. This is not required behavior.
see
oracle.toplink.essentials.mappings.CollectionMapping
author
Big Country
since
TOPLink/Java 3.0+

Fields Summary
private Set
delegate
Reduce type casting
private ValueHolderInterface
valueHolder
Delegate indirection behavior to a value holder
private String
attributeName
The mapping attribute name, used to raise change events.
protected int
initialCapacity
Store initial size for lazy init.
protected float
loadFactor
Store load factor for lazy init.
Constructors Summary
public IndirectSet()
Construct an empty IndirectSet.


             
      
        this.delegate = null;
        this.valueHolder = null;
    
public IndirectSet(int initialCapacity)
Construct an empty IndirectSet with the specified initial capacity.

param
initialCapacity the initial capacity of the set
exception
IllegalArgumentException if the specified initial capacity is negative

        this.delegate = null;
        this.initialCapacity = initialCapacity;
        this.valueHolder = null;
    
public IndirectSet(int initialCapacity, float loadFactor)
Construct an empty IndirectSet with the specified initial capacity and load factor.

param
initialCapacity the initial capacity of the set
param
loadFactor the load factor of the set
exception
IllegalArgumentException if the specified initial capacity is negative

        this.delegate = null;
        this.initialCapacity = initialCapacity;
        this.loadFactor = loadFactor;
        this.valueHolder = null;
    
public IndirectSet(Collection c)
Construct an IndirectSet containing the elements of the specified collection.

param
c the initial elements of the set

        this.delegate = null;
        this.valueHolder = new ValueHolder(new HashSet(c));
    
Methods Summary
public synchronized booleanadd(java.lang.Object o)

see
java.util.Set#add(java.lang.Object)

        this.getDelegate().add(o);
        this.raiseAddChangeEvent(o);
        return true;
    
public synchronized booleanaddAll(java.util.Collection c)

see
java.util.Set#addAll(java.util.Collection)

        // Must trigger add events if tracked or uow.
        if (hasBeenRegistered()) {
            Iterator objects = c.iterator();
            while (objects.hasNext()) {
                this.add(objects.next());
            }
            return true;
        }

        return getDelegate().addAll(c);
    
protected java.util.SetbuildDelegate()
Return the freshly-built delegate.

        return (Set)getValueHolder().getValue();
    
public voidclear()

see
java.util.Set#clear()

        if (hasBeenRegistered()) {
            Iterator objects = this.iterator();
            while (objects.hasNext()) {
                Object o = objects.next();
                objects.remove();
                this.raiseRemoveChangeEvent(o);
            }
        } else {
            this.getDelegate().clear();
        }
    
public java.lang.Objectclone()

see
java.lang.Object#clone() This will result in a database query if necessary.

        try {
            IndirectSet result = (IndirectSet)super.clone();
            result.delegate = this.cloneDelegate();
            result.attributeName = null;
            return result;
        } catch (CloneNotSupportedException e) {
            throw new InternalError("clone not supported");
        }
    
protected java.util.SetcloneDelegate()
Clone the delegate.

        java.lang.reflect.Method cloneMethod;
        try {
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try {
                    cloneMethod = (Method)AccessController.doPrivileged(new PrivilegedGetMethod(this.getDelegate().getClass(), "clone", (Class[])null, false));
                } catch (PrivilegedActionException exception) {
                    throw QueryException.cloneMethodRequired();
                }
            } else {
                cloneMethod = PrivilegedAccessHelper.getMethod(this.getDelegate().getClass(), "clone", (Class[])null, false);
            }
        } catch (NoSuchMethodException ex) {
            throw QueryException.cloneMethodRequired();
        }

        try {
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try {
                    return (Set)AccessController.doPrivileged(new PrivilegedMethodInvoker(cloneMethod, this.getDelegate(), (Object[])null));
                } catch (PrivilegedActionException exception) {
                    Exception throwableException = exception.getException();
                    if (throwableException instanceof IllegalAccessException) {
                        throw QueryException.cloneMethodInaccessible();
                    } else {
                        throw QueryException.cloneMethodThrowException(((java.lang.reflect.InvocationTargetException)throwableException).getTargetException());
                    }
                }
            } else {
                return (Set)PrivilegedAccessHelper.invokeMethod(cloneMethod, this.getDelegate(), (Object[])null);
            }
        } catch (IllegalAccessException ex1) {
            throw QueryException.cloneMethodInaccessible();
        } catch (java.lang.reflect.InvocationTargetException ex2) {
            throw QueryException.cloneMethodThrowException(ex2.getTargetException());
        }
    
public booleancontains(java.lang.Object o)

see
java.util.Set#contains(java.lang.Object)

        return this.getDelegate().contains(o);
    
public booleancontainsAll(java.util.Collection c)

see
java.util.Set#containsAll(java.util.Collection)

        return this.getDelegate().containsAll(c);
    
public booleanequals(java.lang.Object o)

see
java.util.Set#equals(java.lang.Object)

        return this.getDelegate().equals(o);
    
protected java.util.SetgetDelegate()
Check whether the contents have been read from the database. If they have not, read them and set the delegate.

        if (delegate == null) {
            delegate = this.buildDelegate();
        }
        return delegate;
    
public java.lang.StringgetTopLinkAttributeName()
Return the mapping attribute name, used to raise change events.

         return attributeName;
     
public oracle.toplink.essentials.indirection.ValueHolderInterfacegetValueHolder()
Return the valueHolder.

        // PERF: lazy initialize value holder and vector as are normally set after creation.
        if (valueHolder == null) {
            valueHolder = new ValueHolder(new HashSet(initialCapacity, loadFactor));
        }
        return valueHolder;
    
public booleanhasBeenRegistered()
INTERNAL: Return whether this IndirectSet has been registered in a UnitOfWork

        return getValueHolder() instanceof oracle.toplink.essentials.internal.indirection.UnitOfWorkQueryValueHolder;
    
public inthashCode()

see
java.util.Set#hashCode()

        return this.getDelegate().hashCode();
    
public booleanisEmpty()

see
java.util.Set#isEmpty()

        return this.getDelegate().isEmpty();
    
public booleanisInstantiated()
Return whether the contents have been read from the database.

        return this.getValueHolder().isInstantiated();
    
public java.util.Iteratoriterator()

see
java.util.Set#iterator()

        // Must wrap the interator to raise the remove event.
        return new Iterator() {
            Iterator delegateIterator = IndirectSet.this.getDelegate().iterator();
            Object currentObject;
            
            public boolean hasNext() {
                return this.delegateIterator.hasNext();
            }
            
            public Object next() {
                this.currentObject = this.delegateIterator.next();
                return this.currentObject;
            }
            
            public void remove() {
                this.delegateIterator.remove();
                IndirectSet.this.raiseRemoveChangeEvent(this.currentObject);
            }
        };
    
protected voidraiseAddChangeEvent(java.lang.Object element)
Raise the add change event and relationship maintainence.

        if (hasBeenRegistered()) {
            ((UnitOfWorkQueryValueHolder)getValueHolder()).updateForeignReferenceSet(element, null);
        }
    
protected voidraiseRemoveChangeEvent(java.lang.Object element)
Raise the remove change event.

        if (hasBeenRegistered()) {
            ((UnitOfWorkQueryValueHolder)getValueHolder()).updateForeignReferenceRemove(element);
        }
    
public synchronized booleanremove(java.lang.Object o)

see
java.util.Set#remove(java.lang.Object)

        if (this.getDelegate().remove(o)) {     
            this.raiseRemoveChangeEvent(o);
            return true;
        }
        return false;
    
public synchronized booleanremoveAll(java.util.Collection c)

see
java.util.Set#removeAll(java.util.Collection)

        // Must trigger remove events if tracked or uow.
        if (hasBeenRegistered()) {
            Iterator objects = c.iterator();
            while (objects.hasNext()) {
                this.remove(objects.next());
            }
            return true;
        }
        return this.getDelegate().removeAll(c);
    
public synchronized booleanretainAll(java.util.Collection c)

see
java.util.Set#retainAll(java.util.Collection)

        // Must trigger remove events if tracked or uow.
        if (hasBeenRegistered()) {
            Iterator objects = getDelegate().iterator();
            while (objects.hasNext()) {
                Object object = objects.next();
                if (!c.contains(object)) {
                    objects.remove();
                    this.raiseRemoveChangeEvent(object);
                }
            }
            return true;
        }
        return this.getDelegate().retainAll(c);
    
public voidsetTopLinkAttributeName(java.lang.String attributeName)
Set the mapping attribute name, used to raise change events. This is required if the change listener is set.

         this.attributeName = attributeName;
     
public voidsetValueHolder(oracle.toplink.essentials.indirection.ValueHolderInterface valueHolder)
Set the value holder. Note that the delegate must be cleared out.

        this.delegate = null;
        this.valueHolder = valueHolder;
    
public intsize()

see
java.util.Set#size()

        return this.getDelegate().size();
    
public java.lang.Object[]toArray()

see
java.util.Set#toArray()

        return this.getDelegate().toArray();
    
public java.lang.Object[]toArray(java.lang.Object[] a)

see
java.util.Set#toArray(java.lang.Object[])

        return this.getDelegate().toArray(a);
    
public java.lang.StringtoString()
Use the delegate's #toString(); but wrap it with braces to indicate there is a bit of indirection. Don't allow this method to trigger a database read.

see
java.util.HashSet#toString()

        if (ValueHolderInterface.shouldToStringInstantiate) {
            return this.getDelegate().toString();
        }
        if (this.isInstantiated()) {
            return "{" + this.getDelegate().toString() + "}";
        } else {
            return "{" + oracle.toplink.essentials.internal.helper.Helper.getShortClassName(this.getClass()) + ": " + ToStringLocalization.buildMessage("not_instantiated", (Object[])null) + "}";

        }