/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2001 Intersect Software Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.control; import java.util.Collection; import java.util.List; import java.util.Map; import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSDictionary; import net.wotonomy.foundation.NSSet; import net.wotonomy.foundation.internal.WotonomyException; /** * EOCustomObject implements all the necessary interfaces to * receive first-class treatment from the control framework. * The implementation delegates as much class meta-behavior as * possible to EOClassDescription, letting subclasses * focus exclusively on business logic while still allowing * them to customize as much class behavior as needed. * * @author michael@mpowers.net * @author $Author: cgruber $ * @version $Revision: 894 $ */ public class EOCustomObject implements EOEnterpriseObject, EOKeyValueCodingAdditions, EODeferredFaulting, EORelationshipManipulation, EOValidation { private transient static EOClassDescription classDescription; private transient EOEditingContext editingContext; // static configuration /** * Specifies whether the implementation of EOKeyValueCoding * is permitted to access field directly. This implementation * returns true; subclasses may override to customize this behavior. */ public static boolean canAccessFieldsDirectly() { return true; } /** * Specifies whether the implementation of EOKeyValueCoding * is permitted to access private accessors. This implementation * returns true; subclasses may override to customize this behavior. */ public static boolean shouldUseStoredAccessors() { return true; } /** * Specifies whether deferred faults should be used. This implementation * returns false; subclasses may override to customize this behavior. */ public static boolean usesDeferredFaultCreation() { return false; } // constructors /** * Default constructor initializes private state. * EditingContext and ClassDescription are set to null. */ public EOCustomObject() { editingContext = null; classDescription = null; } /** * Preferred constructor, specifying an editing context, * a class description, and a global id, any or all of which * may be null. Subclasses should invoke this constructor. */ public EOCustomObject( EOEditingContext aContext, EOClassDescription aClassDescription, EOGlobalID aGlobalID ) { editingContext = aContext; classDescription = aClassDescription; } // interface EOEnterpriseObject /** * Returns a List of all property keys defined on this object. * This includes both attributes and relationships. * This implementation returns the union of attributeKeys, * toOneRelationshipKeys, and toManyRelationshipKeys. */ public NSArray allPropertyKeys() { NSSet union = new NSSet(); union.addAll( attributeKeys() ); union.addAll( toOneRelationshipKeys() ); union.addAll( toManyRelationshipKeys() ); return new NSArray( (Collection) union ); } /** * Returns a list of all attributes defined on this object. * Attributes are all properties that are not relationships. * This implementation retrieves the keys from the class * description. */ public NSArray attributeKeys() { return classDescription().attributeKeys(); } //void awakeFromClientUpdate(EOEditingContext aContext) /** * Called when the object has first been fetched into the * specified editing context. This implementation calls * awakeObjectFromFetch on the class description. */ public void awakeFromFetch(EOEditingContext anEditingContext) { classDescription().awakeObjectFromFetch( this, anEditingContext ); } /** * Called when the object has been inserted into the * specified editing context. This implementation calls * awakeObjectFromInsertion on the class description. */ public void awakeFromInsertion(EOEditingContext anEditingContext) { classDescription().awakeObjectFromInsertion( this, anEditingContext ); } /** * Returns a Map representing the delta of the current state * from the state represented in the specified snapshot. * The result will contain only the keys that have changed * and their values. Relationship keys will map to an NSArray * that contains an NSArray of added objects and an NSArray * of removed objects, in that order. */ public NSDictionary changesFromSnapshot(NSDictionary snapshot) { throw new WotonomyException( "Not implemented yet." ); } /** * Returns a class description for this object. * Calls EOClassDescription.classDescriptionForClass. */ public EOClassDescription classDescription() { if ( classDescription == null ) { classDescription = EOClassDescription.classDescriptionForClass( getClass() ); if ( classDescription == null ) { throw new WotonomyException( "No class description found for class: " + getClass() ); } } return classDescription; } /** * Returns a class description for the object at the * other end of the specified relationship key. * This implementation calls to the classDescription. */ public EOClassDescription classDescriptionForDestinationKey(String aKey) { return classDescription().classDescriptionForDestinationKey( aKey ); } /** * Clears all property values for this object. * This method is called to clean-up an object that * will no longer be used, and implementations should * ensure that all references are set to null to * prevent problems with garbage-collection. */ public void clearProperties() { //FIXME: clear properties here } /** * Returns the delete rule constant defined on EOClassDescription * for the relationship defined by the specified key. * This implementation calls to the classDescription. */ public int deleteRuleForRelationshipKey(String aRelationshipKey) { return classDescription().deleteRuleForRelationshipKey( aRelationshipKey ); } /** * Returns the editing context in which this object is registered. */ public EOEditingContext editingContext() { return editingContext; } /** * Returns the name of the entity that this object represents. */ public String entityName() { return classDescription().entityName(); } /** * Returns a String containing all property keys and values for * this object. Relationships should be represented by calling * eoShallowDescription() on the object. */ public String eoDescription() { throw new WotonomyException( "Not implemented yet." ); } /** * Returns a String containing all attribute keys and values for * this object. Relationships are not included. */ public String eoShallowDescription() { throw new WotonomyException( "Not implemented yet." ); } /** * Returns the key used to reference this object on the * object at the other end of the specified relationship. * This implementation calls to the class description. */ public String inverseForRelationshipKey(String aRelationshipKey) { return classDescription().inverseForRelationshipKey( aRelationshipKey ); } //Object invokeRemoteMethod( // String aMethodName, Class[] aTypeArray Object[] anArgumentArray) /** * Returns whether the specified relationship key represents * a to-many relationship. */ public boolean isToManyKey(String aKey) { return toManyRelationshipKeys().containsObject( aKey ); } /** * Returns whether the objects at the other end of the specified * relationship should be deleted when this object is deleted. * This implementation calls to the class description. */ public boolean ownsDestinationObjectsForRelationshipKey(String aKey) { return classDescription().ownsDestinationObjectsForRelationshipKey( aKey ); } //void prepareValuesForClient() /** * Called to perform the delete propagation for this object * on the specified editing context. All relationships * should be processed according to their corresponding * delete rule. * This implementation calls to the class description. */ public void propagateDeleteWithEditingContext(EOEditingContext aContext) { classDescription().propagateDeleteForObject( this, aContext ); } /** * Applies the changes from the specified snapshot to * this object. * @see #changesFromSnapshot(NSDictionary) */ public void reapplyChangesFromDictionary(NSDictionary aDeltaSnapshot) { throw new WotonomyException( "Not implemented yet." ); } /** * Returns a snapshot of the current state of this object. * All property keys are mapped to their values; nulls are * represented by NSNull. */ public NSDictionary snapshot() { throw new WotonomyException( "Not implemented yet." ); } /** * Returns a List of the to-many relationship keys * for this object. * This implementation calls to the class description. */ public NSArray toManyRelationshipKeys() { return classDescription().toManyRelationshipKeys(); } /** * Returns a List of the to-one relationship keys * for this object. * This implementation calls to the class description. */ public NSArray toOneRelationshipKeys() { return classDescription().toOneRelationshipKeys(); } /** * Applies the specified snapshot to this object, * converting NSNulls to null and calling * takeStoredValueForKey for each key in the Map. */ public void updateFromSnapshot(NSDictionary aSnapshot) { throw new WotonomyException( "Not implemented yet." ); } /** * Returns a short, stateful string representation * of this object. * This implementation calls to the class description. */ public String userPresentableDescription() { return classDescription().userPresentableDescriptionForObject( this ); } /** * This method should be called by each setter method * on this object before changes are made to the * object's internal state. This implementation calls * EOObserverCenter.notifyObserversObjectWillChange( this ), */ public void willChange() { EOObserverCenter.notifyObserversObjectWillChange( this ); } // interface EOKeyValueCoding /** * Returns the value for the specified property. * If the property does not exist, this method should * call handleQueryWithUnboundKey. */ public Object valueForKey( String aKey ) { return EOKeyValueCodingSupport.valueForKey( this, aKey ); } /** * Sets the property to the specified value. * If the property does not exist, this method should * call handleTakeValueForUnboundKey. * If the property is of a type that cannot allow * null (e.g. primitive types) and aValue is null, * this method should call unableToSetNullForKey. */ public void takeValueForKey( Object aValue, String aKey ) { EOKeyValueCodingSupport.takeValueForKey( this, aValue, aKey ); } /** * Returns the value for the private field that * corresponds to the specified property. */ public Object storedValueForKey( String aKey ) { return EOKeyValueCodingSupport.storedValueForKey( this, aKey ); } /** * Sets the the private field that corresponds to the * specified property to the specified value. */ public void takeStoredValueForKey( Object aValue, String aKey ) { EOKeyValueCodingSupport.takeStoredValueForKey( this, aValue, aKey ); } /** * Called by valueForKey when the specified key is * not found on this object. Implementing classes * should handle the specified value or otherwise * throw an exception. */ public Object handleQueryWithUnboundKey( String aKey ) { return EOKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey ); } /** * Called by takeValueForKey when the specified key * is not found on this object. Implementing classes * should handle the specified value or otherwise * throw an exception. */ public void handleTakeValueForUnboundKey( Object aValue, String aKey ) { EOKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey ); } /** * Called by takeValueForKey when the type of the * specified key is not allowed to be null, as is * the case with primitive types. Implementing * classes should handle this case appropriately * or otherwise throw an exception. */ public void unableToSetNullForKey( String aKey ) { EOKeyValueCodingSupport.unableToSetNullForKey( this, aKey ); } // interface EOKeyValueCodingAdditions /** * Returns the value for the specified key path, which is * a series of keys delimited by ".", for example: * "createTime.year.length". */ public Object valueForKeyPath( String aKeyPath ) { throw new WotonomyException( "Not implemented yet." ); } /** * Sets the value for the specified key path, which is * a series of keys delimited by ".", for example: * "createTime.year.length". * The value is set for the last object referenced by * the key path. */ public void takeValueForKeyPath( Object aValue, String aKeyPath ) { throw new WotonomyException( "Not implemented yet." ); } /** * Returns a Map of the specified keys to their values, * each of which might be obtained by calling valueForKey. */ public NSDictionary valuesForKeys( List aKeyList ) { return KeyValueCodingUtilities.valuesForKeys( this, aKeyList ); } /** * Takes the keys from the specified map as properties * and applies the corresponding values, each of which * might be set by calling takeValueForKey. */ public void takeValuesFromDictionary( Map aMap ) { KeyValueCodingUtilities.takeValuesFromDictionary( this, aMap ); } // interface EOFaulting /** * Called by EOFaultHandler to prepare the object to be turned into a fault. */ public void clearFault() { throw new WotonomyException( "Not implemented yet." ); } /** * Returns this object's EOFaultHandler. */ public EOFaultHandler faultHandler() { throw new WotonomyException( "Not implemented yet." ); } /** * Returns whether this object is currently a fault. * Returns true if this object has not yet retrieved any values. */ public boolean isFault() { throw new WotonomyException( "Not implemented yet." ); } /** * Turns this object into a fault using the specified fault handler. */ public void turnIntoFault( EOFaultHandler aFaultHandler ) { throw new WotonomyException( "Not implemented yet." ); } /** * Called to completely fire the fault, reading all attributes. * This method may be implemented to call willRead(null). */ public void willRead() { throw new WotonomyException( "Not implemented yet." ); } /** * Called to fire the fault for the specified key. * The fault manager is required to populate the specified key * with a value, and may populate any or all of the other values * on this object. A null key will populate all values on the object. * NOTE: This method is not part of the specification. */ public void willRead( String aKey ) { throw new WotonomyException( "Not implemented yet." ); } // interface EODeferredFaulting /** * Returns a fault for the specified deferred fault. */ public Object willReadRelationship( Object anObject ) { throw new WotonomyException( "Not implemented yet." ); } // interface EORelationshipManipulation /** * Adds the specified object to the relationship on this * object specified by the key. For to-one relationships, * this operation is the same as valueForKey. */ public void addObjectToPropertyWithKey( Object anObject, String aKey ) { throw new WotonomyException( "Not implemented yet." ); } /** * Removes the specified object from the relationship on * this object specified by the key. For to-one relationships, * this operation is the same as takeValueForKey with a null * value. */ public void removeObjectFromPropertyWithKey( Object anObject, String aKey ) { throw new WotonomyException( "Not implemented yet." ); } /** * As addObjectToProperty with key, but also performs the * reciprocal operation on the other side of the relationship. */ public void addObjectToBothSidesOfRelationshipWithKey( EORelationshipManipulation anObject, String aKey ) { throw new WotonomyException( "Not implemented yet." ); } /** * As removeObjectFromPropertyWithKey with key, but also performs the * reciprocal operation on the other side of the relationship. */ public void removeObjectFromBothSidesOfRelationshipWithKey( EORelationshipManipulation anObject, String aKey ) { throw new WotonomyException( "Not implemented yet." ); } // interface EOValidation /** * Validates this object for delete. * Throws an exception if this object cannot be deleted. * This implementation calls to the class description. */ public void validateForDelete() { classDescription().validateObjectForDelete( this ); } /** * Validates this object for insertion into the external store. * Throws an exception if this object cannot be inserted. * Validations here should be specific to insertion. * This implementation calls validateForSave(). */ public void validateForInsert() { validateForSave(); } /** * Validates this object for a commit to the external store. * Throws an exception if this object cannot be committed. * Validations here are not specific to either inserts or updates. * This implementation calls to the class description. */ public void validateForSave() { classDescription().validateObjectForSave( this ); } /** * Validates this object for update to the external store. * Throws an exception if this object cannot be updated. * Validations here should be specific to updates. * This implementation calls validateForSave(). */ public void validateForUpdate() { validateForSave(); } } /* * $Log$ * Revision 1.2 2006/02/16 16:47:14 cgruber * Move some classes in to "internal" packages and re-work imports, etc. * * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions. * * Revision 1.1 2006/02/16 13:19:57 cgruber * Check in all sources in eclipse-friendly maven-enabled packages. * * Revision 1.3 2001/12/06 16:42:29 mpowers * Added appropriate constructor. * * Revision 1.2 2001/11/24 17:37:29 mpowers * Implemented static methods. * * Revision 1.1 2001/11/17 17:18:15 mpowers * Initial implementation of EOCustomObject. * * */