Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
MethodExpressionActionListener |
|
| 1.8181818181818181;1.818 |
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 | ||
20 | package javax.faces.event; | |
21 | ||
22 | import javax.el.ELContext; | |
23 | import javax.el.ELException; | |
24 | import javax.el.ExpressionFactory; | |
25 | import javax.el.MethodExpression; | |
26 | import javax.el.MethodNotFoundException; | |
27 | import javax.faces.component.StateHolder; | |
28 | import javax.faces.context.FacesContext; | |
29 | ||
30 | /** | |
31 | * See Javadoc of | |
32 | * <a href= | |
33 | * "https://javaserverfaces.dev.java.net/nonav/docs/2.0/javadocs/javax/faces/event/MethodExpressionActionListener.html"> | |
34 | * JSF Specification</a> | |
35 | */ | |
36 | public class MethodExpressionActionListener implements ActionListener, StateHolder | |
37 | { | |
38 | ||
39 | 2 | private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; |
40 | 2 | private static final Object[] EMPTY_PARAMS = new Object[0]; |
41 | ||
42 | private MethodExpression methodExpressionOneArg; | |
43 | private MethodExpression methodExpressionZeroArg; | |
44 | 14 | private boolean isTransient = false; |
45 | ||
46 | /** Creates a new instance of MethodExpressionActionListener */ | |
47 | public MethodExpressionActionListener() | |
48 | 4 | { |
49 | // constructor for state-saving | |
50 | 4 | } |
51 | ||
52 | public MethodExpressionActionListener(MethodExpression methodExpressionOneArg) | |
53 | 4 | { |
54 | 4 | this.methodExpressionOneArg = methodExpressionOneArg; |
55 | ||
56 | 4 | _createZeroArgsMethodExpression(methodExpressionOneArg); |
57 | 4 | } |
58 | ||
59 | public MethodExpressionActionListener(MethodExpression methodExpressionOneArg, | |
60 | MethodExpression methodExpressionZeroArg) | |
61 | 6 | { |
62 | 6 | this.methodExpressionOneArg = methodExpressionOneArg; |
63 | 6 | if (methodExpressionZeroArg != null) |
64 | { | |
65 | 6 | this.methodExpressionZeroArg = methodExpressionZeroArg; |
66 | } | |
67 | else | |
68 | { | |
69 | 0 | _createZeroArgsMethodExpression(methodExpressionOneArg); |
70 | } | |
71 | 6 | } |
72 | ||
73 | public void processAction(ActionEvent actionEvent) throws AbortProcessingException | |
74 | { | |
75 | try | |
76 | { | |
77 | try | |
78 | { | |
79 | // call to the one argument MethodExpression | |
80 | 4 | Object[] params = new Object[] { actionEvent }; |
81 | 4 | methodExpressionOneArg.invoke(getElContext(), params); |
82 | } | |
83 | 2 | catch (MethodNotFoundException mnfe) |
84 | { | |
85 | // call to the zero argument MethodExpression | |
86 | 2 | methodExpressionZeroArg.invoke(getElContext(), EMPTY_PARAMS); |
87 | 2 | } |
88 | } | |
89 | 0 | catch (ELException e) |
90 | { | |
91 | // "... If that fails for any reason, throw an AbortProcessingException, | |
92 | // including the cause of the failure ..." | |
93 | // -= Leonardo Uribe =- after discussing this topic on MYFACES-3199, the conclusion is the part is an advice | |
94 | // for the developer implementing a listener in a method expressions that could be wrapped by this class. | |
95 | // The spec wording is poor but, to keep this coherently with ExceptionHandler API, | |
96 | // the spec and code on UIViewRoot we need: | |
97 | // 2a) "exception is instance of APE or any of the causes of the exception are an APE, | |
98 | // DON'T publish ExceptionQueuedEvent and terminate processing for current event". | |
99 | // 2b) for any other exception publish ExceptionQueuedEvent and continue broadcast processing. | |
100 | 0 | Throwable cause = e.getCause(); |
101 | 0 | AbortProcessingException ape = null; |
102 | 0 | if (cause != null) |
103 | { | |
104 | do | |
105 | { | |
106 | 0 | if (cause instanceof AbortProcessingException) |
107 | { | |
108 | 0 | ape = (AbortProcessingException) cause; |
109 | 0 | break; |
110 | } | |
111 | 0 | cause = cause.getCause(); |
112 | } | |
113 | 0 | while (cause != null); |
114 | } | |
115 | ||
116 | 0 | if (ape != null) |
117 | { | |
118 | // 2a) "exception is instance of APE or any of the causes of the exception are an APE, | |
119 | // DON'T publish ExceptionQueuedEvent and terminate processing for current event". | |
120 | // To do this throw an AbortProcessingException here, later on UIViewRoot.broadcastAll, | |
121 | // this exception will be received and stored to handle later. | |
122 | 0 | throw ape; |
123 | } | |
124 | 0 | throw e; |
125 | //Throwable cause = e.getCause(); | |
126 | //if (cause == null) | |
127 | //{ | |
128 | // cause = e; | |
129 | //} | |
130 | //if (cause instanceof AbortProcessingException) | |
131 | //{ | |
132 | // throw (AbortProcessingException) cause; | |
133 | //} | |
134 | //else | |
135 | //{ | |
136 | // throw new AbortProcessingException(cause); | |
137 | //} | |
138 | 4 | } |
139 | 4 | } |
140 | ||
141 | public void restoreState(FacesContext context, Object state) | |
142 | { | |
143 | 2 | methodExpressionOneArg = (MethodExpression) ((Object[]) state)[0]; |
144 | 2 | methodExpressionZeroArg = (MethodExpression) ((Object[]) state)[1]; |
145 | 2 | } |
146 | ||
147 | public Object saveState(FacesContext context) | |
148 | { | |
149 | 2 | return new Object[] {methodExpressionOneArg, methodExpressionZeroArg}; |
150 | } | |
151 | ||
152 | public void setTransient(boolean newTransientValue) | |
153 | { | |
154 | 0 | isTransient = newTransientValue; |
155 | 0 | } |
156 | ||
157 | public boolean isTransient() | |
158 | { | |
159 | 0 | return isTransient; |
160 | } | |
161 | ||
162 | private ELContext getElContext() | |
163 | { | |
164 | 10 | return getFacesContext().getELContext(); |
165 | } | |
166 | ||
167 | private FacesContext getFacesContext() | |
168 | { | |
169 | 14 | return FacesContext.getCurrentInstance(); |
170 | } | |
171 | ||
172 | /** | |
173 | * Creates a {@link MethodExpression} with no params and with the same Expression as | |
174 | * param <code>methodExpression</code> | |
175 | * <b>WARNING!</b> This method creates new {@link MethodExpression} with expressionFactory.createMethodExpression. | |
176 | * That means is not decorating MethodExpression passed as parameter - | |
177 | * support for EL VariableMapper will not be available! | |
178 | * This is a problem when using facelets and <ui:decorate/> with EL params (see MYFACES-2541 for details). | |
179 | */ | |
180 | private void _createZeroArgsMethodExpression(MethodExpression methodExpression) | |
181 | { | |
182 | 4 | ExpressionFactory expressionFactory = getFacesContext().getApplication().getExpressionFactory(); |
183 | ||
184 | 4 | this.methodExpressionZeroArg = expressionFactory.createMethodExpression(getElContext(), |
185 | methodExpression.getExpressionString(), Void.class, EMPTY_CLASS_ARRAY); | |
186 | 4 | } |
187 | ||
188 | } |