Programming__WebObjects-EOF-Using EOF-Delegates and Notifications
Version 4.1 by smmccraw on 2007/07/08 09:44
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[] { 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(] { NSNotification.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(] { 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(] { OBJECT, TYPE });
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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
{
/ 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)
{
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)
{
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()
{
ChangeNotificationCenter.defaultCenter().unregisterCacheDependancies(this);
}
/ Overridden to unregister all cache dependancies
*/
public void finalize() throws Throwable
{
ChangeNotificationCenter.defaultCenter().unregisterCacheDependancies(this);
super.finalize();
}
}
}
Category:WebObjects