1
2
3
4
5 package org.rcfaces.core.internal.listener;
6
7 import java.util.Arrays;
8
9 import javax.el.ELContext;
10 import javax.el.ELException;
11 import javax.el.MethodExpression;
12 import javax.el.MethodInfo;
13 import javax.el.MethodNotFoundException;
14 import javax.el.PropertyNotFoundException;
15 import javax.faces.FacesException;
16 import javax.faces.application.NavigationHandler;
17 import javax.faces.component.StateHolder;
18 import javax.faces.context.FacesContext;
19 import javax.faces.event.AbortProcessingException;
20 import javax.faces.event.FacesEvent;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.rcfaces.core.internal.tools.ListenersTools.IMethodExpressionCreator;
25 import org.rcfaces.core.internal.util.ForwardMethodExpression;
26
27
28
29
30
31 abstract class AbstractActionListener implements StateHolder,
32 IServerActionListener, IPartialRenderingListener {
33 private static final String REVISION = "$Revision: 1.17 $";
34
35 private static final Log LOG = LogFactory
36 .getLog(AbstractActionListener.class);
37
38 private static final Class[] FACES_PARAMETERS = new Class[] { FacesEvent.class };
39
40 private static final Class[] NO_PARAMETERS = new Class[0];
41
42 private String expression;
43
44 private MethodExpression speciedMethodExpression;
45
46 private transient boolean forwarNameMethodInitialized;
47
48 private transient MethodExpression forwardNameMethodExpression;
49
50 private transient boolean argsMethodExpressionInitialized;
51
52 private transient MethodExpression argsMethodExpression;
53
54 private transient boolean noArgsMethodExpressionInitialized;
55
56 private transient MethodExpression noArgsMethodExpression;
57
58 private transient boolean facesArgsMethodExpressionInitialized;
59
60 private transient MethodExpression facesArgsMethodExpression;
61
62 private boolean transientValue;
63
64 private boolean partialRendering;
65
66 protected AbstractActionListener() {
67
68 }
69
70 protected AbstractActionListener(String expression) {
71 this.expression = expression;
72 }
73
74 protected AbstractActionListener(String expression, boolean partialRendering) {
75 this(expression);
76 this.partialRendering = partialRendering;
77 }
78
79 public boolean isPartialRendering() {
80 return partialRendering;
81 }
82
83 public void setPartialRendering(boolean partialRendering) {
84 this.partialRendering = partialRendering;
85 }
86
87
88
89
90
91 protected void process(FacesEvent event) throws AbortProcessingException {
92
93 FacesContext facesContext = getFacesContext();
94
95 Object parameters[] = new Object[] { event };
96
97 if (speciedMethodExpression != null) {
98 Exception th = tryMethodExpression(facesContext,
99 speciedMethodExpression, parameters, event);
100
101 if (th == null) {
102 return;
103 }
104
105 if (th instanceof RuntimeException) {
106 throw (RuntimeException) th;
107 }
108
109 throw new FacesException(
110 "Exception when calling forward name method '" + expression
111 + "'.", th);
112 }
113
114 if (forwarNameMethodInitialized == false) {
115 forwarNameMethodInitialized = true;
116
117
118 String forwardName = getForwardName(expression);
119 if (forwardName != null) {
120
121 forwardNameMethodExpression = getForwardMethodExpression();
122 }
123 }
124
125 if (forwardNameMethodExpression != null) {
126 Exception th = tryMethodExpression(facesContext,
127 forwardNameMethodExpression, null, event);
128
129 if (th == null) {
130 return;
131 }
132
133 if (th instanceof RuntimeException) {
134 throw (RuntimeException) th;
135 }
136
137 throw new FacesException(
138 "Exception when calling forward name method '" + expression
139 + "'.", th);
140 }
141
142 Exception firstThrowable = null;
143
144 if (argsMethodExpressionInitialized == false) {
145 argsMethodExpressionInitialized = true;
146 argsMethodExpression = getArgumentsMethodExpression(facesContext);
147 }
148 if (argsMethodExpression != null) {
149 Exception th = tryMethodExpression(facesContext,
150 argsMethodExpression, parameters, event);
151 if (th == null) {
152 return;
153 }
154 firstThrowable = th;
155 }
156
157 if (facesArgsMethodExpressionInitialized == false) {
158 facesArgsMethodExpressionInitialized = true;
159 facesArgsMethodExpression = getFacesArgumentsMethodExpression(facesContext);
160 }
161 if (facesArgsMethodExpression != null) {
162 Exception th = tryMethodExpression(facesContext,
163 facesArgsMethodExpression, parameters, event);
164 if (th == null) {
165 return;
166 }
167 if (firstThrowable == null) {
168 firstThrowable = th;
169 }
170 }
171
172 if (noArgsMethodExpressionInitialized == false) {
173 noArgsMethodExpressionInitialized = true;
174 noArgsMethodExpression = getNoArgsMethodExpression(facesContext);
175 }
176 if (noArgsMethodExpression != null) {
177 Exception th = tryMethodExpression(facesContext,
178 noArgsMethodExpression, null, event);
179 if (th == null) {
180 return;
181 }
182 if (firstThrowable == null) {
183 firstThrowable = th;
184 }
185 }
186
187 LOG.error("Can not find method associated to expression '" + expression
188 + "'.", firstThrowable);
189 }
190
191 private Exception tryMethodExpression(FacesContext facesContext,
192 MethodExpression methodBinding, Object parameters[],
193 FacesEvent event) {
194
195 if (LOG.isDebugEnabled()) {
196 LOG.debug("Try method expression '" + methodBinding
197 + "' parameters='" + ((parameters != null)?
198 Arrays.asList(parameters):"null")
199 + "' event='" + event + "'");
200 }
201
202 try {
203 Object ret = methodBinding.invoke(facesContext.getELContext(),
204 parameters);
205
206 if (LOG.isDebugEnabled()) {
207 LOG.debug("Call method expression '" + methodBinding
208 + "' parameters='" + ((parameters != null)?
209 Arrays.asList(parameters):"null")
210 + "' event='" + event + "' returns '" + ret + "'");
211 }
212
213 processReturn(facesContext, methodBinding, event, ret);
214
215 return null;
216
217 } catch (PropertyNotFoundException ex) {
218 if (LOG.isDebugEnabled()) {
219 LOG.debug("Property not found for expression '" + expression
220 + "'.", ex);
221 }
222
223 return ex;
224
225 } catch (MethodNotFoundException ex) {
226 if (LOG.isDebugEnabled()) {
227 LOG.debug("Method not found for expression '" + expression
228 + "'.", ex);
229 }
230
231 return ex;
232
233 } catch (ELException ex) {
234 if (LOG.isDebugEnabled()) {
235 LOG.debug("Evaluation error for expression '" + expression
236 + "'.", ex);
237 }
238
239 return processException(ex, event);
240
241 } catch (RuntimeException ex) {
242 if (LOG.isDebugEnabled()) {
243 LOG.debug("Evaluation exception for expression '" + expression
244 + "'.", ex);
245 }
246
247 throw ex;
248 }
249 }
250
251 protected Exception processException(ELException ex, FacesEvent event) {
252
253 if (LOG.isDebugEnabled()) {
254 LOG.debug("Process exception '" + ex + "' event='" + event
255 + "', ex");
256 }
257
258 Throwable cause = ex.getCause();
259
260 if (cause instanceof AbortProcessingException) {
261 throw (AbortProcessingException) cause;
262 }
263
264 if (cause instanceof MethodNotFoundException) {
265 return (Exception) cause;
266 }
267
268 if (cause instanceof PropertyNotFoundException) {
269 return (Exception) cause;
270 }
271
272 if (cause instanceof NoSuchMethodException) {
273 return (Exception) cause;
274 }
275
276 throw ex;
277 }
278
279 private MethodExpression getArgumentsMethodExpression(
280 FacesContext facesContext) {
281 return facesContext
282 .getApplication()
283 .getExpressionFactory()
284 .createMethodExpression(facesContext.getELContext(),
285 expression, null, listParameterClasses());
286 }
287
288 private MethodExpression getFacesArgumentsMethodExpression(
289 FacesContext facesContext) {
290 return facesContext
291 .getApplication()
292 .getExpressionFactory()
293 .createMethodExpression(facesContext.getELContext(),
294 expression, null, FACES_PARAMETERS);
295 }
296
297 private MethodExpression getNoArgsMethodExpression(FacesContext facesContext) {
298 return facesContext
299 .getApplication()
300 .getExpressionFactory()
301 .createMethodExpression(facesContext.getELContext(),
302 expression, null, NO_PARAMETERS);
303 }
304
305 protected abstract Class[] listParameterClasses();
306
307 private MethodExpression getForwardMethodExpression() {
308 forwarNameMethodInitialized = true;
309
310 noArgsMethodExpression = new ForwardMethodExpression(expression);
311 return noArgsMethodExpression;
312 }
313
314 protected static final String getForwardName(String expression) {
315 int len = expression.length() - 1;
316
317 if (len < 3) {
318 return null;
319 }
320
321 if (expression.startsWith("#[") == false) {
322 return null;
323 }
324
325 if (expression.charAt(len) != ']') {
326 return null;
327 }
328
329 return expression.substring(2, len);
330 }
331
332 protected final FacesContext getFacesContext() {
333 return FacesContext.getCurrentInstance();
334 }
335
336 public boolean isTransient() {
337 return transientValue;
338 }
339
340 public void setTransient(boolean newTransientValue) {
341 this.transientValue = newTransientValue;
342 }
343
344 public final void restoreState(FacesContext context, Object state) {
345 Object ret[] = (Object[]) state;
346
347 expression = (String) ret[0];
348 if (expression == null) {
349 throw new NullPointerException("Expression is null !");
350 }
351
352 partialRendering = Boolean.TRUE.equals(ret[1]);
353
354 speciedMethodExpression = (MethodExpression) ret[2];
355
356 forwarNameMethodInitialized = false;
357 }
358
359 public final Object saveState(FacesContext context) {
360 Object objects[] = { expression,
361 (partialRendering) ? Boolean.TRUE : null,
362 speciedMethodExpression };
363
364 return objects;
365 }
366
367 protected void processReturn(FacesContext facesContext,
368 MethodExpression binding, FacesEvent event, Object ret) {
369
370 if (LOG.isDebugEnabled()) {
371 LOG.debug("Call of method binding='" + binding + "' event='"
372 + event + "' returns " + ret);
373 }
374
375 if ((ret instanceof String) == false) {
376 if (LOG.isInfoEnabled() && ret != null) {
377 LOG.info("Return of method binding='" + binding + "' event='"
378 + event + "' is not a String !");
379 }
380 return;
381 }
382
383 String outcome = (String) ret;
384
385 NavigationHandler navHandler = facesContext.getApplication()
386 .getNavigationHandler();
387
388 navHandler.handleNavigation(facesContext,
389 binding.getExpressionString(), outcome);
390
391 facesContext.renderResponse();
392 }
393
394 public boolean equals(Object object) {
395 if (object == null
396 || (object instanceof AbstractActionListener) == false) {
397 return false;
398 }
399
400 AbstractActionListener s = (AbstractActionListener) object;
401
402 if (expression != s.expression) {
403 if (expression == null || expression.equals(s.expression) == false) {
404 return false;
405 }
406 }
407
408 return true;
409 }
410
411 public int hashCode() {
412 if (expression == null) {
413 return 0;
414 }
415
416 return expression.hashCode();
417 }
418
419 public MethodExpression getSpeciedMethodExpression() {
420 return speciedMethodExpression;
421 }
422
423 public void createMethodExpression(FacesContext facesContext,
424 IMethodExpressionCreator methodExpressionCreator) {
425
426 if (facesContext == null) {
427 facesContext = FacesContext.getCurrentInstance();
428 }
429
430 ELContext elContext = facesContext.getELContext();
431
432 Class parameters[] = listParameterClasses();
433
434 RuntimeException firstEx = null;
435 try {
436 speciedMethodExpression = methodExpressionCreator.create(
437 expression, parameters);
438
439 MethodInfo methodInfo = speciedMethodExpression
440 .getMethodInfo(elContext);
441
442
443
444 if (LOG.isDebugEnabled()) {
445 LOG.debug("Method expression for '" + expression
446 + "' with parameter '" + parameters[0].getName()
447 + "' detected ! " + speciedMethodExpression
448 + " methodInfo=" + methodInfo);
449 }
450
451 return;
452
453 } catch (RuntimeException ex) {
454 if (LOG.isDebugEnabled()) {
455 LOG.debug("Create method expression for '" + expression
456 + "' with parameter '" + parameters[0].getName()
457 + "' throws exception.", ex);
458 }
459
460 firstEx = ex;
461 }
462
463 try {
464 speciedMethodExpression = methodExpressionCreator.create(
465 expression, FACES_PARAMETERS);
466
467 MethodInfo methodInfo = speciedMethodExpression
468 .getMethodInfo(elContext);
469
470 if (LOG.isDebugEnabled()) {
471 LOG.debug("Method expression for '" + expression
472 + "' with FacesEvent parameter detected ! "
473 + speciedMethodExpression + " methodInfo=" + methodInfo);
474 }
475
476 return;
477
478 } catch (RuntimeException ex) {
479 if (LOG.isDebugEnabled()) {
480 LOG.debug("Create method expression for '" + expression
481 + "' with facesEvent parameter throws exception.", ex);
482 }
483 }
484
485 try {
486 speciedMethodExpression = methodExpressionCreator.create(
487 expression, NO_PARAMETERS);
488
489 MethodInfo methodInfo = speciedMethodExpression
490 .getMethodInfo(elContext);
491
492 if (LOG.isDebugEnabled()) {
493 LOG.debug("Method expression for '" + expression
494 + "' with no parameter detected ! "
495 + speciedMethodExpression + " methodInfo=" + methodInfo);
496 }
497
498 return;
499
500 } catch (RuntimeException ex) {
501 if (LOG.isDebugEnabled()) {
502 LOG.debug("Create method expression for '" + expression
503 + "' without parameters throws exception.", ex);
504 }
505 }
506
507 throw firstEx;
508 }
509 }