| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| Surrogate |
|
| 1.9333333333333333;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 |