diff options
Diffstat (limited to 'projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java')
| -rw-r--r-- | projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java new file mode 100644 index 0000000..5792303 --- /dev/null +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java @@ -0,0 +1,431 @@ +/* +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.foundation; + +import net.wotonomy.foundation.internal.Introspector; +import net.wotonomy.foundation.internal.IntrospectorException; +import net.wotonomy.foundation.internal.MissingPropertyException; +import net.wotonomy.foundation.internal.NullPrimitiveException; +import net.wotonomy.foundation.internal.WotonomyException; + +/** +* NSKeyValueCoding defines an interface for classes that +* need to have more control over the wotonomy's property +* introspection facilities. <br><br> +* +* On an object that implements this interface, wotonomy +* will call these methods, and otherwise use the static +* methods on NSKeyValueCodingSupport. <br><br> +* +* NSKeyValueCodingSupport implements the default behaviors +* for each of these methods, so classes implementing this +* interface can call those methods to acheive the same +* behavior. <br><br> +* +* valueForKey and takeValueForKey are called in response +* to user actions, like viewing an object or updating its +* value in a user interface. These should call the public +* getter and setter methods on the object itself and the +* operations should be subject to validation. <br><br> +* +* storedValueForKey and takeStoredValueForKey are called +* in response to wotonomy actions, like snapshotting, +* faulting, commits, and reverts. These operations should +* bypass the public methods and directly modify the internal +* state of the object without validation. +* +* @author michael@mpowers.net +* @author $Author: cgruber $ +* @version $Revision: 893 $ +*/ +public interface NSKeyValueCoding +{ + + public static final Null NullValue = new Null(); + + /** + * Returns the value for the specified property. + * If the property does not exist, this method should + * call handleQueryWithUnboundKey. + */ + Object valueForKey( String 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. + */ + void takeValueForKey( Object aValue, String aKey ); + + /** + * Returns the value for the private field that + * corresponds to the specified property. + */ + Object storedValueForKey( String aKey ); + + /** + * Sets the the private field that corresponds to the + * specified property to the specified value. + */ + void takeStoredValueForKey( Object aValue, String 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. + */ + Object handleQueryWithUnboundKey( String 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. + */ + void handleTakeValueForUnboundKey( Object aValue, String 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. + */ + void unableToSetNullForKey( String aKey ); + + /** + * Static utility methods that + * call the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + public class Utility + { + /** + * Calls the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + static public Object valueForKey( + Object anObject, String aKey ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + return ((NSKeyValueCoding)anObject).valueForKey( aKey ); + } + return DefaultImplementation.valueForKey( anObject, aKey ); + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + static public void takeValueForKey( + Object anObject, Object aValue, String aKey ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + ((NSKeyValueCoding)anObject).takeValueForKey( aValue, aKey ); + } + DefaultImplementation.takeValueForKey( anObject, aValue, aKey ); + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + static public Object storedValueForKey( + Object anObject, String aKey ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + return ((NSKeyValueCoding)anObject).storedValueForKey( aKey ); + } + return DefaultImplementation.storedValueForKey( anObject, aKey ); + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + static public void takeStoredValueForKey( + Object anObject, Object aValue, String aKey ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + ((NSKeyValueCoding)anObject).takeStoredValueForKey( aValue, aKey ); + } + DefaultImplementation.takeStoredValueForKey( anObject, aValue, aKey ); + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + static public Object handleQueryWithUnboundKey( + Object anObject, String aKey ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey ); + } + return DefaultImplementation.handleQueryWithUnboundKey( anObject, aKey ); + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + static public void handleTakeValueForUnboundKey( + Object anObject, Object aValue, String aKey ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( aValue, aKey ); + } + DefaultImplementation.handleTakeValueForUnboundKey( anObject, aValue, aKey ); + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCoding, otherwise calls the method + * on DefaultImplementation. + */ + static public void unableToSetNullForKey( + Object anObject, String aKey ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey ); + } + DefaultImplementation.unableToSetNullForKey( anObject, aKey ); + } + } + + public class DefaultImplementation + { + /** + * Returns the value for the specified property key + * on the specified object. <br><br> + * + * If the property does not exist, this method calls + * handleQueryWithUnboundKey on the object if it + * implements NSKeyValueCoding, otherwise calls + * handleQueryWithUnboundKey on this class. <br><br> + */ + static public Object valueForKey( + Object anObject, String aKey ) + { + if ( anObject == null ) return null; + //TODO: may need to handle "." nesting here so + // that handleQueryWithUnboundKey gets called for + // for the nested object, not the parent object + + //Correction: need to handle key paths in + // KeyValueCodingAdditionsSupport. + + try + { + return Introspector.get( anObject, aKey ); + } + catch ( IntrospectorException exc ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey ); + } + return handleQueryWithUnboundKey( anObject, aKey ); + } + } + + /** + * Sets the property to the specified value on + * the specified object. + * + * If the property does not exist, this method calls + * handleTakeValueForUnboundKey on the object if it + * implements NSKeyValueCoding, otherwise calls + * handleTakeValueForUnboundKey on this class. + * + * If the property is of a type that cannot allow + * null (e.g. primitive types) and aValue is null, + * this method should call unableToSetNullForKey + * on the object if it implements NSKeyValueCoding, + * otherwise calls unableToSetNullForKey on this class. + */ + static public void takeValueForKey( + Object anObject, Object aValue, String aKey ) + { + if ( anObject == null ) return; + //TODO: may need to handle "." nesting here so + // that handleTakeValueForUnboundKey gets called for + // for the nested object, not the parent object + try + { + Introspector.set( anObject, aKey, aValue ); + } + catch ( NullPrimitiveException exc ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey ); + } + else + { + unableToSetNullForKey( anObject, aKey ); + } + } + catch ( MissingPropertyException exc ) + { + if ( anObject instanceof NSKeyValueCoding ) + { + ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( + aValue, aKey ); + } + else + { + handleTakeValueForUnboundKey( anObject, aValue, aKey ); + } + } + + } + + /** + * Returns the value for the private field that + * corresponds to the specified property on + * the specified object. + * + * This implementation currently calls valueForKey, + * because java security currently prevents us from + * accessing the fields of another object. + */ + static public Object storedValueForKey( + Object anObject, String aKey ) + { + //TODO: this currently just calls valueForKey + return valueForKey( anObject, aKey ); + } + + /** + * Sets the the private field that corresponds to the + * specified property to the specified value on the + * specified object. + * + * This implementation currently calls takeValueForKey, + * because java security currently prevents us from + * accessing the fields of another object. + */ + static public void takeStoredValueForKey( + Object anObject, Object aValue, String aKey ) + { + //TODO: this currently just calls takeValueForKey + takeValueForKey( anObject, aValue, aKey ); + } + + /** + * Called by valueForKey when the specified key is + * not found on the specified object, if that object + * does not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public Object handleQueryWithUnboundKey( + Object anObject, String aKey ) + { + throw new WotonomyException( + "Key not found for object: " + + aKey + " : " + anObject ); + } + + /** + * Called by takeValueForKey when the specified key + * is not found on the specified object, if that object + * does not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public void handleTakeValueForUnboundKey( + Object anObject, Object aValue, String aKey ) + { + throw new WotonomyException( + "Key not found for object while setting value: " + + aKey + " : " + anObject + " : " + aValue ); + } + + /** + * Called by takeValueForKey when the type of the + * specified key is not allowed to be null, as is + * the case with primitive types, if the specified + * object does not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public void unableToSetNullForKey( + Object anObject, String aKey ) + { + throw new WotonomyException( + "Tried to key on object to null: " + + aKey + " : " + anObject ); + } + } + + public class Null { + public Null() { + super(); + } + + public String toString() { + return "<null>"; + } + } +} + +/* + * $Log$ + * Revision 1.2 2006/02/16 13:15:00 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.3 2003/08/07 02:43:56 chochos + * added NullValue, which points to a Null instance. + * + * Revision 1.2 2003/01/18 23:30:42 mpowers + * WODisplayGroup now compiles. + * + * Revision 1.1 2003/01/17 14:40:49 mpowers + * Adding files to fix build. + * + * Revision 1.2 2001/03/28 16:12:30 mpowers + * Documented interface. + * + * Revision 1.1 2001/03/27 23:25:05 mpowers + * Contributing interface, no docs yet. + * + * + */ + + |
