1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package net.wotonomy.access;
19
20 import java.util.Enumeration;
21 import java.util.List;
22 import java.util.Map;
23
24 import net.wotonomy.control.EOAndQualifier;
25 import net.wotonomy.control.EOCooperatingObjectStore;
26 import net.wotonomy.control.EOEditingContext;
27 import net.wotonomy.control.EOEnterpriseObject;
28 import net.wotonomy.control.EOFaultHandler;
29 import net.wotonomy.control.EOFaulting;
30 import net.wotonomy.control.EOFetchSpecification;
31 import net.wotonomy.control.EOGlobalID;
32 import net.wotonomy.control.EOKeyGlobalID;
33 import net.wotonomy.control.EOKeyValueCoding;
34 import net.wotonomy.control.EOKeyValueCodingSupport;
35 import net.wotonomy.control.EOKeyValueQualifier;
36 import net.wotonomy.control.EOObjectStoreCoordinator;
37 import net.wotonomy.control.EOQualifier;
38 import net.wotonomy.foundation.NSArray;
39 import net.wotonomy.foundation.NSDictionary;
40 import net.wotonomy.foundation.NSLocking;
41 import net.wotonomy.foundation.NSMutableArray;
42 import net.wotonomy.foundation.NSMutableDictionary;
43
44 /***
45 *
46 * @author ezamudio@nasoft.com
47 * @author $Author: cgruber $
48 * @version $Revision: 894 $
49 */
50 public class EODatabaseContext
51 extends EOCooperatingObjectStore implements NSLocking {
52
53 private static Class _contextClass;
54 protected EODatabase _database;
55 protected EOAdaptorContext _context;
56 protected NSMutableArray _channels = new NSMutableArray();
57 protected NSMutableArray _lockedObjects = new NSMutableArray();
58
59 protected NSMutableDictionary _simpleSnaps;
60 protected NSMutableDictionary _manySnaps;
61
62 protected EOObjectStoreCoordinator _coordinator;
63 protected EOEditingContext _currEC;
64 protected int _updateStrategy;
65
66 public EODatabaseContext(EODatabase database) {
67 super();
68 _database = database;
69 _context = _database.adaptor().createAdaptorContext();
70 }
71
72 public EOAdaptorContext adaptorContext() {
73 return _context;
74 }
75
76 public EODatabase database() {
77 return _database;
78 }
79
80 public EODatabaseChannel availableChannel() {
81 for (int i = 0; i < _channels.count(); i++) {
82 EODatabaseChannel c = (EODatabaseChannel)_channels.objectAtIndex(i);
83 if (!c.isFetchInProgress())
84 return c;
85 }
86 EODatabaseChannel c = new EODatabaseChannel(this);
87 registerChannel(c);
88 return c;
89 }
90
91 public void batchFetchRelationship(EORelationship rel, NSArray arr, EOEditingContext ec) {
92 }
93
94 public static void setContextClassToRegister(Class contextClass) {
95 _contextClass = contextClass;
96 }
97 public static Class contextClassToRegister() {
98 if (_contextClass == null)
99 _contextClass = EODatabaseContext.class;
100 return _contextClass;
101 }
102
103 public EOObjectStoreCoordinator coordinator() {
104 return _coordinator;
105 }
106
107 public void editingContextDidForgetObjectWithGlobalID(EOEditingContext ec, EOGlobalID gid) {
108 database().decrementSnapshotCountForGlobalID(gid);
109 }
110
111 public void handleDroppedConnection() {
112
113 adaptorContext().handleDroppedConnection();
114 }
115
116
117
118
119 public boolean ownsGlobalID(EOGlobalID gid) {
120 if (!(gid instanceof EOKeyGlobalID))
121 return false;
122 return (database().entityNamed(((EOKeyGlobalID)gid).entityName()) != null);
123 }
124
125
126
127
128 public boolean ownsObject(EOEnterpriseObject eo) {
129 if (eo.entityName() == null)
130 return false;
131 return (database().entityNamed(eo.entityName()) != null);
132 }
133
134
135
136
137 public boolean handlesFetchSpecification(EOFetchSpecification fspec) {
138 String ename = fspec.entityName();
139 return (database().entityNamed(ename) != null);
140 }
141
142 public boolean hasBusyChannels() {
143 return adaptorContext().hasBusyChannels();
144 }
145
146
147
148
149 public void prepareForSaveWithCoordinator(EOObjectStoreCoordinator coord, EOEditingContext ec) {
150
151 _coordinator = coord;
152 _currEC = ec;
153 }
154
155
156
157
158 public void recordChangesInEditingContext() {
159
160 }
161
162
163
164
165 public void recordUpdateForObject(EOEnterpriseObject eo, NSDictionary changes) {
166
167 }
168
169 public void recordSnapshotForGlobalID(NSDictionary snap, EOGlobalID gid) {
170 if (_simpleSnaps == null)
171 throw new IllegalArgumentException("Attempt to record a snapshot without a transaction in progress");
172 _simpleSnaps.setObjectForKey(snap, gid);
173 }
174
175 public void recordSnapshotForSourceGlobalID(NSArray gids, EOGlobalID gid, String relationName) {
176 if (_manySnaps == null)
177 throw new IllegalArgumentException("Attempt to record a snapshot without a transaction in progress");
178 NSMutableDictionary d = (NSMutableDictionary)_manySnaps.objectForKey(gid);
179 if (d == null) {
180 d = new NSMutableDictionary();
181 _manySnaps.setObjectForKey(d, gid);
182 }
183 d.setObjectForKey(gids, relationName);
184 }
185
186 public void recordSnapshots(NSDictionary snaps) {
187 if (_simpleSnaps == null)
188 throw new IllegalArgumentException("Attempt to record snapshots without a transaction in progress.");
189 _simpleSnaps.addEntriesFromDictionary(snaps);
190
191
192
193
194
195
196
197 }
198
199 public void recordToManySnapshots(NSDictionary snaps) {
200 if (_manySnaps == null)
201 throw new IllegalArgumentException("Attempt to record snapshots without a transaction in progress.");
202 Enumeration enumeration = snaps.keyEnumerator();
203 while (enumeration.hasMoreElements()) {
204 Object key = enumeration.nextElement();
205 NSDictionary d = (NSDictionary)snaps.objectForKey(key);
206 NSMutableDictionary d2 = (NSMutableDictionary)_manySnaps.objectForKey(key);
207 if (d2 == null) {
208 d2 = new NSMutableDictionary();
209 _manySnaps.setObjectForKey(d2, key);
210 }
211
212 d2.addEntriesFromDictionary(d);
213 }
214 }
215
216
217
218
219 public void performChanges() {
220
221
222 }
223
224
225
226
227 public void commitChanges() {
228 adaptorContext().commitTransaction();
229 }
230
231
232
233
234 public void rollbackChanges() {
235 adaptorContext().rollbackTransaction();
236 }
237
238
239
240
241 public NSDictionary valuesForKeys(NSArray keys, EOEnterpriseObject eo) {
242
243 return eo.valuesForKeys(keys);
244 }
245
246
247
248
249 public void lock() {
250 EOAccessLock.lock();
251 }
252
253
254
255
256 public void unlock() {
257 EOAccessLock.unlock();
258 }
259
260
261
262
263 public NSArray arrayFaultWithSourceGlobalID(
264 EOGlobalID gid, String relName, EOEditingContext ec) {
265 if (!(gid instanceof EOKeyGlobalID))
266 throw new IllegalArgumentException("an EOKeyGlobalID is needed.");
267 EOAccessArrayFaultHandler handler = new EOAccessArrayFaultHandler((EOKeyGlobalID)gid, relName, this, ec);
268 return new NSArray(handler);
269 }
270
271
272
273
274 public
275 if (!(gid instanceof EOKeyGlobalID))
276 throw new IllegalArgumentException("Cannot fault an object that doesn't have a key global ID.");
277 EOAccessFaultHandler handler = new EOAccessFaultHandler((EOKeyGlobalID)gid, this, ec);
278 EOEntity e = database().entityNamed(((EOKeyGlobalID)gid).entityName());
279 Object o = e.classDescriptionForInstances().createInstanceWithEditingContext(ec, gid);
280 EOFaultHandler.makeObjectIntoFault(o, handler);
281 return o;
282 }
283
284
285
286
287 public
288 EOEntity e = database().entityNamed(entityName);
289 EOGlobalID gid = e.globalIDForRow(row);
290 return faultForGlobalID(gid, ec);
291 }
292
293 public void forgetSnapshotForGlobalID(EOGlobalID gid) {
294 if (_simpleSnaps == null)
295 throw new IllegalArgumentException("Attempt to forget snapshot with no transaction in progress.");
296 _simpleSnaps.removeObjectForKey(gid);
297 _manySnaps.removeObjectForKey(gid);
298 }
299
300 public void forgetSnapshotsForGlobalIDs(List gids) {
301 for (int i = 0; i < gids.size(); i++) {
302 EOGlobalID g = (EOGlobalID)gids.get(i);
303 forgetSnapshotForGlobalID(g);
304 database().forgetSnapshotForGlobalID(g);
305 }
306 }
307
308
309
310
311 public void initializeObject(
312 if (gid.isTemporary())
313 return;
314 NSDictionary snap = snapshotForGlobalID(gid);
315 Object obj = ec.objectForGlobalID(gid);
316 EOEntity e = database().entityNamed(((EOKeyGlobalID)gid).entityName());
317 NSArray props = e.classProperties();
318 for (int i = 0; i < props.count(); i++) {
319 EOProperty p = (EOProperty)props.objectAtIndex(i);
320 Object val = snap.objectForKey(p.name());
321 if (p instanceof EOAttribute) {
322 if ( eo instanceof EOKeyValueCoding )
323 {
324 ((EOKeyValueCoding)eo).takeValueForKey(val, p.name());
325 }
326 else
327 {
328 EOKeyValueCodingSupport.takeValueForKey( eo, val, p.name() );
329 }
330 } else if (p instanceof EORelationship) {
331 if (((EORelationship)p).isToMany()) {
332 val = arrayFaultWithSourceGlobalID(gid, p.name(), ec);
333 } else {
334 EOEntity dest = ((EORelationship)p).destinationEntity();
335 EOKeyGlobalID kgid = (EOKeyGlobalID)dest.globalIDForRow(snap);
336 val = ec.objectForGlobalID(kgid);
337 if (val == null)
338 val = new EOAccessFaultHandler(kgid, this, ec);
339 }
340 if (val == EOKeyValueCoding.NullValue)
341 val = null;
342 if ( eo instanceof EOKeyValueCoding )
343 {
344 ((EOKeyValueCoding)eo).takeValueForKey(val, p.name());
345 }
346 else
347 {
348 EOKeyValueCodingSupport.takeValueForKey( eo, val, p.name() );
349 }
350 }
351 }
352 }
353
354
355
356
357 public void invalidateAllObjects() {
358 invalidateObjectsWithGlobalIDs(database().snapshots().allKeys());
359 }
360
361
362
363
364 public void invalidateObjectsWithGlobalIDs(List aList) {
365 forgetSnapshotsForGlobalIDs(aList);
366 }
367
368
369
370
371 public boolean isObjectLockedWithGlobalID(EOGlobalID gid, EOEditingContext ec) {
372 return isObjectLockedWithGlobalID(gid);
373 }
374
375 public boolean isObjectLockedWithGlobalID(EOGlobalID gid) {
376 return _lockedObjects.containsObject(gid);
377 }
378
379
380
381
382 public void lockObjectWithGlobalID(EOGlobalID gid, EOEditingContext ec) {
383 NSDictionary snap = snapshotForGlobalID(gid);
384 if (snap == null)
385 return;
386 if (!(gid instanceof EOKeyGlobalID))
387 return;
388 EOEntity e = database().entityNamed(((EOKeyGlobalID)gid).entityName());
389 EOQualifier q = e.qualifierForPrimaryKey(snap);
390 EOFetchSpecification fspec = new EOFetchSpecification(e.name(), q, null);
391 fspec.setLocksObjects(true);
392 NSArray arr = ec.objectsWithFetchSpecification(fspec);
393 if (arr.count() != 1)
394 throw new IllegalStateException("Cannot lock object with Global ID " + gid);
395 }
396
397
398
399
400 public NSArray objectsForSourceGlobalID(
401 EOGlobalID gid, String relationName, EOEditingContext ec) {
402 EOEnterpriseObject eo = (EOEnterpriseObject)ec.objectForGlobalID(gid);
403 if (eo == null)
404 throw new IllegalStateException("Cannot find object for global ID " + gid + " in specified editing context.");
405
406 EOEnterpriseObject source = (EOEnterpriseObject) faultForGlobalID(gid, ec);
407 if (source == null)
408 throw new IllegalStateException("There is no snapshot for source global ID " + gid);
409
410
411 NSArray value = (NSArray)source.valueForKey(relationName);
412 EOAccessArrayFaultHandler handler = null;
413 if (value != null) {
414 if (EOFaultHandler.isFault(value)) {
415 handler = new EOAccessArrayFaultHandler((EOKeyGlobalID)gid, relationName, this, ec);
416
417 } else
418 return value;
419 }
420
421
422 EOEntity entity = database().entityNamed(eo.entityName());
423 EORelationship rel = entity.relationshipNamed(relationName);
424 if (rel == null)
425 throw new IllegalStateException("Cannot find relationship named " + relationName + " in entity " + entity.name());
426
427
428 EOQualifier q = null;
429 NSArray joins = rel.joins();
430 NSMutableArray subq = new NSMutableArray(joins.count());
431 for (int i = 0; i < joins.count(); i++) {
432 EOJoin j = (EOJoin)joins.objectAtIndex(i);
433 String key = j.destinationAttribute().name();
434 Object val = eo.valueForKey(j.sourceAttribute().name());
435 subq.addObject(new EOKeyValueQualifier(key, EOQualifier.QualifierOperatorEqual, val));
436 }
437 if (subq.count() == 1) {
438 q = (EOQualifier)subq.objectAtIndex(0);
439 } else {
440 q = new EOAndQualifier(subq);
441 }
442 EOFetchSpecification fspec = new EOFetchSpecification(rel.destinationEntity().name(), q, null);
443 NSArray res = ec.objectsWithFetchSpecification(fspec, ec);
444 NSMutableArray gids = new NSMutableArray(res.count());
445 for (int i = 0; i < res.count(); i++)
446 gids.addObject(ec.globalIDForObject(res.objectAtIndex(i)));
447 recordSnapshotForSourceGlobalID(gids, gid, relationName);
448 return res;
449 }
450
451
452
453
454 public NSArray objectsWithFetchSpecification(EOFetchSpecification fspec, EOEditingContext ec) {
455 EODatabaseChannel channel = availableChannel();
456 channel.selectObjectsWithFetchSpecification(fspec, ec);
457 NSMutableArray arr = new NSMutableArray();
458 while (channel.isFetchInProgress()) {
459 Object o = channel.fetchObject();
460 if (o != null) {
461 arr.addObject(o);
462 }
463 }
464 return arr;
465 }
466
467
468
469
470 public void refaultObject(Object obj, EOGlobalID gid, EOEditingContext ec) {
471 if (!(gid instanceof EOKeyGlobalID))
472 throw new IllegalArgumentException("GlobalID must be an EOKeyGlobalID");
473 if (obj instanceof EOFaulting)
474
475 if (!EOFaultHandler.isFault(obj)) {
476 ((EOFaulting)obj).turnIntoFault(EOFaultHandler.handlerForFault(obj));
477 }
478 }
479
480
481
482
483 public void saveChangesInEditingContext(EOEditingContext ec) {
484 prepareForSaveWithCoordinator(null, ec);
485 recordChangesInEditingContext();
486 performChanges();
487 commitChanges();
488 }
489
490 public void registerChannel(EODatabaseChannel channel) {
491 if (channel.databaseContext() != this)
492 throw new IllegalArgumentException("Cannot register a channel on a context other than its own.");
493 if (_channels.containsObject(channel))
494 throw new IllegalArgumentException("Attempt to register a channel more than once.");
495 _channels.addObject(channel);
496 }
497
498 public void unregisterChannel(EODatabaseChannel channel) {
499 if (channel.databaseContext() != this)
500 throw new IllegalArgumentException("Attempt to unregister a channel from a context other than its own.");
501 _channels.removeObject(channel);
502 }
503
504 public NSArray registeredChannels() {
505 return new NSArray(_channels);
506 }
507
508 public NSDictionary snapshotForGlobalID(EOGlobalID gid) {
509 NSDictionary d = null;
510 if (_simpleSnaps != null) {
511 d = (NSDictionary)_simpleSnaps.objectForKey(gid);
512 }
513 if (d == null)
514 d = database().snapshotForGlobalID(gid);
515 return d;
516 }
517
518 public NSArray snapshotForSourceGlobalID(EOGlobalID gid, String name) {
519 NSArray a = null;
520 if (_manySnaps != null) {
521 NSDictionary d = (NSDictionary)_manySnaps.objectForKey(gid);
522 a = (NSArray)d.objectForKey(name);
523 }
524 if (a == null)
525 a = database().snapshotForSourceGlobalID(gid, name);
526 return a;
527 }
528
529 public void setUpdateStrategy(int strategy) {
530 _updateStrategy = strategy;
531 }
532
533 public int updateStrategy() {
534 return _updateStrategy;
535 }
536
537 }
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568