View Javadoc

1   /*
2   Wotonomy: OpenStep design patterns for pure Java applications.
3   Copyright (C) 2001 Intersect Software Corporation
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, see http://www.gnu.org
17  */
18  
19  package net.wotonomy.control;
20  
21  import java.util.Collection;
22  import java.util.List;
23  import java.util.Map;
24  
25  import net.wotonomy.foundation.NSArray;
26  import net.wotonomy.foundation.NSDictionary;
27  import net.wotonomy.foundation.NSSet;
28  import net.wotonomy.foundation.internal.WotonomyException;
29  
30  /***
31  * EOCustomObject implements all the necessary interfaces to
32  * receive first-class treatment from the control framework.
33  * The implementation delegates as much class meta-behavior as
34  * possible to EOClassDescription, letting subclasses
35  * focus exclusively on business logic while still allowing 
36  * them to customize as much class behavior as needed.
37  *
38  * @author michael@mpowers.net
39  * @author $Author: cgruber $
40  * @version $Revision: 894 $
41  */
42  public class EOCustomObject
43   implements EOEnterpriseObject,
44              EOKeyValueCodingAdditions,
45              EODeferredFaulting,
46              EORelationshipManipulation,
47              EOValidation
48  {
49      private transient static EOClassDescription classDescription;
50      private transient EOEditingContext editingContext;
51      
52      // static configuration
53  
54      /***
55      * Specifies whether the implementation of EOKeyValueCoding
56      * is permitted to access field directly.  This implementation
57      * returns true; subclasses may override to customize this behavior. 
58      */
59      public static boolean canAccessFieldsDirectly()
60      {
61          return true;
62      }
63      
64      /***
65      * Specifies whether the implementation of EOKeyValueCoding
66      * is permitted to access private accessors.  This implementation
67      * returns true; subclasses may override to customize this behavior. 
68      */
69      public static boolean shouldUseStoredAccessors()
70      {
71          return true;
72      }
73      
74      /***
75      * Specifies whether deferred faults should be used.  This implementation
76      * returns false; subclasses may override to customize this behavior. 
77      */
78      public static boolean usesDeferredFaultCreation()
79      {
80          return false;
81      }
82      
83      // constructors
84      
85      /***
86      * Default constructor initializes private state.
87      * EditingContext and ClassDescription are set to null.
88      */
89      public EOCustomObject()
90      {
91          editingContext = null;
92          classDescription = null;
93      }
94      
95      /***
96      * Preferred constructor, specifying an editing context,
97      * a class description, and a global id, any or all of which
98      * may be null.  Subclasses should invoke this constructor.
99      */
100     public EOCustomObject(
101         EOEditingContext aContext, 
102         EOClassDescription aClassDescription, 
103         EOGlobalID aGlobalID )
104     {
105         editingContext = aContext;
106         classDescription = aClassDescription;
107     }
108     
109     // interface EOEnterpriseObject
110 
111     /***
112     * Returns a List of all property keys defined on this object.
113     * This includes both attributes and relationships.
114     * This implementation returns the union of attributeKeys,
115     * toOneRelationshipKeys, and toManyRelationshipKeys.
116     */
117     public NSArray allPropertyKeys()
118     {
119         NSSet union = new NSSet();
120         union.addAll( attributeKeys() );
121         union.addAll( toOneRelationshipKeys() );
122         union.addAll( toManyRelationshipKeys() );
123         return new NSArray( (Collection) union );
124     }
125     
126     /***
127     * Returns a list of all attributes defined on this object.
128     * Attributes are all properties that are not relationships.
129     * This implementation retrieves the keys from the class
130     * description.
131     */
132     public NSArray attributeKeys()
133     {
134         return classDescription().attributeKeys();
135     }
136     
137     //void awakeFromClientUpdate(EOEditingContext aContext)
138     
139     /***
140     * Called when the object has first been fetched into the 
141     * specified editing context.  This implementation calls
142     * awakeObjectFromFetch on the class description.
143     */
144     public void awakeFromFetch(EOEditingContext anEditingContext)
145     {
146         classDescription().awakeObjectFromFetch( this, anEditingContext );
147     }
148     
149     /***
150     * Called when the object has been inserted into the 
151     * specified editing context.  This implementation calls
152     * awakeObjectFromInsertion on the class description.
153     */
154     public void awakeFromInsertion(EOEditingContext anEditingContext)
155     {
156         classDescription().awakeObjectFromInsertion( this, anEditingContext );
157     }
158     
159     /***
160     * Returns a Map representing the delta of the current state
161     * from the state represented in the specified snapshot.
162     * The result will contain only the keys that have changed
163     * and their values.  Relationship keys will map to an NSArray
164     * that contains an NSArray of added objects and an NSArray
165     * of removed objects, in that order.
166     */
167     public NSDictionary changesFromSnapshot(NSDictionary snapshot)
168     {
169         throw new WotonomyException( "Not implemented yet." );
170     }
171     
172     /***
173     * Returns a class description for this object.
174     * Calls EOClassDescription.classDescriptionForClass.
175     */
176     public EOClassDescription classDescription()
177     {
178         if ( classDescription == null )
179         {
180             classDescription = EOClassDescription.classDescriptionForClass( getClass() );
181             if ( classDescription == null )
182             {
183                 throw new WotonomyException( 
184                     "No class description found for class: " + getClass() );
185             }
186         }
187         return classDescription;
188     }
189     
190     /***
191     * Returns a class description for the object at the 
192     * other end of the specified relationship key.
193     * This implementation calls to the classDescription.
194     */
195     public EOClassDescription classDescriptionForDestinationKey(String aKey)
196     {
197         return classDescription().classDescriptionForDestinationKey( aKey );
198     }
199     
200     /***
201     * Clears all property values for this object.
202     * This method is called to clean-up an object that
203     * will no longer be used, and implementations should
204     * ensure that all references are set to null to 
205     * prevent problems with garbage-collection.
206     */ 
207     public void clearProperties()
208     {
209         //FIXME: clear properties here
210     }
211     
212     /***
213     * Returns the delete rule constant defined on EOClassDescription
214     * for the relationship defined by the specified key.
215     * This implementation calls to the classDescription.
216     */
217     public int deleteRuleForRelationshipKey(String aRelationshipKey)
218     {
219         return classDescription().deleteRuleForRelationshipKey( aRelationshipKey );
220     }
221     
222     /***
223     * Returns the editing context in which this object is registered.
224     */
225     public EOEditingContext editingContext()
226     {
227         return editingContext;
228     }
229     
230     /***
231     * Returns the name of the entity that this object represents.
232     */
233     public String entityName()
234     {
235         return classDescription().entityName();
236     }
237     
238     /***
239     * Returns a String containing all property keys and values for
240     * this object.  Relationships should be represented by calling
241     * eoShallowDescription() on the object.
242     */
243     public String eoDescription()
244     {
245         throw new WotonomyException( "Not implemented yet." );
246     }
247     
248     /***
249     * Returns a String containing all attribute keys and values for
250     * this object.  Relationships are not included.
251     */
252     public String eoShallowDescription()
253     {
254         throw new WotonomyException( "Not implemented yet." );
255     }
256     
257     /***
258     * Returns the key used to reference this object on the 
259     * object at the other end of the specified relationship.
260     * This implementation calls to the class description.
261     */
262     public String inverseForRelationshipKey(String aRelationshipKey)
263     {
264         return classDescription().inverseForRelationshipKey( aRelationshipKey );
265     }
266     
267     //Object invokeRemoteMethod( 
268     //	String aMethodName, Class[] aTypeArray Object[] anArgumentArray)
269     
270     /***
271     * Returns whether the specified relationship key represents
272     * a to-many relationship.
273     */
274     public boolean isToManyKey(String aKey)
275     {
276         return toManyRelationshipKeys().containsObject( aKey );
277     }
278     
279     /***
280     * Returns whether the objects at the other end of the specified
281     * relationship should be deleted when this object is deleted.
282     * This implementation calls to the class description.
283     */
284     public boolean ownsDestinationObjectsForRelationshipKey(String aKey)
285     {
286         return classDescription().ownsDestinationObjectsForRelationshipKey( aKey );
287     }
288     
289     //void prepareValuesForClient()
290     
291     /***
292     * Called to perform the delete propagation for this object
293     * on the specified editing context.  All relationships 
294     * should be processed according to their corresponding 
295     * delete rule.
296     * This implementation calls to the class description.
297     */
298     public void propagateDeleteWithEditingContext(EOEditingContext aContext)
299     {
300         classDescription().propagateDeleteForObject( this, aContext );
301     }
302     
303     /***
304     * Applies the changes from the specified snapshot to
305     * this object.  
306     * @see #changesFromSnapshot(NSDictionary)
307     */
308     public void reapplyChangesFromDictionary(NSDictionary aDeltaSnapshot)
309     {
310         throw new WotonomyException( "Not implemented yet." );
311     }
312     
313     /***
314     * Returns a snapshot of the current state of this object.
315     * All property keys are mapped to their values; nulls are
316     * represented by NSNull.
317     */
318     public NSDictionary snapshot()
319     {
320         throw new WotonomyException( "Not implemented yet." );
321     }
322     
323     /***
324     * Returns a List of the to-many relationship keys
325     * for this object.
326     * This implementation calls to the class description.
327     */ 
328     public NSArray toManyRelationshipKeys()
329     {
330         return classDescription().toManyRelationshipKeys();
331     }
332     
333     /***
334     * Returns a List of the to-one relationship keys
335     * for this object.
336     * This implementation calls to the class description.
337     */
338     public NSArray toOneRelationshipKeys()
339     {
340         return classDescription().toOneRelationshipKeys();
341     }
342     
343     /***
344     * Applies the specified snapshot to this object,
345     * converting NSNulls to null and calling 
346     * takeStoredValueForKey for each key in the Map.
347     */
348     public void updateFromSnapshot(NSDictionary aSnapshot)
349     {
350         throw new WotonomyException( "Not implemented yet." );
351     }
352     
353     /***
354     * Returns a short, stateful string representation
355     * of this object.
356     * This implementation calls to the class description.
357     */
358     public String userPresentableDescription()
359     {
360         return classDescription().userPresentableDescriptionForObject( this );
361     }
362     
363     /***
364     * This method should be called by each setter method
365     * on this object before changes are made to the
366     * object's internal state.  This implementation calls 
367     * EOObserverCenter.notifyObserversObjectWillChange( this ),
368     */
369     public void willChange()
370     {
371         EOObserverCenter.notifyObserversObjectWillChange( this );
372     }
373     
374     // interface EOKeyValueCoding
375     
376     /***
377     * Returns the value for the specified property.
378     * If the property does not exist, this method should
379     * call handleQueryWithUnboundKey.
380     */
381     public Object valueForKey( String aKey )
382     {
383         return EOKeyValueCodingSupport.valueForKey( this, aKey );
384     }
385 
386     /***
387     * Sets the property to the specified value.
388     * If the property does not exist, this method should
389     * call handleTakeValueForUnboundKey.
390     * If the property is of a type that cannot allow
391     * null (e.g. primitive types) and aValue is null,
392     * this method should call unableToSetNullForKey.
393     */
394     public void takeValueForKey( Object aValue, String aKey )
395     {
396         EOKeyValueCodingSupport.takeValueForKey( this, aValue, aKey );
397     }
398 
399     /***
400     * Returns the value for the private field that 
401     * corresponds to the specified property.
402     */
403     public Object storedValueForKey( String aKey )
404     {
405         return EOKeyValueCodingSupport.storedValueForKey( this, aKey );
406     }
407 
408     /***
409     * Sets the the private field that corresponds to the 
410     * specified property to the specified value.
411     */
412     public void takeStoredValueForKey( Object aValue, String aKey )
413     {
414         EOKeyValueCodingSupport.takeStoredValueForKey( this, aValue, aKey );
415     }
416 
417     /***
418     * Called by valueForKey when the specified key is
419     * not found on this object.  Implementing classes 
420     * should handle the specified value or otherwise 
421     * throw an exception.
422     */
423     public Object handleQueryWithUnboundKey( String aKey )
424     {
425         return EOKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
426     }
427 
428     /***
429     * Called by takeValueForKey when the specified key
430     * is not found on this object.  Implementing classes
431     * should handle the specified value or otherwise 
432     * throw an exception.
433     */
434     public void handleTakeValueForUnboundKey( Object aValue, String aKey )
435     {
436         EOKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
437     }
438 
439     /***
440     * Called by takeValueForKey when the type of the
441     * specified key is not allowed to be null, as is
442     * the case with primitive types.  Implementing 
443     * classes should handle this case appropriately
444     * or otherwise throw an exception.
445     */
446     public void unableToSetNullForKey( String aKey )
447     {
448         EOKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
449     }
450 
451     // interface EOKeyValueCodingAdditions
452     
453     /***
454     * Returns the value for the specified key path, which is
455     * a series of keys delimited by ".", for example:
456     * "createTime.year.length".
457     */
458     public Object valueForKeyPath( String aKeyPath )
459     {
460         throw new WotonomyException( "Not implemented yet." );
461     }
462 
463     /***
464     * Sets the value for the specified key path, which is
465     * a series of keys delimited by ".", for example:
466     * "createTime.year.length".
467     * The value is set for the last object referenced by
468     * the key path.
469     */
470     public void takeValueForKeyPath( Object aValue, String aKeyPath )
471     {
472         throw new WotonomyException( "Not implemented yet." );
473     }
474     
475     /***
476     * Returns a Map of the specified keys to their values,
477     * each of which might be obtained by calling valueForKey.
478     */
479     public NSDictionary valuesForKeys( List aKeyList )
480     {
481         return KeyValueCodingUtilities.valuesForKeys( this, aKeyList );
482     }
483     
484     /***
485     * Takes the keys from the specified map as properties
486     * and applies the corresponding values, each of which
487     * might be set by calling takeValueForKey.
488     */
489     public void takeValuesFromDictionary( Map aMap )
490     {
491          KeyValueCodingUtilities.takeValuesFromDictionary( this, aMap );
492     }
493     
494     // interface EOFaulting
495     
496     /***
497     * Called by EOFaultHandler to prepare the object to be turned into a fault. 
498     */
499     public void clearFault()
500     {
501         throw new WotonomyException( "Not implemented yet." );
502     }
503     
504     /***
505     * Returns this object's EOFaultHandler.
506     */
507     public EOFaultHandler faultHandler()
508     {
509         throw new WotonomyException( "Not implemented yet." );
510     }
511     
512     /***
513     * Returns whether this object is currently a fault.
514     * Returns true if this object has not yet retrieved any values.
515     */
516     public boolean isFault()
517     {
518         throw new WotonomyException( "Not implemented yet." );
519     }
520     
521     /***
522     * Turns this object into a fault using the specified fault handler.
523     */
524     public void turnIntoFault( EOFaultHandler aFaultHandler )
525     {
526         throw new WotonomyException( "Not implemented yet." );
527     }
528     
529     /***
530     * Called to completely fire the fault, reading all attributes.
531     * This method may be implemented to call willRead(null).
532     */
533     public void willRead()
534     {
535         throw new WotonomyException( "Not implemented yet." );
536     }
537     
538     /***
539     * Called to fire the fault for the specified key.  
540     * The fault manager is required to populate the specified key
541     * with a value, and may populate any or all of the other values
542     * on this object.  A null key will populate all values on the object.
543     * NOTE: This method is not part of the specification.
544     */
545     public void willRead( String aKey )
546     {
547         throw new WotonomyException( "Not implemented yet." );
548     }
549 
550     // interface EODeferredFaulting
551     
552     /***
553     * Returns a fault for the specified deferred fault.
554     */
555 	public Object willReadRelationship( Object anObject )
556     {
557         throw new WotonomyException( "Not implemented yet." );
558     }
559     
560     // interface EORelationshipManipulation
561     
562     /***
563     * Adds the specified object to the relationship on this
564     * object specified by the key.  For to-one relationships,
565     * this operation is the same as valueForKey.
566     */
567     public void addObjectToPropertyWithKey( 
568         Object anObject, String aKey )
569     {
570         throw new WotonomyException( "Not implemented yet." );
571     }
572 
573     /***
574     * Removes the specified object from the relationship on
575     * this object specified by the key.  For to-one relationships,
576     * this operation is the same as takeValueForKey with a null
577     * value.
578     */
579     public void removeObjectFromPropertyWithKey( 
580         Object anObject, String aKey )
581     {
582         throw new WotonomyException( "Not implemented yet." );
583     }
584 
585     /***
586     * As addObjectToProperty with key, but also performs the
587     * reciprocal operation on the other side of the relationship.
588     */
589     public void addObjectToBothSidesOfRelationshipWithKey( 
590         EORelationshipManipulation anObject, String aKey )
591     {
592         throw new WotonomyException( "Not implemented yet." );
593     }
594         
595     /***
596     * As removeObjectFromPropertyWithKey with key, but also performs the
597     * reciprocal operation on the other side of the relationship.
598     */
599     public void removeObjectFromBothSidesOfRelationshipWithKey( 
600         EORelationshipManipulation anObject, String aKey )
601     {
602         throw new WotonomyException( "Not implemented yet." );
603     }
604 
605     // interface EOValidation
606     
607     /***
608     * Validates this object for delete.
609     * Throws an exception if this object cannot be deleted.
610     * This implementation calls to the class description.
611     */
612     public void validateForDelete()
613     {
614         classDescription().validateObjectForDelete( this );
615     }
616     
617     /***
618     * Validates this object for insertion into the external store.
619     * Throws an exception if this object cannot be inserted.
620     * Validations here should be specific to insertion.
621     * This implementation calls validateForSave(). 
622     */
623     public void validateForInsert()
624     {
625         validateForSave();
626     }
627     
628     /***
629     * Validates this object for a commit to the external store.
630     * Throws an exception if this object cannot be committed.
631     * Validations here are not specific to either inserts or updates.
632     * This implementation calls to the class description.
633     */
634     public void validateForSave()
635     {
636         classDescription().validateObjectForSave( this );
637     }
638     
639     /***
640     * Validates this object for update to the external store.
641     * Throws an exception if this object cannot be updated.
642     * Validations here should be specific to updates.
643     * This implementation calls validateForSave(). 
644     */
645     public void validateForUpdate()
646     {
647         validateForSave();
648     }
649 }
650 
651 /*
652  * $Log$
653  * Revision 1.2  2006/02/16 16:47:14  cgruber
654  * Move some classes in to "internal" packages and re-work imports, etc.
655  *
656  * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
657  *
658  * Revision 1.1  2006/02/16 13:19:57  cgruber
659  * Check in all sources in eclipse-friendly maven-enabled packages.
660  *
661  * Revision 1.3  2001/12/06 16:42:29  mpowers
662  * Added appropriate constructor.
663  *
664  * Revision 1.2  2001/11/24 17:37:29  mpowers
665  * Implemented static methods.
666  *
667  * Revision 1.1  2001/11/17 17:18:15  mpowers
668  * Initial implementation of EOCustomObject.
669  *
670  *
671  */
672     
673