Coverage Report - net.wotonomy.control.EOCustomObject
 
Classes in this File Line Coverage Branch Coverage Complexity
EOCustomObject
0% 
0% 
1.4
 
 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  0
         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  0
         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  0
         return false;
 81  
     }
 82  
     
 83  
     // constructors
 84  
     
 85  
     /**
 86  
     * Default constructor initializes private state.
 87  
     * EditingContext and ClassDescription are set to null.
 88  
     */
 89  0
     public EOCustomObject()
 90  0
     {
 91  0
         editingContext = null;
 92  0
         classDescription = null;
 93  0
     }
 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  0
     public EOCustomObject(
 101  
         EOEditingContext aContext, 
 102  
         EOClassDescription aClassDescription, 
 103  
         EOGlobalID aGlobalID )
 104  0
     {
 105  0
         editingContext = aContext;
 106  0
         classDescription = aClassDescription;
 107  0
     }
 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  0
         NSSet union = new NSSet();
 120  0
         union.addAll( attributeKeys() );
 121  0
         union.addAll( toOneRelationshipKeys() );
 122  0
         union.addAll( toManyRelationshipKeys() );
 123  0
         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  0
         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  0
         classDescription().awakeObjectFromFetch( this, anEditingContext );
 147  0
     }
 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  0
         classDescription().awakeObjectFromInsertion( this, anEditingContext );
 157  0
     }
 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  0
         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  0
         if ( classDescription == null )
 179  
         {
 180  0
             classDescription = EOClassDescription.classDescriptionForClass( getClass() );
 181  0
             if ( classDescription == null )
 182  
             {
 183  0
                 throw new WotonomyException( 
 184  0
                     "No class description found for class: " + getClass() );
 185  
             }
 186  
         }
 187  0
         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  0
         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  0
     }
 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  0
         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  0
         return editingContext;
 228  
     }
 229  
     
 230  
     /**
 231  
     * Returns the name of the entity that this object represents.
 232  
     */
 233  
     public String entityName()
 234  
     {
 235  0
         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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         classDescription().propagateDeleteForObject( this, aContext );
 301  0
     }
 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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         EOObserverCenter.notifyObserversObjectWillChange( this );
 372  0
     }
 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  0
         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  0
         EOKeyValueCodingSupport.takeValueForKey( this, aValue, aKey );
 397  0
     }
 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  0
         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  0
         EOKeyValueCodingSupport.takeStoredValueForKey( this, aValue, aKey );
 415  0
     }
 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  0
         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  0
         EOKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
 437  0
     }
 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  0
         EOKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
 449  0
     }
 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  0
         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  0
         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  0
         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  0
          KeyValueCodingUtilities.takeValuesFromDictionary( this, aMap );
 492  0
     }
 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  0
         throw new WotonomyException( "Not implemented yet." );
 502  
     }
 503  
     
 504  
     /**
 505  
     * Returns this object's EOFaultHandler.
 506  
     */
 507  
     public EOFaultHandler faultHandler()
 508  
     {
 509  0
         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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         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  0
         classDescription().validateObjectForDelete( this );
 615  0
     }
 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  0
         validateForSave();
 626  0
     }
 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  0
         classDescription().validateObjectForSave( this );
 637  0
     }
 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  0
         validateForSave();
 648  0
     }
 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