summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java
diff options
context:
space:
mode:
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.java431
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.
+ *
+ *
+ */
+
+