1 package net.wotonomy.test;
2
3 import java.util.Iterator;
4 import java.util.LinkedList;
5 import java.util.List;
6 import java.util.Map;
7
8 import net.wotonomy.control.ArrayFault;
9 import net.wotonomy.control.EOEditingContext;
10 import net.wotonomy.control.EOFetchSpecification;
11 import net.wotonomy.control.EOGlobalID;
12 import net.wotonomy.control.EOObjectStore;
13 import net.wotonomy.control.EOObserverCenter;
14 import net.wotonomy.control.KeyValueCodingUtilities;
15 import net.wotonomy.datastore.DataKey;
16 import net.wotonomy.datastore.DataSoup;
17 import net.wotonomy.datastore.DataView;
18 import net.wotonomy.datastore.XMLFileSoup;
19 import net.wotonomy.foundation.NSArray;
20 import net.wotonomy.foundation.NSMutableArray;
21 import net.wotonomy.foundation.NSMutableDictionary;
22 import net.wotonomy.foundation.NSNotification;
23 import net.wotonomy.foundation.NSNotificationQueue;
24 import net.wotonomy.foundation.internal.WotonomyException;
25
26 /***
27 * An object store that wraps a datastore for vending test objects.
28 */
29 public class DataObjectStore extends EOObjectStore
30 {
31 DataSoup soup;
32
33 /***
34 * Constructor specifies path to datastore.
35 */
36 public DataObjectStore( String aPath )
37 {
38 soup = new XMLFileSoup( aPath );
39 }
40
41 /***
42 * This implementation returns an appropriately configured array fault.
43 */
44 public NSArray arrayFaultWithSourceGlobalID (
45 EOGlobalID aGlobalID,
46 String aRelationship,
47 EOEditingContext aContext )
48 {
49 return new ArrayFault(
50 aGlobalID, aRelationship, aContext );
51 }
52
53 /***
54 * This implementation returns the actual
55 * object for the specified id.
56 */
57 public Object faultForGlobalID (
58 EOGlobalID aGlobalID,
59 EOEditingContext aContext )
60 {
61 System.out.println( "DataObjectStore.faultForGlobalID: * reading object * : " + aGlobalID );
62 Object result = soup.getObjectByKey(
63 ((DataKeyID)aGlobalID).getKey() );
64
65 if ( result == null ) return null;
66
67
68 convertRelationKeysToObjects( aContext, result, aGlobalID );
69
70
71 aContext.recordObject( result, aGlobalID );
72 return result;
73 }
74
75 /***
76 * Returns a fault representing an object of
77 * the specified entity type with values from
78 * the specified dictionary. The fault should
79 * belong to the specified editing context.
80 */
81 public Object faultForRawRow (
82 Map aDictionary,
83 String anEntityName,
84 EOEditingContext aContext )
85 {
86
87 throw new WotonomyException(
88 "Faults are not yet supported." );
89 }
90
91 /***
92 * Given a newly instantiated object, this method
93 * initializes its properties to values appropriate
94 * for the specified id. The object should belong
95 * to the specified editing context.
96 * This method is called to populate faults.
97 */
98 public void initializeObject(Object anObject, EOGlobalID aGlobalID,
99 EOEditingContext aContext) {
100 if (aGlobalID.isTemporary()) {
101
102
103
104
105 return;
106 }
107
108 System.out.println("DataObjectStore.initializeObject: * reading object * : "
109 + aGlobalID);
110
111 Object original = soup.getObjectByKey(((DataKeyID) aGlobalID).getKey());
112
113
114 convertRelationKeysToObjects(aContext, original, aGlobalID);
115
116 EOObserverCenter.notifyObserversObjectWillChange(anObject);
117 KeyValueCodingUtilities.copy(aContext, original, aContext, anObject);
118 }
119
120 /***
121 * Remove all values from all objects in memory, turning them into faults,
122 * and posts a notification that all objects have been invalidated.
123 */
124 public void invalidateAllObjects ()
125 {
126
127
128 NSNotificationQueue.defaultQueue().enqueueNotification(
129 new NSNotification(
130 InvalidatedAllObjectsInStoreNotification, this ),
131 NSNotificationQueue.PostNow );
132 }
133
134 /***
135 * Removes values with the specified ids from memory,
136 * turning them into faults, and posts a notification
137 * that those objects have been invalidated.
138 */
139 public void invalidateObjectsWithGlobalIDs (
140 List aList )
141 {
142
143 }
144
145 /***
146 * Returns false because locking is not permitted.
147 */
148 public boolean isObjectLockedWithGlobalID (
149 EOGlobalID aGlobalID,
150 EOEditingContext aContext )
151 {
152 return false;
153 }
154
155 /***
156 * Does nothing because locking is not permitted.
157 */
158 public void lockObjectWithGlobalID (
159 EOGlobalID aGlobalID,
160 EOEditingContext aContext )
161 {
162
163 }
164
165 /***
166 * Returns a List of objects associated with the object
167 * with the specified id for the specified property
168 * relationship. This method may not return an array fault
169 * because array faults call this method to fetch on demand.
170 * All objects must be registered the specified editing context.
171 * The specified relationship key must produce a result of
172 * type Collection for the source object or an exception is thrown.
173 */
174 public NSArray objectsForSourceGlobalID (
175 EOGlobalID aGlobalID,
176 String aRelationship,
177 EOEditingContext aContext )
178 {
179 System.out.println( "DataObjectStore.objectsForSourceGlobalID: * reading object * : " + aGlobalID );
180 Object object = soup.getObjectByKey(((DataKeyID)aGlobalID).getKey() );
181
182 if ( object == null ) return null;
183
184 Object fault;
185 EOGlobalID id;
186 NSMutableArray result = new NSMutableArray();
187
188 Iterator it = ((TestObject)object).getChildList().iterator();
189 while ( it.hasNext() )
190 {
191 id = new DataKeyID((DataKey)it.next());
192 fault = aContext.faultForGlobalID( id, aContext );
193
194
195 if ( fault != null )
196 {
197
198 result.add( fault );
199
200
201 ((TestObject)fault).setParent( (TestObject) object );
202 }
203 else
204 {
205
206 System.out.println( "objectsForSourceGlobalID: could not find fault for id: " + id );
207 }
208 }
209 return result;
210
211 }
212
213 /***
214 * Returns a List of objects the meet the criteria of
215 * the supplied specification.
216 * Each object is registered with the specified editing context.
217 * If any object is already registered in the specified context,
218 * it is not refetched and that object should be used in the array.
219 */
220 public NSArray objectsWithFetchSpecification (
221 EOFetchSpecification aFetchSpec,
222 EOEditingContext aContext )
223 {
224
225
226 DataView view = soup.queryObjects( null, null );
227 System.out.println( "DataObjectStore: ** querying all objects **" );
228
229
230
231
232
233
234
235 NSMutableArray result = new NSMutableArray();
236 DataKeyID id;
237 Iterator it = view.iterator();
238 while ( it.hasNext() )
239 {
240 id = new DataKeyID( view.getKeyForObject( it.next() ) );
241 result.addObject( aContext.faultForGlobalID( id, aContext ) );
242 }
243 return result;
244 }
245
246 /***
247 * Removes all values from the specified object,
248 * converting it into a fault for the specified id.
249 * New or deleted objects should not be refaulted.
250 */
251 public void refaultObject (
252 Object anObject,
253 EOGlobalID aGlobalID,
254 EOEditingContext aContext )
255 {
256
257
258 initializeObject( anObject, aGlobalID, aContext );
259 }
260
261 /***
262 * Writes all changes in the specified editing context
263 * to the respository.
264 */
265 public void saveChangesInEditingContext (
266 EOEditingContext aContext )
267 {
268 Object o;
269 DataKeyID id;
270 Iterator it;
271
272
273 it = aContext.deletedObjects().iterator();
274 while ( it.hasNext() )
275 {
276 o = it.next();
277 id = (DataKeyID) aContext.globalIDForObject( o );
278 System.out.println( "DataObjectStore: * deleting object * : " + id );
279 soup.removeObject( id.getKey() );
280
281 aContext.forgetObject( o );
282 }
283
284
285 NSMutableDictionary userInfo = null;
286 it = aContext.insertedObjects().iterator();
287 while ( it.hasNext() )
288 {
289 o = it.next();
290 EOGlobalID oldId = aContext.globalIDForObject( o );
291
292
293 convertRelationObjectsToKeys( aContext, (TestObject) o );
294 id = new DataKeyID( soup.addObject( o ) );
295 convertRelationKeysToObjects( aContext, (TestObject) o, oldId );
296
297
298 System.out.println( "DataObjectStore: * adding object * : " + id );
299
300
301 if ( userInfo == null )
302 {
303 userInfo = new NSMutableDictionary();
304 }
305 userInfo.setObjectForKey( id, oldId );
306 }
307
308
309 if ( userInfo != null )
310 {
311 NSNotificationQueue.defaultQueue().enqueueNotification(
312 new NSNotification(
313 EOGlobalID.GlobalIDChangedNotification, null, userInfo ),
314 NSNotificationQueue.PostNow );
315 }
316
317 System.out.println( aContext.updatedObjects() );
318
319
320 it = aContext.updatedObjects().iterator();
321 while ( it.hasNext() )
322 {
323
324
325 o = it.next();
326 id = (DataKeyID) aContext.globalIDForObject( o );
327 System.out.println( "DataObjectStore: * updating object * : " + id );
328
329
330 convertRelationObjectsToKeys( aContext, (TestObject) o );
331 soup.updateObject( id.getKey(), o );
332 convertRelationKeysToObjects( aContext, (TestObject) o, id );
333
334
335 }
336 }
337
338 private void convertRelationKeysToObjects(
339 EOEditingContext aContext, Object anObject, EOGlobalID aGlobalID )
340 {
341
342 ((TestObject)anObject).editingContext = aContext;
343
344 Object fault;
345 DataKeyID id;
346 List result = new LinkedList();
347 Iterator it = ((TestObject)anObject).getChildList().iterator();
348 while ( it.hasNext() )
349 {
350 id = new DataKeyID((DataKey)it.next());
351 fault = aContext.faultForGlobalID( id, aContext );
352
353
354 if ( fault != null )
355 {
356
357 result.add( fault );
358
359
360 ((TestObject)fault).setParent( (TestObject) anObject );
361 }
362 else
363 {
364
365 System.out.println( "convertRelationObjectsToKeys: could not find fault for id: " + id );
366 }
367 }
368
369
370
371 ((TestObject)anObject).setChildList( result );
372
373
374 ((TestObject)anObject).setChildList(
375 aContext.arrayFaultWithSourceGlobalID(
376 aGlobalID, "childList", aContext ) );
377
378 }
379
380 private void convertRelationObjectsToKeys(
381 EOEditingContext aContext, Object anObject )
382 {
383 Object o;
384 DataKeyID id;
385 List result = new LinkedList();
386 Iterator it = ((TestObject)anObject).getChildList().iterator();
387
388 ((TestObject)anObject).setParent( null );
389 ((TestObject)anObject).editingContext = null;
390 while ( it.hasNext() )
391 {
392 o = it.next();
393
394 id = (DataKeyID)aContext.globalIDForObject( o );
395
396
397 if ( id != null )
398 {
399 result.add( id.getKey() );
400 }
401 else
402 {
403
404 System.out.println( "convertRelationObjectsToKeys: could not find id for object: " + o );
405 System.out.println( aContext.registeredObjects() );
406 }
407
408 }
409 ((TestObject)anObject).setChildList( result );
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482 }
483