1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.wotonomy.foundation;
20
21 import java.io.Serializable;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.util.Comparator;
25
26 import net.wotonomy.foundation.internal.PropertyComparator;
27
28 /***
29 * A pure java implementation of NSSelector.
30 *
31 * @author michael@mpowers.net
32 * @author $Author: cgruber $
33 * @version $Revision: 892 $
34 */
35 public class NSSelector implements Comparator, Serializable
36 {
37 protected NSMutableDictionary methodMap;
38 protected String methodName;
39 protected Class[] parameterTypes;
40
41 /***
42 * A marker to indicate object not found.
43 */
44 protected static final String NOT_FOUND = "NOT_FOUND";
45
46 /***
47 * Saves creating a new class array for parameterless method invocation.
48 */
49 protected static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
50
51 /***
52 * Saves creating a new object array for parameterless method invocation.
53 */
54 protected static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
55
56 /***
57 * Constructor specifying a method name and an array of parameter types.
58 */
59 public NSSelector (String aMethodName, Class[] aParameterTypeArray)
60 {
61 methodName = aMethodName;
62 parameterTypes = aParameterTypeArray;
63 methodMap = new NSMutableDictionary();
64 }
65
66 /***
67 * Constructor specifying a method name with no parameters.
68 */
69 public NSSelector (String aMethodName)
70 {
71 this( aMethodName, EMPTY_CLASS_ARRAY );
72 }
73
74 /***
75 * Constructor for custom subclasses that implement specific operators
76 * and that do not use dynamic method invocation.
77 */
78 protected NSSelector()
79 {
80 }
81
82 /***
83 * Returns the name of the method.
84 */
85 public String name ()
86 {
87 return methodName;
88 }
89
90 /***
91 * Returns the array of parameter types.
92 */
93 public Class[] parameterTypes ()
94 {
95 return parameterTypes;
96 }
97
98 /***
99 * A String description of this selector.
100 */
101 public String toString ()
102 {
103 StringBuffer result = new StringBuffer();
104 result.append( "[" + getClass().getName() + ": name = " + name() + ", parameter types = [" );
105 if ( parameterTypes != null )
106 {
107 if ( parameterTypes.length > 0 )
108 {
109 result.append( parameterTypes[0].toString() );
110 }
111 for ( int i = 1; i < parameterTypes.length; i++ )
112 {
113 result.append( ", " );
114 result.append( parameterTypes[i].toString() );
115 }
116 }
117 result.append( "] ]" );
118 return result.toString();
119 }
120
121 /***
122 * Returns the appropriate method for the specified class.
123 */
124 public Method methodOnClass (Class aClass)
125 throws NoSuchMethodException
126 {
127 Object result = methodMap.objectForKey( aClass );
128
129 if ( result == null )
130 {
131 result = getMethodForClass( aClass );
132 if ( result == null )
133 {
134 result = NOT_FOUND;
135 }
136 methodMap.setObjectForKey( result, aClass );
137 }
138
139 if ( result == NOT_FOUND )
140 {
141 throw new NoSuchMethodException();
142 }
143 return (Method) result;
144 }
145
146 /***
147 * Returns the appropriate method, or null if not found.
148 */
149 private Method getMethodForClass( Class aClass )
150 {
151 Method[] methods = aClass.getMethods();
152 for ( int i = 0; i < methods.length; i++ )
153 {
154 if ( methods[i].getName().equals( name() ) )
155 {
156 Class[] params = methods[i].getParameterTypes();
157 if ( params.length == parameterTypes.length )
158 {
159 boolean pass = true;
160 for ( int j = 0; j < params.length; j++ )
161 {
162 if ( ! params[j].isAssignableFrom( parameterTypes[j] ) )
163 {
164 pass = false;
165 }
166 }
167 if ( pass ) return methods[i];
168 }
169 }
170 }
171 return null;
172 }
173
174 /***
175 * Convenience to get a method for an object.
176 */
177 public Method methodOnObject (Object anObject)
178 throws NoSuchMethodException
179 {
180 Method m = methodOnClass( anObject.getClass() );
181 if ( m == null ) throw new NoSuchMethodException( name() );
182 return m;
183 }
184
185 /***
186 * Returns whether the class implements the method for this selector.
187 */
188 public boolean implementedByClass (Class aClass)
189 {
190 try
191 {
192 methodOnClass( aClass );
193 return true;
194 }
195 catch ( NoSuchMethodException exc )
196 {
197 }
198 return false;
199 }
200
201 /***
202 * Returns whether the object's class implements the method
203 * for this selector.
204 */
205 public boolean implementedByObject (Object anObject)
206 {
207 try
208 {
209 methodOnObject( anObject );
210 return true;
211 }
212 catch ( NoSuchMethodException exc )
213 {
214 }
215 return false;
216 }
217
218 /***
219 * Invokes this selector's method on the specified object
220 * using the specified parameters.
221 */
222 public Object invoke (Object anObject, Object[] parameters)
223 throws IllegalAccessException, IllegalArgumentException,
224 InvocationTargetException, NoSuchMethodException
225 {
226 return methodOnObject( anObject ).invoke( anObject, parameters );
227 }
228
229 /***
230 * Invokes this selector's method on the specified object
231 * with no parameters.
232 */
233 public Object invoke (Object anObject)
234 throws IllegalAccessException, IllegalArgumentException,
235 InvocationTargetException, NoSuchMethodException
236 {
237 return invoke( anObject, EMPTY_OBJECT_ARRAY );
238 }
239
240 /***
241 * Invokes this selector's method on the specified object
242 * with the specified parameter.
243 */
244 public Object invoke (Object anObject, Object aParameter)
245 throws IllegalAccessException, IllegalArgumentException,
246 InvocationTargetException, NoSuchMethodException
247 {
248 return invoke( anObject, new Object[] { aParameter } );
249 }
250
251 /***
252 * Invokes this selector's method on the specified object
253 * using the specified two parameters.
254 */
255 public Object invoke (Object anObject, Object p1, Object p2)
256 throws IllegalAccessException, IllegalArgumentException,
257 InvocationTargetException, NoSuchMethodException
258 {
259 return invoke( anObject, new Object[] { p1, p2 } );
260 }
261
262 /***
263 * Invokes the method with the specified signature on the specified
264 * object using the specified parameters.
265 */
266 public static Object invoke
267 (String methodName, Class[] parameterTypes, Object anObject, Object[] parameters)
268 throws IllegalAccessException, IllegalArgumentException,
269 InvocationTargetException, NoSuchMethodException
270 {
271 return new NSSelector( methodName, parameterTypes ).invoke( anObject, parameters );
272 }
273
274 /***
275 * Invokes the method with the specified signature on the specified object
276 * with no parameters.
277 */
278 public static Object invoke
279 (String methodName, Object anObject)
280 throws IllegalAccessException, IllegalArgumentException,
281 InvocationTargetException, NoSuchMethodException
282 {
283 return NSSelector.invoke(
284 methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY );
285 }
286
287 /***
288 * Invokes the method with the specified signature on the specified
289 * object using the specified parameter.
290 */
291 public static Object invoke
292 (String methodName, Class[] parameterTypes,
293 Object anObject, Object aParameter)
294 throws IllegalAccessException, IllegalArgumentException,
295 InvocationTargetException, NoSuchMethodException
296 {
297 return NSSelector.invoke(
298 methodName, parameterTypes, anObject, new Object[] { aParameter } );
299 }
300
301 /***
302 * Invokes the method with the specified signature on the specified
303 * object using the specified two parameters.
304 */
305 public static Object invoke
306 (String methodName, Class[] parameterTypes,
307 Object anObject, Object p1, Object p2)
308 throws IllegalAccessException, IllegalArgumentException,
309 InvocationTargetException, NoSuchMethodException
310 {
311 return NSSelector.invoke(
312 methodName, parameterTypes, anObject, new Object[] { p1, p2 } );
313 }
314
315
316
317 private Comparator comparator;
318
319 /***
320 * Constructor specifying a method name and a comparator.
321 * This is not in the spec.
322 */
323 public NSSelector (String aMethodName, Comparator aComparator)
324 {
325 this( aMethodName, EMPTY_CLASS_ARRAY );
326 comparator = aComparator;
327 }
328
329 /***
330 * Returns the Comparator used for this selector.
331 * This is not in the spec.
332 */
333 public Comparator comparator()
334 {
335 if ( comparator == null )
336 {
337 comparator = new PropertyComparator( methodName );
338 }
339 return comparator;
340 }
341
342 public int compare(Object o1, Object o2)
343 {
344 if ( comparator == null )
345 {
346 comparator = new PropertyComparator( methodName );
347 }
348 return comparator.compare( o1, o2 );
349 }
350
351 public boolean equals(Object obj)
352 {
353 return ( obj == this );
354 }
355 }
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391