|
|
1.1 ! root 1: /* ! 2: DEONotificationCenter.m created by enoyau on Fri 13-Jan-1995 ! 3: ! 4: You may freely copy, distribute, and reuse the code in this example. ! 5: NeXT disclaims any warranty of any kind, expressed or implied, as to its ! 6: fitness for any particular use. ! 7: */ ! 8: ! 9: #import "DEONotificationCenter.h" ! 10: #import "DEONotification.h" ! 11: #import "DEOServerMonitor.h" ! 12: #import <foundation/NSException.h> ! 13: ! 14: #import <libc.h> ! 15: ! 16: NSString *DEOUpdate = @"DEOUpdate"; ! 17: NSString *DEOInsert = @"DEOInsert"; ! 18: NSString *DEODelete = @"DEODelete"; ! 19: ! 20: @interface DEONotificationCenter(Communication) <DEOClient> ! 21: - (void)registerAgain:(NSNotification *)note; ! 22: @end ! 23: ! 24: // Holder object to allow the server to retain the proxy to ! 25: // a DEONotificationCenter without retaining the center itself. ! 26: // See comment in initWithDatabaseChannel:entity: ! 27: @interface DEONotificationCenterHolder : NSObject <DEOClient> ! 28: { ! 29: DEONotificationCenter *center; ! 30: } ! 31: - initWithNonRetainedObject:(DEONotificationCenter *)aCenter; ! 32: @end ! 33: ! 34: ! 35: @implementation DEONotificationCenter ! 36: ! 37: static NSString *localHostname = nil; ! 38: ! 39: + initialize ! 40: { ! 41: if(!localHostname) { ! 42: char DEOHostname[1024]; ! 43: ! 44: gethostname(DEOHostname, 1024); ! 45: localHostname = [[NSString alloc] initWithCString:DEOHostname]; ! 46: } ! 47: return self; ! 48: } ! 49: ! 50: + (NSString *)localHostname ! 51: { ! 52: return localHostname; ! 53: } ! 54: ! 55: - initWithDatabaseChannel:(EODatabaseChannel *)aDatabaseChannel ! 56: entity:(EOEntity *)anEntity ! 57: { ! 58: NSArray *objs; ! 59: NSArray *keys; ! 60: ! 61: [super init]; ! 62: ! 63: // localCenter is used for notification. ! 64: localCenter = [[NSNotificationCenter alloc] init]; ! 65: entity = [anEntity retain]; ! 66: databaseChannel = [aDatabaseChannel retain]; ! 67: ! 68: // Build the unique identifier for the DEONotificationCenter ! 69: objs = [NSArray arrayWithObjects: ! 70: localHostname, ! 71: [NSString stringWithFormat:@"%d", getpid()], ! 72: [anEntity name], ! 73: [NSString stringWithFormat:@"%x", self], ! 74: 0]; ! 75: ! 76: keys = [NSArray arrayWithObjects: ! 77: @"hostname", ! 78: @"pid", ! 79: @"entity", ! 80: @"self", ! 81: 0]; ! 82: ! 83: localID = [[NSDictionary dictionaryWithObjects:objs forKeys:keys] retain]; ! 84: ! 85: // Register self for notifications from monitor ! 86: monitor = [[DEOServerMonitor serverMonitor] retain]; ! 87: [[NSNotificationCenter defaultCenter] addObserver:self ! 88: selector:@selector(registerAgain:) ! 89: notificationName:DEOServerReinitialize ! 90: object:monitor]; ! 91: ! 92: // We need to pass the server a pointer to our object, but it cannot ! 93: // retain it, or a cycle will be created. Unfortunately, the server ! 94: // MUST retain the object we pass it or the proxy on the server side ! 95: // will be released. The solution is to pass the server an "holder" ! 96: // object that it can retain (thus retaining the proxy) without ! 97: // retaining us (thus avoiding a cycle). This holder must pass on ! 98: // messages to our actual instance. ! 99: container = ! 100: [[DEONotificationCenterHolder alloc] initWithNonRetainedObject:self]; ! 101: ! 102: [self registerAgain:nil]; ! 103: ! 104: return self; ! 105: } ! 106: ! 107: - (void)dealloc ! 108: { ! 109: [localCenter release]; ! 110: [entity release]; ! 111: [databaseChannel release]; ! 112: [localID release]; ! 113: NS_DURING ! 114: [[monitor server] unregisterClient:(id <DEOClient>)container]; ! 115: NS_HANDLER ! 116: NSLog(@"Failed to send remote method unregisterClient: to server.\n"); ! 117: NS_ENDHANDLER ! 118: [container release]; ! 119: [monitor release]; ! 120: [super dealloc]; ! 121: return; ! 122: } ! 123: ! 124: - (void)addObserver:observer ! 125: selector:(SEL)selector ! 126: notificationName:(NSString *)notificationName ! 127: object:object ! 128: { ! 129: [localCenter addObserver:observer ! 130: selector:selector ! 131: notificationName:notificationName ! 132: object:object]; ! 133: } ! 134: ! 135: - (void)removeObserver:observer ! 136: notificationName:(NSString *)notificationName ! 137: object:object; ! 138: { ! 139: [localCenter removeObserver:observer ! 140: notificationName:notificationName ! 141: object:object]; ! 142: } ! 143: ! 144: - (void)removeObserver:observer ! 145: { ! 146: [localCenter removeObserver:observer]; ! 147: } ! 148: ! 149: - (void)postNotificationName:(NSString *)notificationName object:object ! 150: { ! 151: [self postNotificationName:notificationName object:object userInfo:nil]; ! 152: } ! 153: ! 154: - (void)postNotificationName:(NSString *)name ! 155: object:object ! 156: userInfo:(NSDictionary *)userInfo; ! 157: { ! 158: NSMutableDictionary *info = [NSMutableDictionary dictionary]; ! 159: NSDictionary *primaryKey = ! 160: [entity primaryKeyForRow:[[[databaseChannel databaseContext] database] snapshotForObject:object]]; ! 161: ! 162: // Encodes the enterprise object in a dictionary with the primary key. ! 163: [info setObject:primaryKey forKey:@"primaryKey"]; ! 164: [info setObject:name forKey:@"notificationName"]; ! 165: [info setObject:localID forKey:@"sender"]; ! 166: ! 167: NS_DURING ! 168: [[monitor server] dispatchInformation:info ! 169: forKey:[entity name] ! 170: userInfo:userInfo]; ! 171: NS_HANDLER ! 172: NSLog(@"Failed to send remote method dispatchInformation:forKey:userInfo: to server.\n"); ! 173: NS_ENDHANDLER ! 174: } ! 175: ! 176: @end ! 177: ! 178: @implementation DEONotificationCenter(Communication) ! 179: ! 180: - (oneway)dispatchInformation:(NSDictionary *)info ! 181: forKey:(NSString *)key ! 182: userInfo:(NSDictionary *)userInfo ! 183: { ! 184: // Decodes the enterprise object from information over the wire ! 185: id database = [[databaseChannel databaseContext] database]; ! 186: id eoObject = [database objectForPrimaryKey:[info objectForKey:@"primaryKey"] ! 187: entity:entity]; ! 188: ! 189: if(!eoObject) { ! 190: // Creates an EOFault if object does not exist yet ! 191: [EOFault objectFaultWithPrimaryKey:[info objectForKey:@"primaryKey"] ! 192: entity:entity ! 193: databaseChannel:databaseChannel ! 194: zone:NSDefaultMallocZone()]; ! 195: } ! 196: ! 197: [localCenter postNotification: ! 198: [DEONotification notificationWithName:[info objectForKey:@"notificationName"] ! 199: object:eoObject ! 200: userInfo:userInfo ! 201: isLocal:[[info objectForKey:@"sender"] isEqual:localID]]]; ! 202: ! 203: return; ! 204: } ! 205: ! 206: // Is called at init time or when the server has died. ! 207: - (void)registerAgain:(NSNotification *)note ! 208: { ! 209: NS_DURING ! 210: // Register as entity user in the distributed server ! 211: [[monitor server] registerClient:(id <DEOClient>)container forKey:[entity name]]; ! 212: NS_HANDLER ! 213: NSLog(@"Failed to send remote method registerClient:forKey: to server.\n"); ! 214: NS_ENDHANDLER ! 215: } ! 216: ! 217: @end ! 218: ! 219: @implementation DEONotificationCenterHolder ! 220: ! 221: - initWithNonRetainedObject:(DEONotificationCenter *)aCenter ! 222: { ! 223: [super init]; ! 224: center = aCenter; ! 225: return self; ! 226: } ! 227: ! 228: - (oneway)dispatchInformation:(NSDictionary *)info ! 229: forKey:(NSString *)key ! 230: userInfo:(NSDictionary *)userInfo ! 231: { ! 232: [center dispatchInformation:info ! 233: forKey:key ! 234: userInfo:userInfo]; ! 235: } ! 236: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.