|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
ListenerMethodInvokerImpl.java | 100% | 100% | 100% | 100% |
|
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;
|
|
18 |
import java.lang.reflect.Method;
|
|
19 |
|
|
20 |
import org.apache.hivemind.ApplicationRuntimeException;
|
|
21 |
import org.apache.hivemind.util.Defense;
|
|
22 |
import org.apache.tapestry.IRequestCycle;
|
|
23 |
import org.apache.tapestry.Tapestry;
|
|
24 |
|
|
25 |
/**
|
|
26 |
* Logic for mapping a listener method name to an actual method invocation; this may require a
|
|
27 |
* little searching to find the correct version of the method, based on the number of parameters to
|
|
28 |
* the method (there's a lot of flexibility in terms of what methods may be considered a listener
|
|
29 |
* method).
|
|
30 |
*
|
|
31 |
* @author Howard M. Lewis Ship
|
|
32 |
* @since 4.0
|
|
33 |
*/
|
|
34 |
public class ListenerMethodInvokerImpl implements ListenerMethodInvoker |
|
35 |
{ |
|
36 |
/**
|
|
37 |
* Methods with a name appropriate for this class, sorted into descending order by number of
|
|
38 |
* parameters.
|
|
39 |
*/
|
|
40 |
|
|
41 |
private final Method[] _methods;
|
|
42 |
|
|
43 |
/**
|
|
44 |
* The listener method name, used in some error messages.
|
|
45 |
*/
|
|
46 |
|
|
47 |
private final String _name;
|
|
48 |
|
|
49 | 1236 |
public ListenerMethodInvokerImpl(String name, Method[] methods)
|
50 |
{ |
|
51 | 1236 |
Defense.notNull(name, "name");
|
52 | 1236 |
Defense.notNull(methods, "methods");
|
53 |
|
|
54 | 1236 |
_name = name; |
55 | 1236 |
_methods = methods; |
56 |
} |
|
57 |
|
|
58 | 59 |
public void invokeListenerMethod(Object target, IRequestCycle cycle) |
59 |
{ |
|
60 | 59 |
Object[] listenerParameters = cycle.getListenerParameters(); |
61 |
|
|
62 |
// method(parameters)
|
|
63 | 59 |
if (searchAndInvoke(target, false, true, cycle, listenerParameters)) |
64 | 2 |
return;
|
65 |
|
|
66 |
// method(IRequestCycle, parameters)
|
|
67 | 56 |
if (searchAndInvoke(target, true, true, cycle, listenerParameters)) |
68 | 41 |
return;
|
69 |
|
|
70 |
// method()
|
|
71 | 13 |
if (searchAndInvoke(target, false, false, cycle, listenerParameters)) |
72 | 1 |
return;
|
73 |
|
|
74 |
// method(IRequestCycle)
|
|
75 | 10 |
if (searchAndInvoke(target, true, false, cycle, listenerParameters)) |
76 | 9 |
return;
|
77 |
|
|
78 | 1 |
throw new ApplicationRuntimeException(ListenerMessages.noListenerMethodFound( |
79 |
_name, |
|
80 |
listenerParameters, |
|
81 |
target), target, null, null); |
|
82 |
} |
|
83 |
|
|
84 | 138 |
private boolean searchAndInvoke(Object target, boolean includeCycle, boolean includeParameters, |
85 |
IRequestCycle cycle, Object[] listenerParameters) |
|
86 |
{ |
|
87 | 138 |
int listenerParameterCount = Tapestry.size(listenerParameters);
|
88 | 138 |
int methodParameterCount = includeParameters ? listenerParameterCount : 0;
|
89 |
|
|
90 | 138 |
if (includeCycle)
|
91 | 66 |
methodParameterCount++; |
92 |
|
|
93 | 138 |
for (int i = 0; i < _methods.length; i++) |
94 |
{ |
|
95 | 139 |
Method m = _methods[i]; |
96 |
|
|
97 |
// Since the methods are sorted, descending, by parameter count,
|
|
98 |
// there's no point in searching past that point.
|
|
99 |
|
|
100 | 139 |
Class[] parameterTypes = m.getParameterTypes(); |
101 |
|
|
102 | 139 |
if (parameterTypes.length < methodParameterCount)
|
103 | 20 |
break;
|
104 |
|
|
105 | 119 |
if (parameterTypes.length != methodParameterCount)
|
106 | 56 |
continue;
|
107 |
|
|
108 | 63 |
boolean firstIsCycle = parameterTypes.length > 0
|
109 |
&& parameterTypes[0] == IRequestCycle.class;
|
|
110 |
|
|
111 |
// When we're searching for a "traditional" style listener method,
|
|
112 |
// one which takes the request cycle as its first parameter,
|
|
113 |
// then check that first parameter is *exactly* IRequestCycle
|
|
114 |
// On the other hand, if we're looking for new style
|
|
115 |
// listener methods (includeCycle is false), then ignore
|
|
116 |
// any methods whose first parameter is the request cycle
|
|
117 |
// (we'll catch those in a later search).
|
|
118 |
|
|
119 | 63 |
if (includeCycle != firstIsCycle)
|
120 | 5 |
continue;
|
121 |
|
|
122 | 58 |
invokeListenerMethod( |
123 |
m, |
|
124 |
target, |
|
125 |
includeCycle, |
|
126 |
includeParameters, |
|
127 |
cycle, |
|
128 |
listenerParameters); |
|
129 |
|
|
130 | 53 |
return true; |
131 |
} |
|
132 |
|
|
133 | 80 |
return false; |
134 |
} |
|
135 |
|
|
136 | 58 |
private void invokeListenerMethod(Method listenerMethod, Object target, boolean includeCycle, |
137 |
boolean includeParameters, IRequestCycle cycle, Object[] listenerParameters)
|
|
138 |
{ |
|
139 | 58 |
Object[] parameters = new Object[listenerMethod.getParameterTypes().length];
|
140 | 58 |
int cursor = 0;
|
141 |
|
|
142 | 58 |
if (includeCycle)
|
143 | 52 |
parameters[cursor++] = cycle; |
144 |
|
|
145 | 58 |
if (includeParameters)
|
146 | 46 |
for (int i = 0; i < Tapestry.size(listenerParameters); i++) |
147 | 26 |
parameters[cursor++] = listenerParameters[i]; |
148 |
|
|
149 | 58 |
try
|
150 |
{ |
|
151 | 58 |
invokeTargetMethod(target, listenerMethod, parameters); |
152 |
} |
|
153 |
catch (InvocationTargetException ex)
|
|
154 |
{ |
|
155 | 4 |
Throwable targetException = ex.getTargetException(); |
156 |
|
|
157 | 4 |
if (targetException instanceof ApplicationRuntimeException) |
158 | 3 |
throw (ApplicationRuntimeException) targetException;
|
159 |
|
|
160 | 1 |
throw new ApplicationRuntimeException(ListenerMessages.listenerMethodFailure( |
161 |
listenerMethod, |
|
162 |
target, |
|
163 |
targetException), target, null, targetException);
|
|
164 |
} |
|
165 |
catch (Exception ex)
|
|
166 |
{ |
|
167 | 1 |
throw new ApplicationRuntimeException(ListenerMessages.listenerMethodFailure( |
168 |
listenerMethod, |
|
169 |
target, |
|
170 |
ex), target, null, ex);
|
|
171 |
|
|
172 |
} |
|
173 |
} |
|
174 |
|
|
175 |
/**
|
|
176 |
* Provided as a hook so that subclasses can perform any additional work before or after
|
|
177 |
* invoking the listener method.
|
|
178 |
*/
|
|
179 |
|
|
180 | 58 |
protected void invokeTargetMethod(Object target, Method listenerMethod, Object[] parameters) |
181 |
throws IllegalAccessException, InvocationTargetException
|
|
182 |
{ |
|
183 | 58 |
listenerMethod.invoke(target, parameters); |
184 |
} |
|
185 |
} |
|