ch.elca.el4j.services.persistence.generic.dao
Class AbstractIdentityFixer

java.lang.Object
  extended by ch.elca.el4j.services.persistence.generic.dao.AbstractIdentityFixer
Direct Known Subclasses:
HibernateProxyAwareIdentityFixer

public abstract class AbstractIdentityFixer
extends Object

Fixes object identities mangled by loosing ORM context or by remoting.

Motivation

Object Identity is an important concept in OOP, but is not always guaranteed or maintained. For instance, sending an object back and forth over the wire (using any standard remoting protocol) will create new objects, causing changes applied to the object not to propagate properly - even within a single VM. Similarly, loosing an OR-Mapper's context between load invocations typically results in creating multiple proxies to the same persisted object. Accepting that loss of identity complicates the programming model, and contradicts OO methodology.

Given a definition of logical identity and a means to recognize immutable value types, an instance of this class fixes the identities of the objects passing through it while propagating state updates to the logical object's unique representative.

Terminology

A representative is an object that has a logical identity. A given identity fixer will always return the same representative for every logical identity, different identity fixers may return different ones. Usually, you will therefore use a singleton identity fixer, but you may allocate as many as you please ;-)

Configuration

To get a working identity fixer, you must write a subclass and override the three abstract methods, id(Object), immutableValue(Object) and prepareObject(Object).

Use

All objects received from an identity-mangling source should pass through an identity fixer. AbstractIdentityFixer.GenericInterceptor provides a generic Spring AOP interceptor to be wrapped around the identity-mangling objects. As an alternative, manual access to identity translation is granted by merge(Object, Object).

Guarantees

During its lifetime, an identity fixer will always return the same object for every logical identity. It will update the shared instance with the state of the new copies - according to a specified IdentityFixerMergePolicy or by its default policy -, and notify registered observers about every such update. These guarantees extend to objects (directly or indirectly) referenced by the translated object unless they are recognized as immutable values by immutableValue(Object).

2-way merging of Collections

Since some identity-mangling sources are replacing collections by own implementations containing also metadata, this class offers a mechanism to work on normal java collections while the source still gets to work on its own versions of the collections.
To set up a working 2-way merging, you need to:

Requirements

This class needs ReflectPermission "suppressAccessChecks" if a security manager is present and an object requiring fixing has non-public fields.

Author:
Adrian Moos (AMS)
File-location:
AbstractIdentityFixer
Last check-in date:
2010-01-05 09:38:21 +0100 (Di, 05. Jan 2010) by jonasha for revision 4068

Nested Class Summary
 class AbstractIdentityFixer.GenericInterceptor
          A generic "around advice" (as defined in AOP terminology) for remote objects.
 
Field Summary
protected static Object ANONYMOUS
          Id for objects of anonymous types (= value types).
 
Constructor Summary
AbstractIdentityFixer()
          Constructs a new IdentityFixer.
AbstractIdentityFixer(DaoChangeNotifier changeNotifier)
          Constructor.
 
Method Summary
 DaoChangeNotifier getChangeNotifier()
          Returns the notifier used to announce changes.
 Collection<?> getRepresentatives()
           
protected abstract  Object id(Object o)
          Returns the globally unique, logical id for the provided object, or null, if it has no id (yet), or ANONYMOUS is this object is of value type.
protected abstract  boolean immutableValue(Object o)
          Returns whether the given reference represents an immutable value, either because it really is a value (null) or because the referenced object's identity is not accessed and its state is not modified.
protected static List<AccessibleObject> instanceAccessibleObjects(Class<?> c)
          Returns a list of all non-static AccessibleObjects (fields and methods, no constructors) of class c.
protected static List<Field> instanceFields(Class<?> c)
          Returns a list of all non-static fields of class c.
 boolean isRepresentative(Object object)
           
<T> T
merge(T anchor, T updated)
          Updates the unique representative by duplicating the state in updated.
protected
<T> T
merge(T anchor, T updated, boolean isIdentical, IdentityHashMap<Object,Object> reached, List<Object> objectsToUpdate, IdentityHashMap<Object,Object> hintMapping)
          Deprecated. 
<T> T
merge(T anchor, T updated, IdentityFixerMergePolicy policy)
          Updates the set of unique representatives according to the IdentityFixerMergePolicy.
protected
<T> T
merge(T anchor, T updated, IdentityFixerMergePolicy policy, boolean isIdentical, IdentityHashMap<Object,Object> reached, HashMap<Object,Object> locked)
          Actually performs the merge.
protected  boolean needsAdditionalProcessing(Object o)
           
protected abstract  Object prepareObject(Object o)
          Returns the prepared Object, is called before checked for immutability to give the id fixer the chance to convert immutable values to usable ones.
 void removeRepresentative(Object object)
          Remove an object from the representatives.
 List<Object> reverseMerge(List<Object> objects)
          Prepare a list of objects to be passed to an identity-mangling source.
 Object reverseMerge(Object object, boolean mergeRecursive)
          Prepare an object to be passed to an identity-mangling source.
protected  Object reverseMerge(Object object, IdentityHashMap<Object,Object> reached, boolean mergeRecursive)
          Prepare an object to be passed to an identity-mangling source.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

ANONYMOUS

protected static final Object ANONYMOUS
Id for objects of anonymous types (= value types).

Constructor Detail

AbstractIdentityFixer

public AbstractIdentityFixer()
Constructs a new IdentityFixer. You'd never have guessed that, would you? ;-)


AbstractIdentityFixer

public AbstractIdentityFixer(DaoChangeNotifier changeNotifier)
Constructor.

Parameters:
changeNotifier - The notifier for broadcasting changes.
Method Detail

getChangeNotifier

public DaoChangeNotifier getChangeNotifier()
Returns the notifier used to announce changes. Chiefly useful because you can subscribe to change messages there.

Returns:
see above

instanceFields

protected static List<Field> instanceFields(Class<?> c)
Returns a list of all non-static fields of class c.

Parameters:
c - The concerned class
Returns:
A list of all non-static fields of the given class

instanceAccessibleObjects

protected static List<AccessibleObject> instanceAccessibleObjects(Class<?> c)
Returns a list of all non-static AccessibleObjects (fields and methods, no constructors) of class c. Also searches in superclasses.

Parameters:
c - the concerned class
Returns:
The accessible objects of this class.

merge

@Deprecated
protected <T> T merge(T anchor,
                                 T updated,
                                 boolean isIdentical,
                                 IdentityHashMap<Object,Object> reached,
                                 List<Object> objectsToUpdate,
                                 IdentityHashMap<Object,Object> hintMapping)
Deprecated. 

Actually performs the merge.

Parameters:
anchor - the (presumed) representative, or null
updated - the new version of the object
isIdentical - whether anchor is known to be transitively identical with updated.
reached - the set of objects in the updated object graph that have been (or are being) merged. Used to avoid merging an object more than once.
objectsToUpdate - A list of anchor objects that should updated, all other objects are not touched. If objectsToUpdate is null then all reachable objects get updated.
hintMapping - A map of [updated -> anchor] used to correctly merge collections. If no collections have to be merged this parameter can be null.
Returns:
the representative.

merge

protected <T> T merge(T anchor,
                      T updated,
                      IdentityFixerMergePolicy policy,
                      boolean isIdentical,
                      IdentityHashMap<Object,Object> reached,
                      HashMap<Object,Object> locked)
Actually performs the merge.

Parameters:
anchor - the (presumed) representative, or null
updated - the new version of the object
policy - the policy to use.
isIdentical - whether anchor is known to be transitively identical with updated.
reached - the set of objects in the updated object graph that have been (or are being) merged. Used to avoid merging an object more than once.
locked - the set of id's that are locked for updating unless the new version is the specified object. This map should be used to prevent updating a representative multiple times which might result in a update to an old or non fully loaded object.
Returns:
the representative.

merge

public <T> T merge(T anchor,
                   T updated)
Updates the unique representative by duplicating the state in updated. If no representative exists so far, one is created.

For every potentially modified entity, DaoChangeNotifier.NewEntityState notification are sent using the configured change notifier.

Parameters:
anchor - the representative known to be transitively identical with updated, or null, if the representative's logical identity is already defined.
updated - The object holding the new state.
Returns:
The representative.

merge

public <T> T merge(T anchor,
                   T updated,
                   IdentityFixerMergePolicy policy)
Updates the set of unique representatives according to the IdentityFixerMergePolicy. If no representative exists of an object contained by the graph of objects in updated so far, one is created.

For every potentially modified entity, DaoChangeNotifier.NewEntityState notification are sent using the configured change notifier.

Parameters:
anchor - the representative known to be transitively identical with updated, or null, if the representative's logical identity is already defined.
updated - The object holding the new state.
policy - The policy how to merge the representatives.
Returns:
The representative.
See Also:
IdentityFixerMergePolicy

reverseMerge

protected Object reverseMerge(Object object,
                              IdentityHashMap<Object,Object> reached,
                              boolean mergeRecursive)
Prepare an object to be passed to an identity-mangling source. Using this method along with merge for incoming objects from the source, a 2-way merging for collections is guaranteed.

Parameters:
object - the object to be prepared.
reached - the set of objects that have been (or are being) reverseMerged. Used to avoid reverseMerging an object more than once.
mergeRecursive - if the graph of objects should be traversed recursively and prepare all objects.
Returns:
the prepared representative

reverseMerge

public Object reverseMerge(Object object,
                           boolean mergeRecursive)
Prepare an object to be passed to an identity-mangling source. Using this method along with merge for incoming objects from the source, a 2-way merging for collections is guaranteed.

Parameters:
object - the object to be prepared.
mergeRecursive - if the graph of objects should be traversed recursively and prepare all objects.
Returns:
the prepared representative

reverseMerge

public List<Object> reverseMerge(List<Object> objects)
Prepare a list of objects to be passed to an identity-mangling source. Using this method along with merge for incoming objects from the source, a 2-way merging for collections is guaranteed.

Parameters:
objects - the list of objects to be prepared.
Returns:
the prepared representatives list.

isRepresentative

public boolean isRepresentative(Object object)
Parameters:
object - the object to test
Returns:
true if object is a representative.

getRepresentatives

public Collection<?> getRepresentatives()
Returns:
a collection of all the representatives held by the identity fixer.

removeRepresentative

public void removeRepresentative(Object object)
Remove an object from the representatives.

Parameters:
object - the object to remove

id

protected abstract Object id(Object o)
Returns the globally unique, logical id for the provided object, or null, if it has no id (yet), or ANONYMOUS is this object is of value type. o may be null, point to an ordinary object or to an array.

The ID objects returned by this method must be value-comparable using equals (which implies that hashCode must be overridden as well). To permit garbage-collection, ids referring to the object they identify should do so with weak references.

Parameters:
o - The object for which a globally unique, logical id will be returned
Returns:
A globally unique, logical ID object for the given object

immutableValue

protected abstract boolean immutableValue(Object o)
Returns whether the given reference represents an immutable value, either because it really is a value (null) or because the referenced object's identity is not accessed and its state is not modified. o may be null, point to an ordinary object or to an array.

Parameters:
o - The concerned object
Returns:
True if the given object represents an immutable value, false otherwise

prepareObject

protected abstract Object prepareObject(Object o)
Returns the prepared Object, is called before checked for immutability to give the id fixer the chance to convert immutable values to usable ones.

Parameters:
o - The concerned object
Returns:
The prepared object.

needsAdditionalProcessing

protected boolean needsAdditionalProcessing(Object o)
Parameters:
o - The concerned object.
Returns:
if the object needs additional processing during a merge(T, T, boolean, java.util.IdentityHashMap, java.util.List, java.util.IdentityHashMap).


Copyright © 2005-2011 ELCA. All Rights Reserved.