/Volumes/Plantain/MyDocuments/Projects/MacTrek/MacTrek/Luky/Comm/LLNotificationCenter.m

00001 //
00002 //  LLNotificationCenter.m
00003 //  MacTrek
00004 //
00005 //  Created by Aqua on 27/04/2006.
00006 //  Copyright 2006 __MyCompanyName__. All rights reserved.
00007 //
00008 
00009 #import "LLNotificationCenter.h"
00010 
00011 
00012 @implementation LLNotificationCenter
00013 
00014 LLNotificationCenter *defaultCenter;
00015 NSLock *synchronizeAccess;
00016 NSMutableDictionary *senders;
00017 LLDOReceiver *receiver;
00018 NSString *mainThreadID;
00019 bool sendEvents = YES;
00020 
00021 - (id) init {
00022     self = [super init];
00023     if (self != nil) {
00024         listeners = [[NSMutableArray alloc] init];
00025         useLocks = NO; // default off
00026         synchronizeAccess = [[NSLock alloc] init];
00027         timeOut = 2; // default wait 2 seconds
00028         
00029         // this is the main run loop so set up the DO
00030         receiver = [[LLDOReceiver alloc] init];
00031         // this will be called from a thread when an event was posted
00032         [receiver setTarget:self withSelector:@selector(remotelyPostedEvent:)];
00033         // this will store the senders
00034         senders = [[NSMutableDictionary alloc] init];
00035         // and this is the id of the main thread
00036         mainThreadID = [NSString stringWithFormat:@"%d", [NSThread currentThread]];
00037         [mainThreadID retain];
00038     }
00039     return self;
00040 }
00041 
00042 + (LLNotificationCenter*) defaultCenter {
00043     if (defaultCenter == nil) {
00044         defaultCenter = [[LLNotificationCenter alloc] init];
00045     }
00046     return defaultCenter;
00047 }
00048 
00049 - (void)addObserver:(id)notificationObserver            // cannot be nil
00050            selector:(SEL)notificationSelector           // cannot be nil
00051                name:(NSString *)notificationName {
00052        
00053     [self addObserver:notificationObserver 
00054              selector:notificationSelector 
00055                  name:notificationName 
00056                object:nil 
00057              useLocks:NO
00058        useMainRunLoop:NO];
00059 }
00060 
00061 - (void)addObserver:(id)notificationObserver            // cannot be nil
00062            selector:(SEL)notificationSelector           // cannot be nil
00063                name:(NSString *)notificationName        // nil means all
00064              object:(NSString *)notificationSender {    // nil means of all
00065     
00066     [self addObserver:notificationObserver 
00067              selector:notificationSelector 
00068                  name:notificationName 
00069                object:notificationSender 
00070              useLocks:NO
00071        useMainRunLoop:NO];
00072 }
00073 
00074 - (void)addObserver:(id)notificationObserver            // cannot be nil
00075            selector:(SEL)notificationSelector           // cannot be nil
00076                name:(NSString *)notificationName        // nil means all
00077              object:(NSString *)notificationSender      // nil means of all
00078            useLocks:(bool)protect {
00079     [self addObserver:notificationObserver 
00080              selector:notificationSelector 
00081                  name:notificationName 
00082                object:notificationSender 
00083              useLocks:protect
00084        useMainRunLoop:NO];
00085 }
00086 
00087 - (void)addObserver:(id)notificationObserver            // cannot be nil
00088            selector:(SEL)notificationSelector           // cannot be nil
00089                name:(NSString *)notificationName        // nil means all
00090              object:(NSString *)notificationSender      // nil means of all
00091            useLocks:(bool)protect 
00092   useMainRunLoop:(bool)useMainLoop {                                                     
00093     
00094     if (notificationObserver == nil) {
00095         NSLog(@"LLNotificationCenter.addObserver notificationObserver cannot be nil");
00096         return;
00097     } 
00098     if (notificationSelector == nil) {
00099         NSLog(@"LLNotificationCenter.addObserver notificationSelector cannot be nil");
00100         return;
00101     }
00102     // little optimalization, when using the mainloop it is thread safe anyway
00103     if (useMainLoop) {
00104         protect = NO; // no need for locks AND DO
00105     }
00106     [listeners addObject:[[LLNotificationCenterEntry alloc] initWithNotificationName:notificationName
00107                                                                               source:notificationSender 
00108                                                                               target:notificationObserver
00109                                                                             selector:notificationSelector
00110                                                                             useLocks:protect
00111                                                                          useMainLoop:useMainLoop]];
00112     return;    
00113 }    
00114 
00115 - (void) remotelyPostedEvent:(LLNotificationCenterEntry *)listener {
00116     
00117     //NSLog(@"LLNotificationCenter.remotelyPostedEvent %@", [listener name]); 
00118     
00119     // get the parameters passed over the DO
00120     id target = [listener target];
00121     SEL selector = [listener selector];
00122     id userInfo = [listener userData];
00123     
00124     // invoke the selector (we are now in the main loop)
00125     [target performSelector:selector withObject:userInfo];
00126 }
00127 
00128 - (LLDOSender *) getSenderForMyThread {
00129     // create a new one for every event.... $$
00130     NSString *threadID = [NSString stringWithFormat:@"%d", [NSThread currentThread]]; 
00131     
00132     // for the main thread do nothing
00133     if ([threadID isEqualToString: mainThreadID]) {
00134         return nil;
00135     }
00136     
00137     LLDOSender *sender = [senders objectForKey:threadID];
00138     if (sender == nil) {
00139         // new thread? create a seperate sender
00140         NSLog(@"LLNotificationCenter.getSenderForMyThread creating sender for thread %d", threadID);
00141         sender = [[LLDOSender alloc] init];
00142         [senders setObject:sender forKey:threadID];
00143     }
00144     return sender;
00145 }
00146 
00147 - (void) setEnable:(bool)enable {
00148     sendEvents = enable;
00149 }
00150 
00151 - (void) postNotificationName:(NSString *)name object:(id) sender userInfo:(id)userInfo {
00152     
00153     if (!sendEvents) {
00154         return;
00155     }
00156     
00157     // debug print, very helpfull, but takes load
00158     //NSLog(@"LLNotificationCenter.postNotificationName %@", name);
00159     
00160     for (int i = 0; i < [listeners count]; i++) {
00161         LLNotificationCenterEntry *listener = [listeners objectAtIndex:i];
00162         
00163         // filter on source first
00164         if (([listener source] == sender) || ([listener source] == nil)) { // nil means all source
00165             if (([[listener name] isEqualToString: name]) || ([listener name] == nil)) { // nil means all messages
00166                 id target = [listener target];
00167                 SEL selector = [listener selector];                    
00168                 // check for the use of locks (protect multithreading)
00169                 if (useLocks || [listener useLocks]) {
00170                     // if we use locks, use a timeout
00171                     if ([synchronizeAccess lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:timeOut]]) {
00172                         //[synchronizeAccess lock]; // lock was obtained, don't lock twice
00173                         [target performSelector:selector withObject:userInfo];       // invoke 
00174                         [synchronizeAccess unlock]; // but unlock
00175                     } else {
00176                         NSLog(@"LLNotificationCenter.postNotificationName waited %d seconds for lock, discarding event");
00177                         return; // no lock obtained, so no need to unlock
00178                     }
00179                 } else {
00180                     if ([listener useMainLoop]) {
00181                         // this event could have occured in a seperate thread as the main thread
00182                         // so we need to perform the execution over the DO
00183                         
00184                         // store the data
00185                         [listener setUserData:userInfo]; 
00186                         // get the sender
00187                         LLDOSender *sender = [self getSenderForMyThread];
00188                         // send the notification over the do
00189                         if (sender != nil) {
00190                             [sender invokeRemoteObjectWithUserData:listener];
00191                         } else { // try something
00192                             [target performSelector:selector withObject:userInfo];       // normal invoke
00193                         }                        
00194                         
00195                     } else {
00196                         [target performSelector:selector withObject:userInfo];       // normal invoke 
00197                     }
00198                      
00199                 }
00200             }
00201         } 
00202     }
00203 }
00204 
00205 - (void)removeObserver:(id)notificationObserver        
00206                   name:(NSString *)notificationName {
00207     NSLog(@"LLNotificationCenter.removeObserver %@", notificationObserver);
00208     
00209     NSMutableArray *toBeRemovedListners = [[NSMutableArray alloc] init];    
00210     
00211     // see which ones are
00212     for (int i = 0; i < [listeners count]; i++) {
00213         LLNotificationCenterEntry *listener = [listeners objectAtIndex:i];        
00214         
00215         if ([listener target] == notificationObserver) {
00216             // found the right lister target
00217             if ([[listener name] isEqualToString:notificationName] ||
00218                 (notificationName == nil)) {
00219                 // notification name is ok
00220                 [toBeRemovedListners addObject:listener];              
00221             }
00222         }
00223     }
00224     
00225     // remove
00226     [listeners removeObjectsInArray:toBeRemovedListners];
00227     NSLog(@"LLNotificationCenter.removeObserver removed %d occurences", [toBeRemovedListners count]);
00228     [toBeRemovedListners release];
00229    
00230 }
00231 
00232 - (void) postNotificationName:(NSString *)name {
00233     [self postNotificationName:name object:self userInfo:nil];
00234 }
00235 
00236 - (void) postNotificationName:(NSString *)name userInfo:(id)userInfo {
00237     [self postNotificationName:name object:self userInfo:userInfo];
00238 }
00239 
00240 - (bool) useLocks {
00241     return useLocks;
00242 }
00243 
00244 - (void) setUseLocks:(bool)protect {
00245     useLocks = protect;
00246 }
00247 
00248 - (int)  timeOut {
00249     return timeOut;
00250 }
00251 
00252 - (void) setTimeOut:(int)interval {
00253     timeOut = interval;
00254 }
00255 
00256 @end

Generated on Fri Jul 28 19:15:22 2006 for MacTrek by  doxygen 1.4.7