1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 public Surrogate()
60 {
61 delegates = null;
62 defaultValue = null;
63 }
64
65 /***
66 * Constructor specifying a delegate object.
67 */
68 public Surrogate( Object[] aDelegateArray )
69 {
70 setDelegates( aDelegateArray );
71 }
72
73 /***
74 * Constructor specifying a default value.
75 */
76 public Surrogate( Object aDefault )
77 {
78 setDefaultValue( aDefault );
79 }
80
81 /***
82 * Constructor specifying a delegate object and a default value.
83 */
84 public Surrogate( Object[] aDelegateArray, Object aDefault )
85 {
86 setDelegates( aDelegateArray );
87 setDefaultValue( aDefault );
88 }
89
90 /***
91 * Returns the first delegate object, or null if no delegates exist.
92 */
93 public Object getDelegate()
94 {
95 if ( delegates == null ) return null;
96 if ( delegates.length == 0 ) return null;
97 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 setDelegates( new Object[] { aDelegate } );
107 }
108
109 /***
110 * Returns the list of delegates in the order in which
111 * they are consulted.
112 */
113 public Object[] getDelegates()
114 {
115 if ( delegates == null ) delegates = new Object[0];
116 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 delegates = aDelegateArray;
126 }
127
128 /***
129 * Returns the current default value, or null if no default exists.
130 */
131 public Object getDefaultValue()
132 {
133 return defaultValue;
134 }
135
136 /***
137 * Sets the default value.
138 */
139 public void setDefaultValue( Object aDefault )
140 {
141 defaultValue = aDefault;
142 }
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 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 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
171 int i, j;
172 Object[] list = getDelegates();
173 String[] properties;
174 for ( i = 0; i < list.length; i++ )
175 {
176
177 properties =
178 Introspector.getReadPropertiesForObject( list[i] );
179 for ( j = 0; j < properties.length; j++ )
180 {
181
182 if ( properties[j].equals( aKey ) )
183 {
184
185 return Introspector.get( list[i], aKey.toString() );
186 }
187 }
188 }
189
190
191 Object result = directGet( aKey );
192 if ( result == null )
193 {
194
195 result = getDefaultValue();
196 }
197 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
208 int i, j;
209 Object[] list = getDelegates();
210 String[] properties;
211 for ( i = 0; i < list.length; i++ )
212 {
213
214 properties =
215 Introspector.getWritePropertiesForObject( list[i] );
216 for ( j = 0; j < properties.length; j++ )
217 {
218
219 if ( properties[j].equals( aKey ) )
220 {
221
222 EOObserverCenter.notifyObserversObjectWillChange( list[i] );
223 return Introspector.set( list[i], aKey.toString(), aValue );
224 }
225 }
226 }
227
228
229 EOObserverCenter.notifyObserversObjectWillChange( this );
230 return directPut( aKey, aValue );
231 }
232
233 /***
234 * Overridden to compare by reference.
235 */
236 public boolean equals( Object anObject )
237 {
238 return ( this == anObject );
239 }
240
241 }
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259