You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

EO Change Notifications

Pierre Bernard

To invalidate cached versions of derived values, you might want to use this:

/** Utility class. Provides for a way to watch for changes in EOs. The main use of this would be to

  • be able to safely keep cached/computed/derived values that get cleared once out of sync.
  • @author bernard
  • @version ChangeNotificationCenter.java,v 1.1 2003/03/11 16:26:59 bernard Exp
    **/
    public class ChangeNotificationCenter
    {
    // Public class constants

/** Name of the posted notification
*/
public static final String OBJECT_CHANGED = "MBSObjectChanged";

/** Possible type of change a notification is posted for
*/
public static final String INVALIDATION = "Invalidation";

/** Possible type of change a notification is posted for
*/
public static final String DELETION = "Deletion";

/** Possible type of change a notification is posted for
*/
public static final String UPDATE = "Update";

// Private class constants

/** Key in the posted notification's userInfo dictionary.
*/
private static final String OBJECT = "MBSObject";

/** Key in the posted notification's userInfo dictionary.
*/
private static final String TYPE = "MBSType";

/** Selector used for calling the watcher object upon a change
*/
private static final NSSelector watchedObjectChangedSelector =
new NSSelector("watchedObjectChanged", new Class[]

Unknown macro: { NSNotification.class }

);

// Private class variables

/** Reference holding the shared singleton instance.
*/
private static ChangeNotificationCenter defaultCenter = null;

// Constructor

/** Singleton class
*/
private ChangeNotificationCenter()
{
super();

Class[) notificationArray = new Class(]

;
NSSelector objectsChangedIInEditingContextSelector =
new NSSelector("objectsChangedInEditingContext", notificationArray);

NSNotificationCenter.defaultCenter().addObserver(
this,
objectsChangedIInEditingContextSelector,
EOEditingContext.ObjectsChangedInEditingContextNotification,
null);
}

// Public insatnce methods

/** Method called when a change notification is received.

  • The notification is split and redispatched for all updated objects.
    */
    public void objectsChangedInEditingContext(NSNotification notification)
    {
    NSArray updated = (NSArray) notification.userInfo().objectForKey(EOObjectStore.UpdatedKey);

if (updated !=_null)
______{
_______int_count=_updated.count();
__
_______for(int_i_=0;_i<_count;_i++)
________{
_________Object_object=_updated.objectAtIndex;
_________NSDictionary_userInfo=
___________new_NSDictionary(new_Object[)_(_object,_UPDATE_),_new_Object(]{OBJECT,_TYPE});
__________NSNotificationCenter.defaultCenter().postNotification(OBJECT_CHANGED,_object,_userInfo);
________}
______}
__
_____NSArray_invalidated=_(NSArray)_notification.userInfo().objectForKey(EOObjectStore.InvalidatedKey);
__
_____if(invalidated_!= null)
{
int count = invalidated.count();

for (int i = 0; i < count; i++)
{
Object object = invalidated.objectAtIndex;
NSDictionary userInfo =
new NSDictionary(new Object[) ( object, INVALIDATION ), new Object(]

Unknown macro: { OBJECT, TYPE }

);
NSNotificationCenter.defaultCenter().postNotification(OBJECT_CHANGED, object, userInfo);
}
}

NSArray deleted = (NSArray) notification.userInfo().objectForKey(EOObjectStore.DeletedKey);

if (deleted != null)
{
int count = deleted.count();

for (int i = 0; i < count; i++)
{
Object object = deleted.objectAtIndex;
NSDictionary userInfo = new NSDictionary(new Object[) ( object, DELETION ), new Object(]

);
NSNotificationCenter.defaultCenter().postNotification(OBJECT_CHANGED, object, userInfo);
}
}
}

/** Method to be called when one creates a cached value that depends on the attributes of a given object.<BR>

  • Upon registration the object is watched and the watchedObjectChanged() is called once it changes, thus providing an
  • oppurtunity to invalidate the cached value.<BR>
  • @param watcher the watching object which should unregister before disposing
  • @param object the object to watch
  • @see #unregisterCacheDependancy
  • @see #unregisterCacheDependancies
    */
    public void registerCacheDependancy(ObserverInterface watcher, EOEnterpriseObject object)
    Unknown macro: { NSNotificationCenter.defaultCenter().addObserver(watcher, watchedObjectChangedSelector, OBJECT_CHANGED, object); }

/** Method to be called when one abandons or clears a cached value that depended on attributes of a given object.<BR>

  • @param watcher the watching object
  • @param object the object to watch
  • @see #registerCacheDependancy
    */
    public void unregisterCacheDependancy(ObserverInterface watcher, Object object)
    Unknown macro: { NSNotificationCenter.defaultCenter().removeObserver(watcher, OBJECT_CHANGED, object); }

/** Unregisters all of the callers dependancies. To be used sparingly as it may break unknown but required

  • dependancies. Usually called when disposing the calling object.<BR>
  • @param watcher the watching object
  • @see #registerCacheDependancy
  • @see #unregisterCacheDependancy
    */
    public void unregisterCacheDependancies(ObserverInterface watcher)
    Unknown macro: { NSNotificationCenter.defaultCenter().removeObserver(watcher, OBJECT_CHANGED, null); }

// Public class methods

/** Gets or lazily instantiates the shared instance of the ChangeNotificationCenter

  • @return the unique instance
    */
    public static ChangeNotificationCenter defaultCenter()
    {
    if (defaultCenter h1. null)
    Unknown macro: { createDefaultCenter(); }

return defaultCenter;
}

/** Utility method. Allows for retrieving the changed object from a notification

  • that results of registering interest in a change.
  • @param notification the received notification
  • @return the object that triggered the notification
    */
    public static EOEnterpriseObject objectFromNotification(NSNotification notification)
    Unknown macro: { return (EOEnterpriseObject) notification.userInfo().objectForKey(OBJECT); }

/** Utility method. Allows for retrieving the type of change that ocurred from a notification

  • that results of registering interest in a change.
  • @param notification the received notification
  • @return the type as one of the class constants defined in ChangeNotificationCenter
    */
    public static String typeFromNotification(NSNotification notification)
    Unknown macro: { return (String) notification.userInfo().objectForKey(TYPE); }

// Private class methods

/** Creates the singleton instance ensuring there is no existing instance.
*/
private static synchronized void createDefaultCenter()
{
if (defaultCenter null)

Unknown macro: { defaultCenter = new ChangeNotificationCenter(); }

}

// Inner interface definition

/** Interface to be implemented by objects that need to listen to changes.<BR>

  • CAVEAT: in most cases it is recommended to not directly implement the interface,
  • but rather create an inner class that implements the interface or better yet
  • extends the default implementation. Indeed if an object (e.g. an EO) which
  • participates in an inheritance hierarchy is used as receiver for notifications,
  • registering or unregistering might break functionality in a parent class.
    */
    public static interface ObserverInterface
    Unknown macro: { /** Method called when an object on which locally cached values depend is modified.<BR> * * This hook is provided as an opportunity to clear locally cached values. It's a good idea not to recreate * the cached values immediately, but on an as-needed basis. You should refrain from changing persisted EO * attributes from within this method as this might kick off another chain of notifications.<BR> * * Once the caches cleared, it would be a very good idea to unregister from further notifications until * the cache is recreated. * * @see lu.bcl.enterprise.entity.ChangeNotificationCenter#objectFromNotification * @see lu.bcl.enterprise.entity.ChangeNotificationCenter#registerCacheDependancy * @see lu.bcl.enterprise.entity.ChangeNotificationCenter#unRegisterCacheDependancy */ public void watchedObjectChanged(NSNotification notification); }

// Inner class

/** Convenience class for implementing ObserverInterface.<BR>

  • The recommended way of registering for change notificications is to create an inner
  • class extending this one.
    */
    public abstract static class Observer implements ObserverInterface
    {
    /** Method to be called by subclasses when the create a cached value that depends on the attributes of a given object.<BR>
  • Upon registration the object is watched and the clearCachedValues() is called once it changes, thus providing an
  • oppurtunity to invalidate the cached value.<BR>
  • You need to register for each object your locally cached values depend on. E.g. if you build a cached value from
  • attributes of EOs in a too-many relationship, your cache depends on each of the objects in the relationship as well
  • as on the source of the realtionship.<BR>
  • N.B. Extend the dispose() method to unregister any dependancy you might be registered for.
  • @param object the object to watch
  • @see #unregisterCacheDependancy
  • @see #clearCachedValues
    */
    protected void registerCacheDependancy(EOEnterpriseObject object)
    Unknown macro: { ChangeNotificationCenter.defaultCenter().registerCacheDependancy(this, object); }

/** Method to be called by subclasses when they abandon or clear a cached value that depended on attributes

  • of a given object.<BR>
    *
  • @param object the object to watch
  • @see #registerCacheDependancy
  • @see #clearCachedValues
    */
    protected void unregisterCacheDependancy(EOEnterpriseObject object)
    Unknown macro: { ChangeNotificationCenter.defaultCenter().unregisterCacheDependancy(this, object); }

/** Unregisters all of the callers dependancies. To be used sparingly as it may break unknown but required

  • dependancies. Usually called when disposing the calling object.<BR>
  • @see #registerCacheDependancy
  • @see #unregisterCacheDependancy
    */
    public void unregisterCacheDependancies()
    Unknown macro: { ChangeNotificationCenter.defaultCenter().unregisterCacheDependancies(this); }

/** Overridden to unregister all cache dependancies
*/
public void finalize() throws Throwable

Unknown macro: { ChangeNotificationCenter.defaultCenter().unregisterCacheDependancies(this); super.finalize(); }

}
}

Category:WebObjects

  • No labels