View Javadoc

1   /*
2    * $Id: AbstractActionListener.java,v 1.17 2011/06/16 09:29:41 jbmeslin Exp $
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   * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
29   * @version $Revision: 1.17 $ $Date: 2011/06/16 09:29:41 $
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          // Pour la deserialisation
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       * public final MethodExpression getMethodExpression() { return
89       * methodBinding; }
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             // Format #[xxx] ???
118             String forwardName = getForwardName(expression);
119             if (forwardName != null) {
120                 // Oui !
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             // On provoque la recherche d'info pour vérifier que la méthode
442             // existe :-)
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 }