|
|
Sample Programs from NeXSTEP 3.3
/*
DEONotificationCenter.m created by enoyau on Fri 13-Jan-1995
You may freely copy, distribute, and reuse the code in this example.
NeXT disclaims any warranty of any kind, expressed or implied, as to its
fitness for any particular use.
*/
#import "DEONotificationCenter.h"
#import "DEONotification.h"
#import "DEOServerMonitor.h"
#import <foundation/NSException.h>
#import <libc.h>
NSString *DEOUpdate = @"DEOUpdate";
NSString *DEOInsert = @"DEOInsert";
NSString *DEODelete = @"DEODelete";
@interface DEONotificationCenter(Communication) <DEOClient>
- (void)registerAgain:(NSNotification *)note;
@end
// Holder object to allow the server to retain the proxy to
// a DEONotificationCenter without retaining the center itself.
// See comment in initWithDatabaseChannel:entity:
@interface DEONotificationCenterHolder : NSObject <DEOClient>
{
DEONotificationCenter *center;
}
- initWithNonRetainedObject:(DEONotificationCenter *)aCenter;
@end
@implementation DEONotificationCenter
static NSString *localHostname = nil;
+ initialize
{
if(!localHostname) {
char DEOHostname[1024];
gethostname(DEOHostname, 1024);
localHostname = [[NSString alloc] initWithCString:DEOHostname];
}
return self;
}
+ (NSString *)localHostname
{
return localHostname;
}
- initWithDatabaseChannel:(EODatabaseChannel *)aDatabaseChannel
entity:(EOEntity *)anEntity
{
NSArray *objs;
NSArray *keys;
[super init];
// localCenter is used for notification.
localCenter = [[NSNotificationCenter alloc] init];
entity = [anEntity retain];
databaseChannel = [aDatabaseChannel retain];
// Build the unique identifier for the DEONotificationCenter
objs = [NSArray arrayWithObjects:
localHostname,
[NSString stringWithFormat:@"%d", getpid()],
[anEntity name],
[NSString stringWithFormat:@"%x", self],
0];
keys = [NSArray arrayWithObjects:
@"hostname",
@"pid",
@"entity",
@"self",
0];
localID = [[NSDictionary dictionaryWithObjects:objs forKeys:keys] retain];
// Register self for notifications from monitor
monitor = [[DEOServerMonitor serverMonitor] retain];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(registerAgain:)
notificationName:DEOServerReinitialize
object:monitor];
// We need to pass the server a pointer to our object, but it cannot
// retain it, or a cycle will be created. Unfortunately, the server
// MUST retain the object we pass it or the proxy on the server side
// will be released. The solution is to pass the server an "holder"
// object that it can retain (thus retaining the proxy) without
// retaining us (thus avoiding a cycle). This holder must pass on
// messages to our actual instance.
container =
[[DEONotificationCenterHolder alloc] initWithNonRetainedObject:self];
[self registerAgain:nil];
return self;
}
- (void)dealloc
{
[localCenter release];
[entity release];
[databaseChannel release];
[localID release];
NS_DURING
[[monitor server] unregisterClient:(id <DEOClient>)container];
NS_HANDLER
NSLog(@"Failed to send remote method unregisterClient: to server.\n");
NS_ENDHANDLER
[container release];
[monitor release];
[super dealloc];
return;
}
- (void)addObserver:observer
selector:(SEL)selector
notificationName:(NSString *)notificationName
object:object
{
[localCenter addObserver:observer
selector:selector
notificationName:notificationName
object:object];
}
- (void)removeObserver:observer
notificationName:(NSString *)notificationName
object:object;
{
[localCenter removeObserver:observer
notificationName:notificationName
object:object];
}
- (void)removeObserver:observer
{
[localCenter removeObserver:observer];
}
- (void)postNotificationName:(NSString *)notificationName object:object
{
[self postNotificationName:notificationName object:object userInfo:nil];
}
- (void)postNotificationName:(NSString *)name
object:object
userInfo:(NSDictionary *)userInfo;
{
NSMutableDictionary *info = [NSMutableDictionary dictionary];
NSDictionary *primaryKey =
[entity primaryKeyForRow:[[[databaseChannel databaseContext] database] snapshotForObject:object]];
// Encodes the enterprise object in a dictionary with the primary key.
[info setObject:primaryKey forKey:@"primaryKey"];
[info setObject:name forKey:@"notificationName"];
[info setObject:localID forKey:@"sender"];
NS_DURING
[[monitor server] dispatchInformation:info
forKey:[entity name]
userInfo:userInfo];
NS_HANDLER
NSLog(@"Failed to send remote method dispatchInformation:forKey:userInfo: to server.\n");
NS_ENDHANDLER
}
@end
@implementation DEONotificationCenter(Communication)
- (oneway)dispatchInformation:(NSDictionary *)info
forKey:(NSString *)key
userInfo:(NSDictionary *)userInfo
{
// Decodes the enterprise object from information over the wire
id database = [[databaseChannel databaseContext] database];
id eoObject = [database objectForPrimaryKey:[info objectForKey:@"primaryKey"]
entity:entity];
if(!eoObject) {
// Creates an EOFault if object does not exist yet
[EOFault objectFaultWithPrimaryKey:[info objectForKey:@"primaryKey"]
entity:entity
databaseChannel:databaseChannel
zone:NSDefaultMallocZone()];
}
[localCenter postNotification:
[DEONotification notificationWithName:[info objectForKey:@"notificationName"]
object:eoObject
userInfo:userInfo
isLocal:[[info objectForKey:@"sender"] isEqual:localID]]];
return;
}
// Is called at init time or when the server has died.
- (void)registerAgain:(NSNotification *)note
{
NS_DURING
// Register as entity user in the distributed server
[[monitor server] registerClient:(id <DEOClient>)container forKey:[entity name]];
NS_HANDLER
NSLog(@"Failed to send remote method registerClient:forKey: to server.\n");
NS_ENDHANDLER
}
@end
@implementation DEONotificationCenterHolder
- initWithNonRetainedObject:(DEONotificationCenter *)aCenter
{
[super init];
center = aCenter;
return self;
}
- (oneway)dispatchInformation:(NSDictionary *)info
forKey:(NSString *)key
userInfo:(NSDictionary *)userInfo
{
[center dispatchInformation:info
forKey:key
userInfo:userInfo];
}
@end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.