/* 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. * * */