View Javadoc

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          //! transpose keys to objects
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          //TODO: faults are not yet supported
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 			// TODO: this should never happen, but it does now until we get
102 			// faults.
103 
104 			// do not reinit an uncommitted object
105 			return;
106 		}
107 
108 		System.out.println("DataObjectStore.initializeObject: * reading object * : "
109 						+ aGlobalID);
110 		//net.wotonomy.ui.swing.util.StackTraceInspector.printShortStackTrace();
111 		Object original = soup.getObjectByKey(((DataKeyID) aGlobalID).getKey());
112 
113 		// ! transpose keys to objects
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         // does nothing except post notification
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         // does nothing
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         // does nothing   
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             // if key still exists
195             if ( fault != null ) 
196             {
197 //System.out.println( "objectsForSourceGlobalID: found: " + id + " : " + fault ); 
198                 result.add( fault );
199 
200 // for testing purposes                
201 ((TestObject)fault).setParent( (TestObject) object );
202             }
203             else // key no longer exists
204             {
205                 // do not add
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         //TODO: fetch specs are not yet supported
225         
226         DataView view = soup.queryObjects( null, null );
227 System.out.println( "DataObjectStore: ** querying all objects **" );
228 
229         // we've changed this implementation so that 
230         // it simply calls faultForGlobalID on the context
231         // for each id in the result set.
232         // this way, child contexts inherit parent's state.
233         // however, it's unclear if the specification allows
234         // faults in the resulting array.  sounds like it doesn't.
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         //TODO: faults are not yet supported
257         // just re-initialize the object
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         // process deletes
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             // remove object from editing context
281             aContext.forgetObject( o );
282         }
283         
284         // process inserts
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             //! transpose objects to keys
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             // save mapping of old id to new id
301             if ( userInfo == null ) 
302             {
303                 userInfo = new NSMutableDictionary();   
304             }
305             userInfo.setObjectForKey( id, oldId );
306         }
307         
308         // broadcast inserted objects' new ids if necessary
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         // process updates
320         it = aContext.updatedObjects().iterator();
321         while ( it.hasNext() )
322         {
323 //if ( true ) // test validation error message handling
324 //throw new RuntimeException( "Update not allowed." );            
325             o = it.next();
326             id = (DataKeyID) aContext.globalIDForObject( o );
327 System.out.println( "DataObjectStore: * updating object * : " + id );
328 
329             //! transpose objects to keys
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     { // System.out.println( "convertRelationKeysToObjects: " + anObject );        
341 // set editing context for testing
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             // if key still exists
354             if ( fault != null ) 
355             {
356 //System.out.println( "convertRelationObjectsToKeys: found: " + id + " : " + fault ); 
357                 result.add( fault );
358 
359 // for testing purposes                
360 ((TestObject)fault).setParent( (TestObject) anObject );
361             }
362             else // key no longer exists
363             {
364                 // do not add
365 System.out.println( "convertRelationObjectsToKeys: could not find fault for id: " + id ); 
366             }
367         }
368         // this tests loading manually on-demand
369 //        ((TestObject)anObject).setChildList( null );
370         // this tests loading immediately
371         ((TestObject)anObject).setChildList( result );
372         // this tests loading array faults
373 //        ((TestObject)result).setChildList( null );
374         ((TestObject)anObject).setChildList( 
375             aContext.arrayFaultWithSourceGlobalID( 
376                 aGlobalID, "childList", aContext ) );
377 
378     }
379     
380     private void convertRelationObjectsToKeys( 
381         EOEditingContext aContext, Object anObject )
382     { // System.out.println( "convertRelationObjectsToKeys: " + anObject );        
383         Object o;
384         DataKeyID id;
385         List result = new LinkedList();
386         Iterator it = ((TestObject)anObject).getChildList().iterator();
387 // for testing purposes                
388 ((TestObject)anObject).setParent( null );
389 ((TestObject)anObject).editingContext = null;
390         while ( it.hasNext() )
391         {
392             o = it.next();
393 //System.out.println( "convertRelationObjectsToKeys: " + o + " : " + aContext.globalIDForObject( o ) ); 
394             id = (DataKeyID)aContext.globalIDForObject( o );            
395             
396             // if object still exists in context
397             if ( id != null ) 
398             {
399                 result.add( id.getKey() );
400             }
401             else // object was deleted
402             {
403                 // do not add  
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  * $Log$
415  * Revision 1.1  2006/02/19 16:30:25  cgruber
416  * Update imports and maven dependencies.
417  *
418  * Revision 1.1  2006/02/16 13:18:56  cgruber
419  * Check in all sources in eclipse-friendly maven-enabled packages.
420  *
421  * Revision 1.18  2002/03/11 03:18:39  mpowers
422  * Now properly handling ObserverChangesLater.
423  *
424  * Revision 1.17  2001/10/26 18:39:44  mpowers
425  * Posting notifications immediately, rather than delayed.
426  *
427  * Revision 1.16  2001/05/06 18:27:10  mpowers
428  * More broadly catching editing contexts for now.
429  *
430  * Revision 1.15  2001/05/05 23:05:43  mpowers
431  * Implemented Array Faults.
432  *
433  * Revision 1.14  2001/05/05 15:00:06  mpowers
434  * Tested load-on-demand: still works.
435  * Now using registerClone for consistency.
436  * Editing context is temporarily posting notification on objectWillChange.
437  *
438  * Revision 1.13  2001/05/04 23:24:30  mpowers
439  * Changes to test code.
440  *
441  * Revision 1.12  2001/05/04 16:57:56  mpowers
442  * Now correctly transposing references to editing contexts when
443  * cloning/copying between editing contexts.
444  *
445  * Revision 1.11  2001/05/02 17:33:28  mpowers
446  * More changes for testing.
447  *
448  * Revision 1.10  2001/04/30 13:15:24  mpowers
449  * Child contexts re-initializing objects invalidated in parent now
450  * propery transpose relationships.
451  *
452  * Revision 1.9  2001/04/29 22:02:45  mpowers
453  * Work on id transposing between editing contexts.
454  *
455  * Revision 1.8  2001/04/29 02:29:31  mpowers
456  * Debugging relationship faulting.
457  *
458  * Revision 1.7  2001/04/28 22:17:51  mpowers
459  * Revised PropertyDataSource to be EOClassDescription-aware.
460  *
461  * Revision 1.6  2001/04/28 16:18:44  mpowers
462  * Implementing relationships.
463  *
464  * Revision 1.5  2001/04/13 16:33:36  mpowers
465  * Now broadcasting notifications.
466  *
467  * Revision 1.4  2001/04/08 21:00:54  mpowers
468  * Changes to support new objectsForFetchSpecification scheme.
469  *
470  * Revision 1.3  2001/03/22 21:37:52  mpowers
471  * Testing new features.
472  *
473  * Revision 1.2  2001/03/15 21:10:41  mpowers
474  * Implemented global id re-registration for newly saved inserts.
475  *
476  * Revision 1.1  2001/03/05 22:12:11  mpowers
477  * Created the control package for a datastore-specific implementation
478  * of EOObjectStore.
479  *
480  * 
481  */
482 }
483