Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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

Panel
Wiki Markup
Code Block

/** 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_=_
    {
      int count = updated.count();
__ ________for_(int_i_=_0;_i_<_count;_

      for (int i = 0; i < count; i++)
________{ __________Object_object_=_
      {
        Object object = updated.objectAtIndex(i);
__________NSDictionary_userInfo_= ____________new_NSDictionary(new_Object[)_(_object,_UPDATE_),_new_Object(]_{_OBJECT,_TYPE_}); __________
        NSDictionary userInfo =
          new NSDictionary(new Object[] { object, UPDATE }, new Object[] { OBJECT, TYPE });
        NSNotificationCenter.defaultCenter().postNotification(OBJECT_CHANGED,
_
 object,
_
 userInfo);
________} ______} __ ______NSArray_invalidated_=_(NSArray)_
      }
    }

    NSArray invalidated = (NSArray) notification.userInfo().objectForKey(EOObjectStore.InvalidatedKey);
__ ______if_(invalidated_

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

      for (int i = 0; i < count; i++)
      {
        Object object = invalidated.objectAtIndex(i);
        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(i);
        
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