KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > listener > ListenerMethodInvokerImpl


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

15 package org.apache.tapestry.listener;
16
17 import java.lang.reflect.InvocationTargetException JavaDoc;
18 import java.lang.reflect.Method JavaDoc;
19
20 import org.apache.hivemind.ApplicationRuntimeException;
21 import org.apache.hivemind.util.Defense;
22 import org.apache.tapestry.IPage;
23 import org.apache.tapestry.IRequestCycle;
24 import org.apache.tapestry.Tapestry;
25
26 /**
27  * Logic for mapping a listener method name to an actual method invocation; this may require a
28  * little searching to find the correct version of the method, based on the number of parameters to
29  * the method (there's a lot of flexibility in terms of what methods may be considered a listener
30  * method).
31  *
32  * @author Howard M. Lewis Ship
33  * @since 4.0
34  */

35 public class ListenerMethodInvokerImpl implements ListenerMethodInvoker
36 {
37     /**
38      * Methods with a name appropriate for this class, sorted into descending order by number of
39      * parameters.
40      */

41
42     private final Method JavaDoc[] _methods;
43
44     /**
45      * The listener method name, used in some error messages.
46      */

47
48     private final String JavaDoc _name;
49
50     public ListenerMethodInvokerImpl(String JavaDoc name, Method JavaDoc[] methods)
51     {
52         Defense.notNull(name, "name");
53         Defense.notNull(methods, "methods");
54
55         _name = name;
56         _methods = methods;
57     }
58
59     public void invokeListenerMethod(Object JavaDoc target, IRequestCycle cycle)
60     {
61         Object JavaDoc[] listenerParameters = cycle.getListenerParameters();
62
63         // method(parameters)
64
if (searchAndInvoke(target, false, true, cycle, listenerParameters))
65             return;
66
67         // method(IRequestCycle, parameters)
68
if (searchAndInvoke(target, true, true, cycle, listenerParameters))
69             return;
70
71         // method()
72
if (searchAndInvoke(target, false, false, cycle, listenerParameters))
73             return;
74
75         // method(IRequestCycle)
76
if (searchAndInvoke(target, true, false, cycle, listenerParameters))
77             return;
78
79         throw new ApplicationRuntimeException(ListenerMessages.noListenerMethodFound(
80                 _name,
81                 listenerParameters,
82                 target), target, null, null);
83     }
84
85     private boolean searchAndInvoke(Object JavaDoc target, boolean includeCycle, boolean includeParameters,
86             IRequestCycle cycle, Object JavaDoc[] listenerParameters)
87     {
88         int listenerParameterCount = Tapestry.size(listenerParameters);
89         int methodParameterCount = includeParameters ? listenerParameterCount : 0;
90
91         if (includeCycle)
92             methodParameterCount++;
93
94         for (int i = 0; i < _methods.length; i++)
95         {
96             Method JavaDoc m = _methods[i];
97
98             // Since the methods are sorted, descending, by parameter count,
99
// there's no point in searching past that point.
100

101             Class JavaDoc[] parameterTypes = m.getParameterTypes();
102
103             if (parameterTypes.length < methodParameterCount)
104                 break;
105
106             if (parameterTypes.length != methodParameterCount)
107                 continue;
108
109             boolean firstIsCycle = parameterTypes.length > 0
110                     && parameterTypes[0] == IRequestCycle.class;
111
112             // When we're searching for a "traditional" style listener method,
113
// one which takes the request cycle as its first parameter,
114
// then check that first parameter is *exactly* IRequestCycle
115
// On the other hand, if we're looking for new style
116
// listener methods (includeCycle is false), then ignore
117
// any methods whose first parameter is the request cycle
118
// (we'll catch those in a later search).
119

120             if (includeCycle != firstIsCycle)
121                 continue;
122
123             invokeListenerMethod(
124                     m,
125                     target,
126                     includeCycle,
127                     includeParameters,
128                     cycle,
129                     listenerParameters);
130
131             return true;
132         }
133
134         return false;
135     }
136
137     private void invokeListenerMethod(Method JavaDoc listenerMethod, Object JavaDoc target, boolean includeCycle,
138             boolean includeParameters, IRequestCycle cycle, Object JavaDoc[] listenerParameters)
139     {
140         Object JavaDoc[] parameters = new Object JavaDoc[listenerMethod.getParameterTypes().length];
141         int cursor = 0;
142
143         if (includeCycle)
144             parameters[cursor++] = cycle;
145
146         if (includeParameters)
147             for (int i = 0; i < Tapestry.size(listenerParameters); i++)
148                 parameters[cursor++] = listenerParameters[i];
149
150         try
151         {
152             Object JavaDoc methodResult = invokeTargetMethod(target, listenerMethod, parameters);
153
154             // void methods return null
155

156             if (methodResult == null)
157                 return;
158
159             // The method scanner, inside ListenerMapSourceImpl,
160
// ensures that only methods that return void, String,
161
// or assignable to IPage are considered.
162

163             if (methodResult instanceof String JavaDoc)
164             {
165                 cycle.activate((String JavaDoc) methodResult);
166                 return;
167             }
168
169             cycle.activate((IPage) methodResult);
170         }
171         catch (InvocationTargetException JavaDoc ex)
172         {
173             Throwable JavaDoc targetException = ex.getTargetException();
174
175             if (targetException instanceof ApplicationRuntimeException)
176                 throw (ApplicationRuntimeException) targetException;
177
178             throw new ApplicationRuntimeException(ListenerMessages.listenerMethodFailure(
179                     listenerMethod,
180                     target,
181                     targetException), target, null, targetException);
182         }
183         catch (Exception JavaDoc ex)
184         {
185             throw new ApplicationRuntimeException(ListenerMessages.listenerMethodFailure(
186                     listenerMethod,
187                     target,
188                     ex), target, null, ex);
189
190         }
191     }
192
193     /**
194      * Provided as a hook so that subclasses can perform any additional work before or after
195      * invoking the listener method.
196      */

197
198     protected Object JavaDoc invokeTargetMethod(Object JavaDoc target, Method JavaDoc listenerMethod, Object JavaDoc[] parameters)
199             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc
200     {
201         return listenerMethod.invoke(target, parameters);
202     }
203 }
Popular Tags