1 package org.apache.turbine.modules;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.annotation.Annotation;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.util.Arrays;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentMap;
28
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.fulcrum.parser.ParameterParser;
31 import org.apache.fulcrum.parser.ValueParser.URLCaseFolding;
32 import org.apache.logging.log4j.LogManager;
33 import org.apache.logging.log4j.Logger;
34 import org.apache.turbine.Turbine;
35 import org.apache.turbine.TurbineConstants;
36 import org.apache.turbine.annotation.AnnotationProcessor;
37 import org.apache.turbine.annotation.TurbineActionEvent;
38 import org.apache.turbine.annotation.TurbineConfiguration;
39 import org.apache.turbine.pipeline.PipelineData;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 public abstract class ActionEvent implements Action
87 {
88
89 protected Logger log = LogManager.getLogger(this.getClass());
90
91
92 protected static final String BUTTON = "eventSubmit_";
93
94 protected static final int BUTTON_LENGTH = BUTTON.length();
95
96 protected static final String DEFAULT_METHOD = "doPerform";
97
98 protected static final String METHOD_NAME_PREFIX = "do";
99
100 protected static final int METHOD_NAME_LENGTH = METHOD_NAME_PREFIX.length();
101
102 protected static final int LENGTH = BUTTON.length();
103
104
105
106
107
108 @TurbineConfiguration( TurbineConstants.ACTION_EVENTSUBMIT_NEEDSVALUE_KEY )
109 private boolean submitValueKey = TurbineConstants.ACTION_EVENTSUBMIT_NEEDSVALUE_DEFAULT;
110
111
112
113
114
115
116 @TurbineConfiguration( TurbineConstants.ACTION_EVENT_BUBBLE_EXCEPTION_UP )
117 protected boolean bubbleUpException = TurbineConstants.ACTION_EVENT_BUBBLE_EXCEPTION_UP_DEFAULT;
118
119
120
121
122 private ConcurrentMap<String, Method> methodCache = new ConcurrentHashMap<String, Method>();
123
124
125
126
127
128
129
130
131
132
133
134 protected Method getMethod(String name, Class<?>[] signature, ParameterParser pp) throws NoSuchMethodException
135 {
136 StringBuilder cacheKey = new StringBuilder(name);
137 for (Class<?> clazz : signature)
138 {
139 cacheKey.append(':').append(clazz.getCanonicalName());
140 }
141
142 Method method = this.methodCache.get(cacheKey.toString());
143
144 if (method == null)
145 {
146
147 Method[] methods = getClass().getMethods();
148
149 methodLoop:
150 for (Method m : methods)
151 {
152 Annotation[] annotations = AnnotationProcessor.getAnnotations(m);
153 for (Annotation a : annotations)
154 {
155 if (a instanceof TurbineActionEvent)
156 {
157 TurbineActionEvent../org/apache/turbine/annotation/TurbineActionEvent.html#TurbineActionEvent">TurbineActionEvent tae = (TurbineActionEvent) a;
158 if (name.equals(pp.convert(tae.value()))
159 && Arrays.equals(signature, m.getParameterTypes()))
160 {
161 method = m;
162 break methodLoop;
163 }
164 }
165 }
166 }
167
168
169 if (method == null)
170 {
171 String tmp = name.toLowerCase().substring(METHOD_NAME_LENGTH);
172 method = getClass().getMethod(METHOD_NAME_PREFIX + StringUtils.capitalize(tmp), signature);
173 }
174
175 Method oldMethod = this.methodCache.putIfAbsent(cacheKey.toString(), method);
176 if (oldMethod != null)
177 {
178 method = oldMethod;
179 }
180 }
181
182 return method;
183 }
184
185
186
187
188
189
190
191
192
193 @Override
194 public void doPerform(PipelineData pipelineData)
195 throws Exception
196 {
197 ParameterParser pp = pipelineData.get(Turbine.class, ParameterParser.class);
198 executeEvents(pp, new Class<?>[]{ PipelineData.class }, new Object[]{ pipelineData });
199 }
200
201
202
203
204
205
206
207
208
209
210 protected void executeEvents(ParameterParser pp, Class<?>[] signature, Object[] parameters)
211 throws Exception
212 {
213
214 String theButton = null;
215
216 String button = pp.convert(BUTTON);
217 String key = null;
218
219
220 for (String k : pp)
221 {
222 key = k;
223 if (key.startsWith(button))
224 {
225 if (considerKey(key, pp))
226 {
227 theButton = key;
228 break;
229 }
230 }
231 }
232
233 if (theButton == null)
234 {
235 theButton = BUTTON + DEFAULT_METHOD;
236 key = null;
237 }
238
239 theButton = formatString(theButton, pp);
240 Method method = null;
241
242 try
243 {
244 method = getMethod(theButton, signature, pp);
245 }
246 catch (NoSuchMethodException e)
247 {
248 method = getMethod(DEFAULT_METHOD, signature, pp);
249 }
250 finally
251 {
252 if (key != null)
253 {
254 pp.remove(key);
255 }
256 }
257
258 try
259 {
260 log.debug("Invoking {}", method);
261
262 method.invoke(this, parameters);
263 }
264 catch (InvocationTargetException ite)
265 {
266 Throwable t = ite.getTargetException();
267 if (bubbleUpException)
268 {
269 if (t instanceof Exception)
270 {
271 throw (Exception) t;
272 }
273 else
274 {
275 throw ite;
276 }
277 }
278 else
279 {
280 log.error("Invokation of {}", method, t);
281 }
282 }
283 }
284
285
286
287
288
289
290
291
292
293 protected String formatString(String input, ParameterParser pp)
294 {
295 String tmp = input;
296
297 if (StringUtils.isNotEmpty(input))
298 {
299 tmp = input.toLowerCase();
300
301
302 String methodName = (tmp.endsWith(".x") || tmp.endsWith(".y"))
303 ? input.substring(0, input.length() - 2)
304 : input;
305
306 if (pp.getUrlFolding() == URLCaseFolding.NONE)
307 {
308 tmp = methodName.substring(BUTTON_LENGTH);
309 }
310 else
311 {
312 tmp = methodName.toLowerCase().substring(BUTTON_LENGTH);
313 }
314 }
315
316 return tmp;
317 }
318
319
320
321
322
323
324
325
326
327 protected boolean considerKey(String key, ParameterParser pp)
328 {
329 if (!submitValueKey)
330 {
331 log.debug("No Value required, accepting {}", key);
332 return true;
333 }
334 else
335 {
336
337
338
339
340
341
342
343
344
345 String keyValue = pp.getString(key);
346 log.debug("Key Value is {}", keyValue);
347 if (StringUtils.isEmpty(keyValue))
348 {
349 log.debug("Key is empty, rejecting {}", key);
350 return false;
351 }
352
353 try
354 {
355 if (Integer.parseInt(keyValue) != 0)
356 {
357 log.debug("Integer != 0, accepting {}", key);
358 return true;
359 }
360 }
361 catch (NumberFormatException nfe)
362 {
363
364
365
366 log.debug("Not a number, accepting " + key);
367 return true;
368 }
369 }
370 log.debug("Rejecting {}", key);
371 return false;
372 }
373 }