KickJava   Java API By Example, From Geeks To Geeks.

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


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.util;
58
59 import java.lang.ref.WeakReference JavaDoc;
60 import java.lang.reflect.InvocationTargetException JavaDoc;
61 import java.lang.reflect.Method JavaDoc;
62
63 import org.apache.log4j.Logger;
64 import org.objectstyle.cayenne.CayenneRuntimeException;
65
66 /**
67  * Invocation represents a dynamic method invocation bound to a specific target.
68  * The target is kept with a WeakReference and can therefore be reclaimed by the
69  * Garbage Collector.
70  *
71  * @author Holger Hoffstaette
72  * @author Dirk Olmes
73  */

74 public class Invocation extends Object JavaDoc {
75     private static final Logger log = Logger.getLogger(Invocation.class);
76
77     private WeakReference JavaDoc _target;
78     private Method JavaDoc _method;
79     private Class JavaDoc[] _parameterTypes;
80
81     /**
82      * Prevent use of empty default constructor
83      */

84     private Invocation() {
85     }
86
87     /**
88      * Constructor for an Invocation without arguments in the target's method.
89      *
90      * @see #Invocation(Object, String, Class[])
91      */

92     public Invocation(Object JavaDoc target, String JavaDoc methodName) throws NoSuchMethodException JavaDoc {
93         this(target, methodName, (Class JavaDoc[]) null);
94     }
95
96     /**
97      * Constructor for an Invocation with a single argument in the target's
98      * method.
99      *
100      * @see #Invocation(Object, String, Class[])
101      */

102     public Invocation(Object JavaDoc target, String JavaDoc methodName, Class JavaDoc parameterType)
103         throws NoSuchMethodException JavaDoc {
104         this(target, methodName, new Class JavaDoc[] { parameterType });
105     }
106
107     /**
108      * Constructor for an Invocation with arbitrary arguments in the target's
109      * method.
110      *
111      * @param target
112      * @param methodName
113      * @param parameterTypes
114      * @throws NoSuchMethodException if <code>methodName</code> could not be
115      * found in the target
116      * @throws IllegalArgumentException if target or methodName are
117      * <code>null</code>, or parameterTypes is empty or contains
118      * <code>null</code> elements
119      */

120     public Invocation(Object JavaDoc target, String JavaDoc methodName, Class JavaDoc[] parameterTypes)
121         throws NoSuchMethodException JavaDoc {
122         super();
123
124         if (target == null) {
125             throw new IllegalArgumentException JavaDoc("target argument must not be null");
126         }
127
128         if (methodName == null) {
129             throw new IllegalArgumentException JavaDoc("method name must not be null");
130         }
131
132         if (parameterTypes != null) {
133             if (parameterTypes.length > 0) {
134                 for (int i = 0; i < parameterTypes.length; i++) {
135                     if (parameterTypes[i] == null) {
136                         throw new IllegalArgumentException JavaDoc(
137                             "parameter type[" + i + "] must not be null");
138                     }
139                 }
140             }
141             else {
142                 throw new IllegalArgumentException JavaDoc("parameter types must not be empty");
143             }
144         }
145
146         Method JavaDoc method = null;
147
148         // allow access to public methods of inaccessible classes, if such methods were
149
// declared in a public interface
150
Class JavaDoc targetClass = target.getClass();
151         Class JavaDoc[] interfaces = targetClass.getInterfaces();
152         for (int i = 0; i < interfaces.length; i++) {
153             try {
154                 method = interfaces[i].getMethod(methodName, parameterTypes);
155                 break;
156             }
157             catch (NoSuchMethodException JavaDoc ex) {
158                 // ignoring, keep looking
159
}
160         }
161
162         _method =
163             (method != null) ? method : targetClass.getMethod(methodName, parameterTypes);
164         _parameterTypes = parameterTypes;
165         _target = new WeakReference JavaDoc(target);
166     }
167
168     /**
169      * Invoke the target's method without any arguments.
170      *
171      * @see #fire(Object[])
172      */

173     public boolean fire() {
174         return this.fire(null);
175     }
176
177     /**
178      * Invoke the target's method with a single argument.
179      *
180      * @param argument an object passed to the target's method
181      * @see #fire(Object[])
182      */

183     public boolean fire(Object JavaDoc argument) {
184         return this.fire(new Object JavaDoc[] { argument });
185     }
186
187     /**
188      * Invoke the target's method with an arbitrary number of arguments.
189      * The number of arguments must be consistent with the arguments given at
190      * construction time of this Invocation.
191      *
192      * @param arguments an array of objects passed to the target's method
193      *
194      * @return <code>true</code> if invocation of the method succeeded,
195      * otherwise <code>false</code>.
196      *
197      * @throws IllegalArgumentException if the passed arguments are inconsistent
198      * with the arguments passed to this instance's constructor
199      * @see #fire(Object[])
200      */

201     public boolean fire(Object JavaDoc[] arguments) {
202
203         if (_parameterTypes == null) {
204             if (arguments != null) {
205                 throw new IllegalArgumentException JavaDoc("arguments unexpectedly != null");
206             }
207         }
208         else if (arguments == null) {
209             throw new IllegalArgumentException JavaDoc("arguments must not be null");
210         }
211         else if (_parameterTypes.length != arguments.length) {
212             throw new IllegalArgumentException JavaDoc(
213                 "inconsistent number of arguments: expected"
214                     + _parameterTypes.length
215                     + ", got "
216                     + arguments.length);
217         }
218
219         Object JavaDoc currentTarget = _target.get();
220         if (currentTarget == null) {
221             log.info("null target for: " + _method.getName());
222             return false;
223         }
224
225         try {
226             _method.invoke(currentTarget, arguments);
227             return true;
228         }
229         catch (InvocationTargetException JavaDoc ite) {
230             // this is the only type of exception that can be rethrown, since
231
// listener can have a valid need to respond to an event with exception,
232
// and this does not indicate that it is being in invalid state
233

234             Throwable JavaDoc cause = ite.getCause();
235             if (cause instanceof RuntimeException JavaDoc) {
236                 throw (RuntimeException JavaDoc) cause;
237             }
238             else {
239                 throw new CayenneRuntimeException(cause);
240             }
241         }
242         catch (Exception JavaDoc ex) {
243             // all other exceptions indicate propblems with the listener,
244
// so return invalid status
245
log.info("exception firing '" + _method.getName() + "'", ex);
246             return false;
247         }
248     }
249
250     /**
251      * @see Object#equals(java.lang.Object)
252      */

253     public boolean equals(Object JavaDoc obj) {
254         if ((obj != null) && (obj.getClass().equals(this.getClass()))) {
255             Invocation otherInvocation = (Invocation) obj;
256             if (_method.equals(otherInvocation.getMethod())) {
257                 Object JavaDoc otherTarget = otherInvocation.getTarget();
258                 Object JavaDoc target = _target.get();
259
260                 if ((target == null) && (otherTarget == null)) {
261                     return true;
262                 }
263
264                 if ((target == null) && (otherTarget != null)) {
265                     return false;
266                 }
267
268                 if (target != null) {
269                     return target.equals(otherTarget);
270                 }
271             }
272
273             return false;
274         }
275         else {
276             return super.equals(obj);
277         }
278     }
279
280     /**
281      * @see Object#hashCode()
282      */

283     public int hashCode() {
284         // IMPORTANT: DO NOT include Invocation target into whatever
285
// algorithm is used to compute hashCode, since it is using a
286
// WeakReference and can be released at a later time, altering
287
// hashCode, and breaking collections using Invocation as a key
288
// (e.g. event DispatchQueue)
289

290         // TODO: use Jakarta commons HashBuilder
291
int hash = 42, hashMultiplier = 59;
292         return hash * hashMultiplier + _method.hashCode();
293     }
294
295     /**
296      * @return the method to be invoked on the target
297      */

298     public Method JavaDoc getMethod() {
299         return _method;
300     }
301
302     /**
303      * @return the target object of this Invocation
304      */

305     public Object JavaDoc getTarget() {
306         return _target.get();
307     }
308
309     /**
310      * @return an array of Classes describing the target method's parameters
311      */

312     public Class JavaDoc[] getParameterTypes() {
313         return _parameterTypes;
314     }
315
316 }
317
Popular Tags