1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
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
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
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
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
268
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
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
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
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
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
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
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
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
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673