View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.application;
20  
21  import javax.el.ELException;
22  import javax.el.MethodExpression;
23  import javax.faces.FacesException;
24  import javax.faces.application.Application;
25  import javax.faces.application.NavigationHandler;
26  import javax.faces.component.ActionSource;
27  import javax.faces.component.ActionSource2;
28  import javax.faces.component.UIComponent;
29  import javax.faces.context.FacesContext;
30  import javax.faces.el.EvaluationException;
31  import javax.faces.el.MethodBinding;
32  import javax.faces.event.AbortProcessingException;
33  import javax.faces.event.ActionEvent;
34  import javax.faces.event.ActionListener;
35  
36  
37  /**
38   * @author Manfred Geiler (latest modification by $Author: bommel $)
39   * @author Anton Koinov
40   * @version $Revision: 1187700 $ $Date: 2011-10-22 07:19:37 -0500 (Sat, 22 Oct 2011) $
41   */
42  public class ActionListenerImpl implements ActionListener
43  {
44      public void processAction(ActionEvent actionEvent) throws AbortProcessingException
45      {
46          FacesContext facesContext = FacesContext.getCurrentInstance();
47          Application application = facesContext.getApplication();
48          UIComponent component = actionEvent.getComponent();
49          
50          MethodExpression methodExpression = null;
51          MethodBinding methodBinding = null;
52          
53          String fromAction = null;
54          String outcome = null;
55          
56          if (component instanceof ActionSource2)
57          {
58              // Must be an instance of ActionSource2, so don't look on action if the actionExpression is set 
59              methodExpression = ((ActionSource2) component).getActionExpression();            
60          }
61          if (methodExpression == null && component instanceof ActionSource)
62          {
63              // Backwards compatibility for pre-1.2.
64              methodBinding = ((ActionSource) component).getAction();
65          }
66          
67          if (methodExpression != null)
68          {
69              fromAction = methodExpression.getExpressionString();
70              try
71              {
72                  Object objOutcome = methodExpression.invoke(facesContext.getELContext(), null);
73                  if (objOutcome != null)
74                  {
75                      outcome = objOutcome.toString();
76                  }
77              }
78              catch (ELException e)
79              {
80                  // "... If that fails for any reason, throw an AbortProcessingException, including the cause of the failure ..."
81                  // -= Leonardo Uribe =- after discussing this topic on MYFACES-3199, the conclusion is the part is an advice
82                  // for the developer implementing a listener in a method expressions that could be wrapped by this class.
83                  // The spec wording is poor but, to keep this coherently with ExceptionHandler API, the spec and code on UIViewRoot we need:
84                  // 2a) "exception is instance of APE or any of the causes of the exception are an APE, 
85                  // DON'T publish ExceptionQueuedEvent and terminate processing for current event".
86                  // 2b) for any other exception publish ExceptionQueuedEvent and continue broadcast processing.
87                  Throwable cause = e.getCause();
88                  AbortProcessingException ape = null;
89                  if (cause != null)
90                  {
91                      do
92                      {
93                          if (cause != null && cause instanceof AbortProcessingException)
94                          {
95                              ape = (AbortProcessingException) cause;
96                              break;
97                          }
98                          cause = cause.getCause();
99                      }
100                     while (cause != null);
101                 }
102                 
103                 if (ape != null)
104                 {
105                     // 2a) "exception is instance of APE or any of the causes of the exception are an APE, 
106                     // DON'T publish ExceptionQueuedEvent and terminate processing for current event".
107                     // To do this throw an AbortProcessingException here, later on UIViewRoot.broadcastAll,
108                     // this exception will be received and stored to handle later.
109                     throw ape;
110                 }
111                 
112                 // Since this ActionListener is the one who handles navigation, if we have another different exception
113                 // here we can't queue it on ExceptionHandler stack, instead throw it as a FacesException.
114                 throw new FacesException("Error calling action method of component with id " + actionEvent.getComponent().getClientId(facesContext), e);
115             }
116             catch (RuntimeException e)
117             {
118                 throw new FacesException("Error calling action method of component with id " + actionEvent.getComponent().getClientId(facesContext), e);
119             }
120         }
121         
122         else if (methodBinding != null) {
123             fromAction = methodBinding.getExpressionString();
124             try
125             {
126                 Object objOutcome = methodBinding.invoke(facesContext, null);
127 
128                 if (objOutcome != null)
129                 {
130                     outcome = objOutcome.toString();
131                 }
132             }
133             catch (EvaluationException e)
134             {
135                 Throwable cause = e.getCause();
136                 if (cause != null && cause instanceof AbortProcessingException)
137                 {
138                     throw (AbortProcessingException)cause;
139                 }
140    
141                 throw new FacesException("Error calling action method of component with id " + actionEvent.getComponent().getClientId(facesContext), e);
142                 
143             }
144             catch (RuntimeException e)
145             {
146                 throw new FacesException("Error calling action method of component with id " + actionEvent.getComponent().getClientId(facesContext), e);
147             }
148         }
149         
150         NavigationHandler navigationHandler = application.getNavigationHandler();
151         navigationHandler.handleNavigation(facesContext, fromAction, outcome);
152         //Render Response if needed
153         facesContext.renderResponse();
154 
155     }
156 }