|
|
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.