Coverage Report - net.wotonomy.control.internal.Surrogate
 
Classes in this File Line Coverage Branch Coverage Complexity
Surrogate
0% 
0% 
1.933
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 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.control.internal;
 20  
 
 21  
 import net.wotonomy.control.EOObserverCenter;
 22  
 import net.wotonomy.foundation.NSMutableDictionary;
 23  
 import net.wotonomy.foundation.internal.Introspector;
 24  
 
 25  
 /**
 26  
 * A Surrogate is a special object that can be used in a display
 27  
 * group when you wish to emulate other objects or modify their
 28  
 * behaviors.  Because it is a Map, it makes use of Introspector's
 29  
 * ability to treat keys in a map as if they were properties to
 30  
 * implement the following features.
 31  
 * <ul>
 32  
 * <li>By default, Surrogate works like a Map, and reading and 
 33  
 * writing properties to a Surrogate gets and puts values in the 
 34  
 * Map.</li>
 35  
 * <li>If one or more delegate objects are specified, property keys 
 36  
 * that do not exist in the map are read from and written to the 
 37  
 * delegate object.</li>
 38  
 * <li>If a default value is specified, that value will be returned
 39  
 * for all property reads that do not exist in the map or in the
 40  
 * delegate object.  (Subsequent writes to those properties will
 41  
 * create a key in the map and then subsequent reads will read not
 42  
 * read the default object.)</li>
 43  
 * <li>Subclasses can override the get(Object) method to further
 44  
 * customize the behavior of a Surrogate.
 45  
 * </ul>
 46  
 *
 47  
 * @author michael@mpowers.net
 48  
 * @date $Date: 2006-02-18 22:46:44 +0000 (Sat, 18 Feb 2006) $
 49  
 * @revision $Revision: 900 $
 50  
 */
 51  
 public class Surrogate extends NSMutableDictionary
 52  
 {
 53  
         protected Object[] delegates;
 54  
         protected Object defaultValue;
 55  
         
 56  
         /**
 57  
         * Default constructor with no delegate object and no default value.
 58  
         */
 59  0
         public Surrogate()
 60  0
         {
 61  0
                 delegates = null;
 62  0
                 defaultValue = null;
 63  0
         }
 64  
         
 65  
         /**
 66  
         * Constructor specifying a delegate object.
 67  
         */
 68  0
         public Surrogate( Object[] aDelegateArray )
 69  0
         {
 70  0
                 setDelegates( aDelegateArray );
 71  0
         }
 72  
 
 73  
         /**
 74  
         * Constructor specifying a default value.
 75  
         */
 76  0
         public Surrogate( Object aDefault )
 77  0
         {
 78  0
                 setDefaultValue( aDefault );
 79  0
         }
 80  
 
 81  
         /**
 82  
         * Constructor specifying a delegate object and a default value.
 83  
         */
 84  0
         public Surrogate( Object[] aDelegateArray, Object aDefault )
 85  0
         {
 86  0
                 setDelegates( aDelegateArray );
 87  0
                 setDefaultValue( aDefault );
 88  0
         }
 89  
 
 90  
         /**
 91  
         * Returns the first delegate object, or null if no delegates exist.
 92  
         */
 93  
         public Object getDelegate()
 94  
         {
 95  0
                 if ( delegates == null ) return null;
 96  0
                 if ( delegates.length == 0 ) return null;
 97  0
                 return delegates[0];
 98  
         }
 99  
         
 100  
         /**
 101  
         * Sets the delegate object list to contain only the
 102  
         * specified object.
 103  
         */
 104  
         public void setDelegate( Object aDelegate )
 105  
         {
 106  0
                 setDelegates( new Object[] { aDelegate } );
 107  0
         }
 108  
         
 109  
         /**
 110  
         * Returns the list of delegates in the order in which
 111  
         * they are consulted.
 112  
         */
 113  
         public Object[] getDelegates()
 114  
         {
 115  0
                 if ( delegates == null ) delegates = new Object[0];
 116  0
                 return delegates;        
 117  
         }
 118  
         
 119  
         /**
 120  
         * Sets the list of delegates in the order in which they
 121  
         * will be consulted.
 122  
         */
 123  
         public void setDelegates( Object[] aDelegateArray )
 124  
         {
 125  0
                 delegates = aDelegateArray;
 126  0
         }
 127  
 
 128  
         /**
 129  
         * Returns the current default value, or null if no default exists.
 130  
         */
 131  
         public Object getDefaultValue()
 132  
         {
 133  0
                 return defaultValue;
 134  
         }
 135  
         
 136  
         /**
 137  
         * Sets the default value.
 138  
         */
 139  
         public void setDefaultValue( Object aDefault )
 140  
         {
 141  0
                 defaultValue = aDefault;
 142  0
         }
 143  
         
 144  
         /**
 145  
         * Called by get to retrieve a value from the internal map.
 146  
         * This implementation simply calls super.get().
 147  
         */
 148  
         public Object directGet( Object aKey )
 149  
         {
 150  0
                 return super.get( aKey );        
 151  
         }
 152  
         
 153  
         /**
 154  
         * Called by put to retrieve a value from the internal map.
 155  
         * This implementation simply calls super.put().
 156  
         */
 157  
         public Object directPut( Object aKey, Object aValue )
 158  
         {
 159  0
                 return super.put( aKey, aValue );        
 160  
         }
 161  
         
 162  
         /**
 163  
         * Overridden to consult each delegate before 
 164  
         * checking the internal list of keys.  No matching
 165  
         * key is found, returns the default object, or 
 166  
         * null if no default object exists.
 167  
         */
 168  
         public Object get( Object aKey )
 169  
         {
 170  
                 // check all delegates in order
 171  
                 int i, j;
 172  0
                 Object[] list = getDelegates();
 173  
                 String[] properties;
 174  0
                 for ( i = 0; i < list.length; i++ )
 175  
                 {
 176  
                         // for each delegate
 177  0
                         properties = 
 178  0
                                 Introspector.getReadPropertiesForObject( list[i] );
 179  0
                         for ( j = 0; j < properties.length; j++ )
 180  
                         {
 181  
                                 // if delegate has property
 182  0
                                 if ( properties[j].equals( aKey ) )
 183  
                                 {
 184  
                                         // use this delegate
 185  0
                                         return Introspector.get( list[i], aKey.toString() );        
 186  
                                 }
 187  
                         }
 188  
                 }
 189  
                 
 190  
                 // return from internal map
 191  0
                 Object result = directGet( aKey );
 192  0
                 if ( result == null )
 193  
                 {
 194  
                         // if not in map, return default object
 195  0
                         result = getDefaultValue();
 196  
                 }
 197  0
                 return result;                
 198  
         }
 199  
         
 200  
         /** 
 201  
         * Overridden to attempt to write each delegate, writing to
 202  
         * only the first successful delegate, before storing the 
 203  
         * value in the internal map.
 204  
         */
 205  
         public Object put( Object aKey, Object aValue )
 206  
         {
 207  
                 // check all delegates in order
 208  
                 int i, j;
 209  0
                 Object[] list = getDelegates();
 210  
                 String[] properties;
 211  0
                 for ( i = 0; i < list.length; i++ )
 212  
                 {
 213  
                         // for each delegate
 214  0
                         properties = 
 215  0
                                 Introspector.getWritePropertiesForObject( list[i] );
 216  0
                         for ( j = 0; j < properties.length; j++ )
 217  
                         {
 218  
                                 // if delegate has property
 219  0
                                 if ( properties[j].equals( aKey ) )
 220  
                                 {
 221  
                                         // use this delegate
 222  0
                                         EOObserverCenter.notifyObserversObjectWillChange( list[i] );
 223  0
                                         return Introspector.set( list[i], aKey.toString(), aValue );        
 224  
                                 }
 225  
                         }
 226  
                 }
 227  
                 
 228  
                 // set on internal map
 229  0
                 EOObserverCenter.notifyObserversObjectWillChange( this );
 230  0
                 return directPut( aKey, aValue );
 231  
         }
 232  
 
 233  
         /**
 234  
         * Overridden to compare by reference.
 235  
         */
 236  
         public boolean equals( Object anObject )
 237  
         {
 238  0
                 return ( this == anObject );
 239  
         }
 240  
 
 241  
 }
 242  
 
 243  
 /*
 244  
  * $Log$
 245  
  * Revision 1.1  2006/02/18 22:46:44  cgruber
 246  
  * Add Surrogate map from .util into control's internal package, and fix imports.
 247  
  *
 248  
  * Revision 1.1  2006/02/16 13:22:22  cgruber
 249  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 250  
  *
 251  
  * Revision 1.1.1.1  2000/12/21 15:52:21  mpowers
 252  
  * Contributing wotonomy.
 253  
  *
 254  
  * Revision 1.2  2000/12/20 16:25:48  michael
 255  
  * Added log to all files.
 256  
  *
 257  
  *
 258  
  */
 259