KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > util > Invocation


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20
21 package org.apache.cayenne.util;
22
23 import java.lang.ref.WeakReference JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26
27 import org.apache.cayenne.CayenneRuntimeException;
28
29 /**
30  * Invocation represents a dynamic method invocation bound to a specific target. The
31  * target is kept with a WeakReference and can therefore be reclaimed by the Garbage
32  * Collector.
33  *
34  * @author Holger Hoffstaette
35  * @author Dirk Olmes
36  */

37 public class Invocation extends Object JavaDoc {
38
39     private WeakReference JavaDoc _target;
40     private Method JavaDoc _method;
41     private Class JavaDoc[] _parameterTypes;
42
43     /**
44      * Prevent use of empty default constructor
45      */

46     private Invocation() {
47     }
48
49     /**
50      * Constructor for an Invocation without arguments in the target's method.
51      *
52      * @see #Invocation(Object, String, Class[])
53      */

54     public Invocation(Object JavaDoc target, String JavaDoc methodName) throws NoSuchMethodException JavaDoc {
55         this(target, methodName, (Class JavaDoc[]) null);
56     }
57
58     /**
59      * Constructor for an Invocation with a single argument in the target's method.
60      *
61      * @see #Invocation(Object, String, Class[])
62      */

63     public Invocation(Object JavaDoc target, String JavaDoc methodName, Class JavaDoc parameterType)
64             throws NoSuchMethodException JavaDoc {
65         this(target, methodName, new Class JavaDoc[] {
66             parameterType
67         });
68     }
69
70     /**
71      * Constructor for an Invocation with arbitrary arguments in the target's method.
72      *
73      * @param target
74      * @param methodName
75      * @param parameterTypes
76      * @throws NoSuchMethodException if <code>methodName</code> could not be found in
77      * the target
78      * @throws IllegalArgumentException if target or methodName are <code>null</code>,
79      * or parameterTypes is empty or contains <code>null</code> elements
80      */

81     public Invocation(Object JavaDoc target, String JavaDoc methodName, Class JavaDoc[] parameterTypes)
82             throws NoSuchMethodException JavaDoc {
83         super();
84
85         if (target == null) {
86             throw new IllegalArgumentException JavaDoc("target argument must not be null");
87         }
88
89         if (methodName == null) {
90             throw new IllegalArgumentException JavaDoc("method name must not be null");
91         }
92
93         if (parameterTypes != null) {
94             if (parameterTypes.length > 0) {
95                 for (int i = 0; i < parameterTypes.length; i++) {
96                     if (parameterTypes[i] == null) {
97                         throw new IllegalArgumentException JavaDoc("parameter type["
98                                 + i
99                                 + "] must not be null");
100                     }
101                 }
102             }
103             else {
104                 throw new IllegalArgumentException JavaDoc("parameter types must not be empty");
105             }
106         }
107
108         // allow access to public methods of inaccessible classes, if such methods were
109
// declared in a public interface
110

111         _method = lookupMethodInHierarchy(target.getClass(), methodName, parameterTypes);
112
113         if (_method == null) {
114             throw new NoSuchMethodException JavaDoc("No such method: "
115                     + target.getClass().getName()
116                     + "."
117                     + methodName);
118         }
119
120         if (!Util.isAccessible(_method)) {
121             _method.setAccessible(true);
122         }
123
124         _parameterTypes = parameterTypes;
125         _target = new WeakReference JavaDoc(target);
126     }
127
128     Method JavaDoc lookupMethodInHierarchy(
129             Class JavaDoc objectClass,
130             String JavaDoc methodName,
131             Class JavaDoc[] parameterTypes) throws SecurityException JavaDoc, NoSuchMethodException JavaDoc {
132
133         try {
134             return objectClass.getDeclaredMethod(methodName, parameterTypes);
135         }
136         catch (NoSuchMethodException JavaDoc e) {
137
138             Class JavaDoc superClass = objectClass.getSuperclass();
139             if (superClass == null || superClass.getName().equals(Object JavaDoc.class.getName())) {
140                 throw e;
141             }
142
143             return lookupMethodInHierarchy(superClass, methodName, parameterTypes);
144         }
145     }
146
147     /**
148      * Invoke the target's method without any arguments.
149      *
150      * @see #fire(Object[])
151      */

152     public boolean fire() {
153         return this.fire(null);
154     }
155
156     /**
157      * Invoke the target's method with a single argument.
158      *
159      * @param argument an object passed to the target's method
160      * @see #fire(Object[])
161      */

162     public boolean fire(Object JavaDoc argument) {
163         return this.fire(new Object JavaDoc[] {
164             argument
165         });
166     }
167
168     /**
169      * Invoke the target's method with an arbitrary number of arguments. The number of
170      * arguments must be consistent with the arguments given at construction time of this
171      * Invocation.
172      *
173      * @param arguments an array of objects passed to the target's method
174      * @return <code>true</code> if invocation of the method succeeded, otherwise
175      * <code>false</code>.
176      * @throws IllegalArgumentException if the passed arguments are inconsistent with the
177      * arguments passed to this instance's constructor
178      * @see #fire(Object[])
179      */

180     public boolean fire(Object JavaDoc[] arguments) {
181
182         if (_parameterTypes == null) {
183             if (arguments != null) {
184                 throw new IllegalArgumentException JavaDoc("arguments unexpectedly != null");
185             }
186         }
187         else if (arguments == null) {
188             throw new IllegalArgumentException JavaDoc("arguments must not be null");
189         }
190         else if (_parameterTypes.length != arguments.length) {
191             throw new IllegalArgumentException JavaDoc(
192                     "inconsistent number of arguments: expected"
193                             + _parameterTypes.length
194                             + ", got "
195                             + arguments.length);
196         }
197
198         Object JavaDoc currentTarget = _target.get();
199         if (currentTarget == null) {
200             return false;
201         }
202
203         try {
204             _method.invoke(currentTarget, arguments);
205             return true;
206         }
207         catch (InvocationTargetException JavaDoc ite) {
208             // this is the only type of exception that can be rethrown, since
209
// listener can have a valid need to respond to an event with exception,
210
// and this does not indicate that it is being in invalid state
211

212             Throwable JavaDoc cause = ite.getCause();
213             if (cause instanceof RuntimeException JavaDoc) {
214                 throw (RuntimeException JavaDoc) cause;
215             }
216             else {
217                 throw new CayenneRuntimeException(cause);
218             }
219         }
220         catch (Exception JavaDoc ex) {
221             // all other exceptions indicate propblems with the listener,
222
// so return invalid status
223
return false;
224         }
225     }
226
227     /**
228      * @see Object#equals(java.lang.Object)
229      */

230     public boolean equals(Object JavaDoc obj) {
231         if ((obj != null) && (obj.getClass().equals(this.getClass()))) {
232             Invocation otherInvocation = (Invocation) obj;
233             if (_method.equals(otherInvocation.getMethod())) {
234                 Object JavaDoc otherTarget = otherInvocation.getTarget();
235                 Object JavaDoc target = _target.get();
236
237                 if ((target == null) && (otherTarget == null)) {
238                     return true;
239                 }
240
241                 if ((target == null) && (otherTarget != null)) {
242                     return false;
243                 }
244
245                 if (target != null) {
246                     return target.equals(otherTarget);
247                 }
248             }
249
250             return false;
251         }
252         else {
253             return super.equals(obj);
254         }
255     }
256
257     /**
258      * @see Object#hashCode()
259      */

260     public int hashCode() {
261         // IMPORTANT: DO NOT include Invocation target into whatever
262
// algorithm is used to compute hashCode, since it is using a
263
// WeakReference and can be released at a later time, altering
264
// hashCode, and breaking collections using Invocation as a key
265
// (e.g. event DispatchQueue)
266

267         // TODO: use Jakarta commons HashBuilder
268
int hash = 42, hashMultiplier = 59;
269         return hash * hashMultiplier + _method.hashCode();
270     }
271
272     /**
273      * @return the method to be invoked on the target
274      */

275     public Method JavaDoc getMethod() {
276         return _method;
277     }
278
279     /**
280      * @return the target object of this Invocation
281      */

282     public Object JavaDoc getTarget() {
283         return _target.get();
284     }
285
286     /**
287      * @return an array of Classes describing the target method's parameters
288      */

289     public Class JavaDoc[] getParameterTypes() {
290         return _parameterTypes;
291     }
292
293 }
294
Popular Tags