Coverage Report - net.wotonomy.foundation.NSKeyValueCoding
 
Classes in this File Line Coverage Branch Coverage Complexity
NSKeyValueCoding
0% 
0% 
2.087
 
 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.foundation;
 20  
 
 21  
 import net.wotonomy.foundation.internal.Introspector;
 22  
 import net.wotonomy.foundation.internal.IntrospectorException;
 23  
 import net.wotonomy.foundation.internal.MissingPropertyException;
 24  
 import net.wotonomy.foundation.internal.NullPrimitiveException;
 25  
 import net.wotonomy.foundation.internal.WotonomyException;
 26  
 
 27  
 /**
 28  
 * NSKeyValueCoding defines an interface for classes that
 29  
 * need to have more control over the wotonomy's property
 30  
 * introspection facilities.  <br><br>
 31  
 * 
 32  
 * On an object that implements this interface, wotonomy 
 33  
 * will call these methods, and otherwise use the static
 34  
 * methods on NSKeyValueCodingSupport.  <br><br>
 35  
 *
 36  
 * NSKeyValueCodingSupport implements the default behaviors 
 37  
 * for each of these methods, so classes implementing this 
 38  
 * interface can call those methods to acheive the same 
 39  
 * behavior. <br><br>
 40  
 *
 41  
 * valueForKey and takeValueForKey are called in response
 42  
 * to user actions, like viewing an object or updating its
 43  
 * value in a user interface.  These should call the public
 44  
 * getter and setter methods on the object itself and the
 45  
 * operations should be subject to validation. <br><br>
 46  
 * 
 47  
 * storedValueForKey and takeStoredValueForKey are called 
 48  
 * in response to wotonomy actions, like snapshotting, 
 49  
 * faulting, commits, and reverts.  These operations should
 50  
 * bypass the public methods and directly modify the internal
 51  
 * state of the object without validation.
 52  
 *
 53  
 * @author michael@mpowers.net
 54  
 * @author $Author: cgruber $
 55  
 * @version $Revision: 893 $
 56  
 */
 57  
 public interface NSKeyValueCoding 
 58  
 {
 59  
 
 60  
         public static final Null NullValue = new Null();
 61  
 
 62  
     /**
 63  
     * Returns the value for the specified property.
 64  
     * If the property does not exist, this method should
 65  
     * call handleQueryWithUnboundKey.
 66  
     */
 67  
     Object valueForKey( String aKey );
 68  
 
 69  
     /**
 70  
     * Sets the property to the specified value.
 71  
     * If the property does not exist, this method should
 72  
     * call handleTakeValueForUnboundKey.
 73  
     * If the property is of a type that cannot allow
 74  
     * null (e.g. primitive types) and aValue is null,
 75  
     * this method should call unableToSetNullForKey.
 76  
     */
 77  
     void takeValueForKey( Object aValue, String aKey );
 78  
 
 79  
     /**
 80  
     * Returns the value for the private field that 
 81  
     * corresponds to the specified property.
 82  
     */
 83  
     Object storedValueForKey( String aKey );
 84  
 
 85  
     /**
 86  
     * Sets the the private field that corresponds to the 
 87  
     * specified property to the specified value.
 88  
     */
 89  
     void takeStoredValueForKey( Object aValue, String aKey );
 90  
 
 91  
     /**
 92  
     * Called by valueForKey when the specified key is
 93  
     * not found on this object.  Implementing classes 
 94  
     * should handle the specified value or otherwise 
 95  
     * throw an exception.
 96  
     */
 97  
     Object handleQueryWithUnboundKey( String aKey );
 98  
 
 99  
     /**
 100  
     * Called by takeValueForKey when the specified key
 101  
     * is not found on this object.  Implementing classes
 102  
     * should handle the specified value or otherwise 
 103  
     * throw an exception.
 104  
     */
 105  
     void handleTakeValueForUnboundKey( Object aValue, String aKey );
 106  
 
 107  
     /**
 108  
     * Called by takeValueForKey when the type of the
 109  
     * specified key is not allowed to be null, as is
 110  
     * the case with primitive types.  Implementing 
 111  
     * classes should handle this case appropriately
 112  
     * or otherwise throw an exception.
 113  
     */
 114  
     void unableToSetNullForKey( String aKey );
 115  
 
 116  
     /**
 117  
     * Static utility methods that
 118  
     * call the appropriate method if the object implements
 119  
     * NSKeyValueCoding, otherwise calls the method
 120  
     * on DefaultImplementation.
 121  
     */
 122  0
     public class Utility
 123  
     {
 124  
         /**
 125  
         * Calls the appropriate method if the object implements
 126  
         * NSKeyValueCoding, otherwise calls the method
 127  
         * on DefaultImplementation.
 128  
         */
 129  
         static public Object valueForKey( 
 130  
             Object anObject, String aKey )
 131  
         {
 132  0
             if ( anObject instanceof NSKeyValueCoding )
 133  
             {
 134  0
                 return ((NSKeyValueCoding)anObject).valueForKey( aKey );
 135  
             }
 136  0
             return DefaultImplementation.valueForKey( anObject, aKey );
 137  
         }
 138  
     
 139  
         /**
 140  
         * Calls the appropriate method if the object implements
 141  
         * NSKeyValueCoding, otherwise calls the method
 142  
         * on DefaultImplementation.
 143  
         */
 144  
         static public void takeValueForKey( 
 145  
             Object anObject, Object aValue, String aKey )
 146  
         {
 147  0
             if ( anObject instanceof NSKeyValueCoding )
 148  
             {
 149  0
                 ((NSKeyValueCoding)anObject).takeValueForKey( aValue, aKey );
 150  
             }
 151  0
             DefaultImplementation.takeValueForKey( anObject, aValue, aKey );
 152  0
         }
 153  
     
 154  
         /**
 155  
         * Calls the appropriate method if the object implements
 156  
         * NSKeyValueCoding, otherwise calls the method
 157  
         * on DefaultImplementation.
 158  
         */
 159  
         static public Object storedValueForKey( 
 160  
             Object anObject, String aKey )
 161  
         {
 162  0
             if ( anObject instanceof NSKeyValueCoding )
 163  
             {
 164  0
                 return ((NSKeyValueCoding)anObject).storedValueForKey( aKey );
 165  
             }
 166  0
             return DefaultImplementation.storedValueForKey( anObject, aKey );
 167  
         }
 168  
     
 169  
         /**
 170  
         * Calls the appropriate method if the object implements
 171  
         * NSKeyValueCoding, otherwise calls the method
 172  
         * on DefaultImplementation.
 173  
         */
 174  
         static public void takeStoredValueForKey( 
 175  
             Object anObject, Object aValue, String aKey )
 176  
         {
 177  0
             if ( anObject instanceof NSKeyValueCoding )
 178  
             {
 179  0
                 ((NSKeyValueCoding)anObject).takeStoredValueForKey( aValue, aKey );
 180  
             }
 181  0
             DefaultImplementation.takeStoredValueForKey( anObject, aValue, aKey );
 182  0
         }
 183  
     
 184  
         /**
 185  
         * Calls the appropriate method if the object implements
 186  
         * NSKeyValueCoding, otherwise calls the method
 187  
         * on DefaultImplementation.
 188  
         */
 189  
         static public Object handleQueryWithUnboundKey( 
 190  
             Object anObject, String aKey )
 191  
         {
 192  0
             if ( anObject instanceof NSKeyValueCoding )
 193  
             {
 194  0
                 return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey );
 195  
             }
 196  0
             return DefaultImplementation.handleQueryWithUnboundKey( anObject, aKey );
 197  
         }
 198  
     
 199  
         /**
 200  
         * Calls the appropriate method if the object implements
 201  
         * NSKeyValueCoding, otherwise calls the method
 202  
         * on DefaultImplementation.
 203  
         */
 204  
         static public void handleTakeValueForUnboundKey( 
 205  
             Object anObject, Object aValue, String aKey )
 206  
         {
 207  0
             if ( anObject instanceof NSKeyValueCoding )
 208  
             {
 209  0
                 ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( aValue, aKey );
 210  
             }
 211  0
             DefaultImplementation.handleTakeValueForUnboundKey( anObject, aValue, aKey );
 212  0
         }
 213  
     
 214  
         /**
 215  
         * Calls the appropriate method if the object implements
 216  
         * NSKeyValueCoding, otherwise calls the method
 217  
         * on DefaultImplementation.
 218  
         */
 219  
         static public void unableToSetNullForKey( 
 220  
             Object anObject, String aKey )
 221  
         {
 222  0
             if ( anObject instanceof NSKeyValueCoding )
 223  
             {
 224  0
                 ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey );
 225  
             }
 226  0
             DefaultImplementation.unableToSetNullForKey( anObject, aKey );
 227  0
         }
 228  
     }
 229  
     
 230  0
     public class DefaultImplementation
 231  
     {
 232  
         /**
 233  
         * Returns the value for the specified property key
 234  
         * on the specified object. <br><br>
 235  
         *
 236  
         * If the property does not exist, this method calls
 237  
         * handleQueryWithUnboundKey on the object if it 
 238  
         * implements NSKeyValueCoding, otherwise calls
 239  
         * handleQueryWithUnboundKey on this class. <br><br>
 240  
         */
 241  
         static public Object valueForKey( 
 242  
             Object anObject, String aKey )
 243  
         {
 244  0
             if ( anObject == null ) return null;    
 245  
             //TODO: may need to handle "." nesting here so
 246  
             // that handleQueryWithUnboundKey gets called for 
 247  
             // for the nested object, not the parent object
 248  
             
 249  
             //Correction: need to handle key paths in
 250  
             // KeyValueCodingAdditionsSupport.
 251  
                 
 252  
             try
 253  
             {
 254  0
                 return Introspector.get( anObject, aKey );        
 255  
             }
 256  0
             catch ( IntrospectorException exc )
 257  
             {
 258  0
                 if ( anObject instanceof NSKeyValueCoding )
 259  
                 {
 260  0
                     return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey );
 261  
                 }
 262  0
                 return handleQueryWithUnboundKey( anObject, aKey );   
 263  
             }
 264  
         }
 265  
     
 266  
         /**
 267  
         * Sets the property to the specified value on
 268  
         * the specified object.
 269  
         *
 270  
         * If the property does not exist, this method calls
 271  
         * handleTakeValueForUnboundKey on the object if it 
 272  
         * implements NSKeyValueCoding, otherwise calls
 273  
         * handleTakeValueForUnboundKey on this class.
 274  
         * 
 275  
         * If the property is of a type that cannot allow
 276  
         * null (e.g. primitive types) and aValue is null,
 277  
         * this method should call unableToSetNullForKey
 278  
         * on the object if it implements NSKeyValueCoding, 
 279  
         * otherwise calls unableToSetNullForKey on this class.    
 280  
         */
 281  
         static public void takeValueForKey( 
 282  
             Object anObject, Object aValue, String aKey )
 283  
         {
 284  0
             if ( anObject == null ) return;    
 285  
             //TODO: may need to handle "." nesting here so
 286  
             // that handleTakeValueForUnboundKey gets called for 
 287  
             // for the nested object, not the parent object
 288  
             try
 289  
             {
 290  0
                 Introspector.set( anObject, aKey, aValue );
 291  
             }
 292  0
             catch ( NullPrimitiveException exc )
 293  
             {
 294  0
                 if ( anObject instanceof NSKeyValueCoding )
 295  
                 {
 296  0
                     ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey );
 297  0
                 } 
 298  
                 else
 299  
                 {
 300  0
                     unableToSetNullForKey( anObject, aKey );   
 301  
                 }
 302  
             }
 303  0
             catch ( MissingPropertyException exc )
 304  
             {
 305  0
                 if ( anObject instanceof NSKeyValueCoding )
 306  
                 {
 307  0
                     ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( 
 308  0
                         aValue, aKey );
 309  0
                 } 
 310  
                 else
 311  
                 {
 312  0
                     handleTakeValueForUnboundKey( anObject, aValue, aKey );   
 313  
                 }
 314  0
             }
 315  
             
 316  0
         }
 317  
     
 318  
         /**
 319  
         * Returns the value for the private field that 
 320  
         * corresponds to the specified property on
 321  
         * the specified object.
 322  
         *
 323  
         * This implementation currently calls valueForKey,
 324  
         * because java security currently prevents us from 
 325  
         * accessing the fields of another object.
 326  
         */
 327  
         static public Object storedValueForKey( 
 328  
             Object anObject, String aKey )
 329  
         {
 330  
             //TODO: this currently just calls valueForKey
 331  0
             return valueForKey( anObject, aKey );
 332  
         }
 333  
     
 334  
         /**
 335  
         * Sets the the private field that corresponds to the 
 336  
         * specified property to the specified value on the
 337  
         * specified object.
 338  
         *
 339  
         * This implementation currently calls takeValueForKey,
 340  
         * because java security currently prevents us from 
 341  
         * accessing the fields of another object.
 342  
         */
 343  
         static public void takeStoredValueForKey( 
 344  
             Object anObject, Object aValue, String aKey )
 345  
         {
 346  
             //TODO: this currently just calls takeValueForKey
 347  0
             takeValueForKey( anObject, aValue, aKey );
 348  0
         }
 349  
     
 350  
         /**
 351  
         * Called by valueForKey when the specified key is
 352  
         * not found on the specified object, if that object
 353  
         * does not implement NSKeyValueCoding.
 354  
         *
 355  
         * This implementation throws a WotonomyException.
 356  
         */
 357  
         static public Object handleQueryWithUnboundKey( 
 358  
             Object anObject, String aKey )
 359  
         {
 360  0
             throw new WotonomyException(   
 361  0
                 "Key not found for object: " 
 362  0
                 + aKey + " : " + anObject );
 363  
         }
 364  
     
 365  
         /**
 366  
         * Called by takeValueForKey when the specified key
 367  
         * is not found on the specified object, if that object
 368  
         * does not implement NSKeyValueCoding.
 369  
         *
 370  
         * This implementation throws a WotonomyException.
 371  
         */
 372  
         static public void handleTakeValueForUnboundKey( 
 373  
             Object anObject, Object aValue, String aKey )
 374  
         {
 375  0
             throw new WotonomyException(   
 376  0
                 "Key not found for object while setting value: " 
 377  0
                 + aKey + " : " + anObject + " : " + aValue );
 378  
         }
 379  
     
 380  
         /**
 381  
         * Called by takeValueForKey when the type of the
 382  
         * specified key is not allowed to be null, as is
 383  
         * the case with primitive types, if the specified
 384  
         * object does not implement NSKeyValueCoding.  
 385  
         *
 386  
         * This implementation throws a WotonomyException.
 387  
         */
 388  
         static public void unableToSetNullForKey( 
 389  
             Object anObject, String aKey )
 390  
         {
 391  0
             throw new WotonomyException(   
 392  0
                 "Tried to key on object to null: " 
 393  0
                 + aKey + " : " + anObject );
 394  
         }
 395  
     }
 396  
 
 397  
         public class Null {
 398  
                 public Null() {
 399  0
                         super();
 400  0
                 }
 401  
 
 402  
                 public String toString() {
 403  0
                         return "<null>";
 404  
                 }
 405  
         }
 406  
 }
 407  
 
 408  
 /*
 409  
  * $Log$
 410  
  * Revision 1.2  2006/02/16 13:15:00  cgruber
 411  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 412  
  *
 413  
  * Revision 1.3  2003/08/07 02:43:56  chochos
 414  
  * added NullValue, which points to a Null instance.
 415  
  *
 416  
  * Revision 1.2  2003/01/18 23:30:42  mpowers
 417  
  * WODisplayGroup now compiles.
 418  
  *
 419  
  * Revision 1.1  2003/01/17 14:40:49  mpowers
 420  
  * Adding files to fix build.
 421  
  *
 422  
  * Revision 1.2  2001/03/28 16:12:30  mpowers
 423  
  * Documented interface.
 424  
  *
 425  
  * Revision 1.1  2001/03/27 23:25:05  mpowers
 426  
  * Contributing interface, no docs yet.
 427  
  *
 428  
  *
 429  
  */
 430  
     
 431