Coverage Report - net.wotonomy.foundation.NSNotificationQueue
 
Classes in this File Line Coverage Branch Coverage Complexity
NSNotificationQueue
0% 
0% 
3.111
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2001 Intersect Software Corporation
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.foundation;
 20  
 
 21  
 import java.util.Iterator;
 22  
 import java.util.LinkedList;
 23  
 import java.util.List;
 24  
 
 25  
 /**
 26  
 * NSNotificationQueue coalesces notifications to be
 27  
 * posted to the NSNotificationCenter and can post them
 28  
 * asynchronously.  While calling postNotification on
 29  
 * the notification center does not return until all 
 30  
 * receivers have been notified, calling enqueueNotification
 31  
 * can return immediately.  Use this class when you want
 32  
 * to coalesce notifications or notify asynchronously, or
 33  
 * both, which is the typical case.
 34  
 *
 35  
 * @author michael@mpowers.net
 36  
 * @author $Author: cgruber $
 37  
 * @version $Revision: 893 $
 38  
 */
 39  0
 public class NSNotificationQueue
 40  
 {
 41  0
     private static NSNotificationQueue defaultQueue = null;
 42  
     
 43  
     /**
 44  
     * Posting style specifying that the notification should
 45  
     * be posted on the next available event loop.
 46  
     */
 47  
     public static final int PostASAP = 4;
 48  
 
 49  
     /**
 50  
     * Posting style specifying that the notification should
 51  
     * be posted on the next available idle loop.
 52  
     */
 53  
     public static final int PostWhenIdle = 8;
 54  
 
 55  
     /**
 56  
     * Posting style specifying that the notification should
 57  
     * be posted immediately.  The enqueue method will not
 58  
     * return until all receivers have been notified.
 59  
     */
 60  
     public static final int PostNow = 16;
 61  
     
 62  
     /**
 63  
     * Used to indicate that this notification should not
 64  
     * be coalesced with other notifications. 
 65  
     * Ignored if combined with other coalesce flags.
 66  
     */
 67  
     public static final int NotificationNoCoalescing = 0;
 68  
 
 69  
     /**
 70  
     * Used to indicate that this notification should 
 71  
     * be coalesced with other notifications with the
 72  
     * same name.  
 73  
     * May be combined with NotificationCoalescingOnSender.
 74  
     */
 75  
     public static final int NotificationCoalescingOnName = 1;
 76  
 
 77  
     /**
 78  
     * Used to indicate that this notification should 
 79  
     * be coalesced with other notifications with the
 80  
     * same object argument (which is typically the sender).
 81  
     * May be combined with NotificationCoalescingOnName.
 82  
     */
 83  
     public static final int NotificationCoalescingOnSender = 2;
 84  
     
 85  
     /**
 86  
     * The ASAP queue, which should probably use a LinkedList.
 87  
     */
 88  
     private List queue;
 89  
     
 90  
     /**
 91  
     * The idle queue, which should probably use a LinkedList.
 92  
     */
 93  
     private List idleQueue;
 94  
     
 95  
     /**
 96  
     * The notification center we will be using.
 97  
     */
 98  0
     private NSNotificationCenter center;
 99  
     
 100  
     /**
 101  
     * Our private ASAP notifier.
 102  
     */
 103  
     private Notifier notifier;
 104  
     
 105  
     /**
 106  
     * Our private idle notifier.
 107  
     */
 108  
     private Notifier idleNotifier;
 109  
     
 110  
     /**
 111  
     * Default constructor creates a new notification queue
 112  
     * that uses the default notification center.
 113  
     */
 114  
     public NSNotificationQueue()
 115  
     {
 116  0
         this( NSNotificationCenter.defaultCenter() );
 117  0
     }
 118  
     
 119  
     /**
 120  
     * Creates a new notification queue that uses the 
 121  
     * specified notification center.
 122  
     */
 123  0
     public NSNotificationQueue( 
 124  
         NSNotificationCenter aCenter )
 125  0
     {
 126  0
         queue = new LinkedList();
 127  0
         idleQueue = new LinkedList();
 128  0
         center = aCenter;
 129  0
         notifier = new Notifier( this, queue );
 130  0
         idleNotifier = new Notifier( this, idleQueue );
 131  0
     }
 132  
     
 133  
     /**
 134  
     * Returns the system default queue, creating one
 135  
     * if it has not yet been created.  The system default
 136  
     * queue uses the system default notification center.
 137  
     */
 138  
     static public NSNotificationQueue defaultQueue()
 139  
     {
 140  0
         if ( defaultQueue == null )
 141  
         {
 142  0
             defaultQueue = new NSNotificationQueue();   
 143  
         }
 144  0
         return defaultQueue;
 145  
     }
 146  
         
 147  
     /**
 148  
     * Removes notifications from the queue that match
 149  
     * the specified notification, considering the 
 150  
     * specified coalesce mask.
 151  
     */ 
 152  
     public void dequeueMatchingNotifications( 
 153  
         NSNotification aNotification, 
 154  
         int aCoalesceMask)
 155  
     {
 156  0
         if ( aCoalesceMask == NotificationNoCoalescing ) return;
 157  0
         dequeueFromQueue( aNotification, aCoalesceMask, queue );
 158  0
         dequeueFromQueue( aNotification, aCoalesceMask, idleQueue );
 159  0
     }
 160  
     
 161  
     private void dequeueFromQueue( 
 162  
         NSNotification aNotification, 
 163  
         int aCoalesceMask, 
 164  
         List aQueue )
 165  
     {
 166  0
         synchronized ( aQueue )
 167  
         {
 168  
             int flag;
 169  
             NSNotification notification;
 170  0
             Object name = aNotification.name();
 171  0
             Object object = aNotification.object();
 172  0
             Iterator it = aQueue.iterator();
 173  0
             while ( it.hasNext() )
 174  
             {
 175  0
                 flag = 0;
 176  0
                 notification = (NSNotification) it.next();
 177  
                 // if NotificationCoalescingOnName
 178  0
                 if ( ( aCoalesceMask == 1 ) || ( aCoalesceMask == 3 ) )
 179  
                 {
 180  0
                     if ( name == null )
 181  
                     {
 182  0
                         if ( notification.name() != null )
 183  
                         {
 184  0
                             flag += NotificationCoalescingOnName;
 185  0
                         }
 186  
                     }
 187  
                     else
 188  
                     {
 189  
                         // compare by value
 190  0
                         if ( name.equals( notification.name() ) )
 191  
                         {
 192  0
                             flag += NotificationCoalescingOnName;
 193  
                         }
 194  
                     }
 195  
                 }
 196  
                 // if NotificationCoalescingOnSender
 197  0
                 if ( aCoalesceMask >= 2 )
 198  
                 {
 199  
                     // compare by reference
 200  0
                     if ( object == notification.object() )
 201  
                     {
 202  0
                         flag += NotificationCoalescingOnSender;
 203  
                     }
 204  
                 }
 205  
                 
 206  0
                 if ( flag == aCoalesceMask )
 207  
                 {
 208  0
                     it.remove();   
 209  0
                 }
 210  
             }
 211  0
         }
 212  0
     }
 213  
 
 214  
     /**
 215  
     * Adds the notification to the queue to be run at
 216  
     * the time specified by the posting style.  The
 217  
     * notification will be coalesced with other notifications
 218  
     * that match the same name and object (sender) argument.
 219  
     */ 
 220  
     public void enqueueNotification( 
 221  
         NSNotification aNotification, 
 222  
         int aPostingStyle)
 223  
     {
 224  0
         enqueueNotificationWithCoalesceMaskForModes(
 225  0
             aNotification, aPostingStyle,
 226  0
             NotificationCoalescingOnName + NotificationCoalescingOnSender,
 227  0
             null );
 228  0
     }
 229  
 
 230  
     /**
 231  
     * Adds the notification to the queue to be run at
 232  
     * the time specified by the posting style and coelesced
 233  
     * as the specified mask indicates.
 234  
     * aModeList is currently ignored and may be null.
 235  
     */ 
 236  
     public void enqueueNotificationWithCoalesceMaskForModes( 
 237  
         NSNotification aNotification, 
 238  
         int aPostingStyle, 
 239  
         int aCoalesceMask, 
 240  
         List aModeList)
 241  
     {
 242  0
         dequeueMatchingNotifications( aNotification, aCoalesceMask );
 243  
         
 244  0
         if ( aPostingStyle == PostNow )
 245  
         {
 246  0
             center.postNotification( aNotification );
 247  0
             return;
 248  
         }
 249  
         
 250  0
         if ( aPostingStyle == PostASAP )
 251  
         {
 252  0
             synchronized ( queue )
 253  
             {
 254  0
                 queue.add( aNotification );
 255  0
                 if ( ! notifier.willRun )
 256  
                 {
 257  
                     // asap runs at the very first run loop ordering, plus one just in case
 258  0
                     NSRunLoop.invokeLaterWithOrder( notifier, 1 );
 259  0
                     notifier.willRun = true;
 260  
                 }
 261  0
             }
 262  0
             return;
 263  
         }
 264  
         
 265  0
         if ( aPostingStyle == PostWhenIdle )
 266  
         {
 267  0
             synchronized ( idleQueue )
 268  
             {
 269  0
                 idleQueue.add( aNotification );
 270  0
                 if ( ! idleNotifier.willRun )
 271  
                 {
 272  
                     // when idle runs at the very last run loop ordering, minus one just in case
 273  0
                     NSRunLoop.invokeLaterWithOrder( idleNotifier, Integer.MAX_VALUE - 1 );
 274  0
                     idleNotifier.willRun = true;
 275  
                 }
 276  0
             }
 277  0
             return;
 278  
         }
 279  
         
 280  0
     }
 281  
     
 282  
     private class Notifier implements Runnable
 283  
     {
 284  
         public boolean willRun;
 285  
         
 286  
         NSNotificationQueue parent;
 287  
         List queue;
 288  
         
 289  0
         public Notifier(
 290  
             NSNotificationQueue aParent, List aQueue )
 291  0
         {
 292  0
             willRun = false;
 293  0
             parent = aParent;
 294  0
             queue = aQueue;
 295  0
         }
 296  
         
 297  
         public void run()
 298  
         {
 299  0
             Iterator it = new LinkedList( queue ).iterator();
 300  0
             synchronized ( queue )
 301  
             {
 302  0
                 queue.clear();
 303  0
             }
 304  0
             willRun = false;
 305  
 
 306  
             // queue must already be cleared and willRun reset
 307  
             //   because this loop might queue more notifications                
 308  0
             while ( it.hasNext() )
 309  
             {
 310  0
                 parent.center.postNotification( 
 311  0
                     (NSNotification) it.next() );
 312  0
             }
 313  0
         }
 314  
     }
 315  
 
 316  
 }
 317  
 
 318  
 /*
 319  
  * $Log$
 320  
  * Revision 1.2  2006/02/16 13:15:00  cgruber
 321  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 322  
  *
 323  
  * Revision 1.6  2003/08/11 18:18:08  chochos
 324  
  * improved encoding of strings, removed warnings
 325  
  *
 326  
  * Revision 1.5  2003/08/06 23:07:52  chochos
 327  
  * general code cleanup (mostly, removing unused imports)
 328  
  *
 329  
  * Revision 1.4  2001/11/01 15:49:26  mpowers
 330  
  * With NSRunLoop, we can now correctly implement PostASAP and PostWhenIdle.
 331  
  *
 332  
  * Revision 1.3  2001/06/25 14:47:24  mpowers
 333  
  * Fixed serious error where some notifications were not being posted at all.
 334  
  * A simple change to Notifier class fixed the problem.  Thanks to glista.
 335  
  *
 336  
  * Revision 1.2  2001/02/26 15:53:22  mpowers
 337  
  * Fine-tuning notification firing.
 338  
  * Child display groups now update properly after parent save or invalidate.
 339  
  *
 340  
  * Revision 1.1  2001/02/24 17:03:22  mpowers
 341  
  * Implemented the notification queue, and changed editing context to use it.
 342  
  *
 343  
  *
 344  
  */
 345