1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.tag.ui;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.EnumSet;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.el.ELContext;
29 import javax.el.ValueExpression;
30 import javax.faces.component.EditableValueHolder;
31 import javax.faces.component.UIComponent;
32 import javax.faces.component.UIViewRoot;
33 import javax.faces.component.visit.VisitCallback;
34 import javax.faces.component.visit.VisitContext;
35 import javax.faces.component.visit.VisitHint;
36 import javax.faces.component.visit.VisitResult;
37 import javax.faces.context.FacesContext;
38 import javax.faces.event.PhaseEvent;
39 import javax.faces.event.PhaseId;
40 import javax.faces.event.PhaseListener;
41
42 import org.apache.myfaces.renderkit.ErrorPageWriter;
43
44
45
46
47
48
49
50
51 public class DebugPhaseListener implements PhaseListener
52 {
53
54 private static final long serialVersionUID = -1517198431551012882L;
55
56 private static final String SUBMITTED_VALUE_FIELD = "submittedValue";
57 private static final String LOCAL_VALUE_FIELD = "localValue";
58 private static final String VALUE_FIELD = "value";
59
60
61
62
63
64
65
66 @SuppressWarnings("unchecked")
67 public static Map<String, List<Object[]>> getDebugInfoMap(String clientId)
68 {
69 final Map<String, Object> requestMap = FacesContext.getCurrentInstance()
70 .getExternalContext().getRequestMap();
71 Map<String, List<Object[]>> debugInfo = (Map<String, List<Object[]>>)
72 requestMap.get(ErrorPageWriter.DEBUG_INFO_KEY + clientId);
73 if (debugInfo == null)
74 {
75
76 debugInfo = new HashMap<String, List<Object[]>>();
77 requestMap.put(ErrorPageWriter.DEBUG_INFO_KEY + clientId, debugInfo);
78 }
79 return debugInfo;
80 }
81
82
83
84
85
86
87
88
89 public static List<Object[]> getFieldDebugInfos(final String field, String clientId)
90 {
91 Map<String, List<Object[]>> debugInfo = getDebugInfoMap(clientId);
92 List<Object[]> fieldDebugInfo = debugInfo.get(field);
93 if (fieldDebugInfo == null)
94 {
95
96 fieldDebugInfo = new ArrayList<Object[]>();
97 debugInfo.put(field, fieldDebugInfo);
98 }
99 return fieldDebugInfo;
100 }
101
102
103
104
105
106
107
108
109
110
111
112 public static void createFieldDebugInfo(FacesContext facesContext,
113 final String field, Object oldValue,
114 Object newValue, String clientId)
115 {
116 if ((oldValue == null && newValue == null)
117 || (oldValue != null && oldValue.equals(newValue)))
118 {
119
120
121
122
123 return;
124 }
125
126
127 if (oldValue != null && oldValue.getClass().isArray())
128 {
129 oldValue = Arrays.deepToString((Object[]) oldValue);
130 }
131 if (newValue != null && newValue.getClass().isArray())
132 {
133 newValue = Arrays.deepToString((Object[]) newValue);
134 }
135
136
137
138
139
140
141
142
143
144
145
146 Object[] debugInfo = new Object[4];
147 debugInfo[0] = facesContext.getCurrentPhaseId();
148 debugInfo[1] = oldValue;
149 debugInfo[2] = newValue;
150 debugInfo[3] = null;
151
152
153 getFieldDebugInfos(field, clientId).add(debugInfo);
154 }
155
156
157
158
159
160
161 private class DebugVisitCallback implements VisitCallback
162 {
163
164 public VisitResult visit(VisitContext context, UIComponent target)
165 {
166 if (target instanceof EditableValueHolder)
167 {
168 EditableValueHolder evh = (EditableValueHolder) target;
169 final String clientId = target.getClientId(context.getFacesContext());
170 Map<String, Object> requestMap = context.getFacesContext()
171 .getExternalContext().getRequestMap();
172
173 if (_afterPhase)
174 {
175
176
177
178 _createFieldDebugInfosIfNecessary(SUBMITTED_VALUE_FIELD, clientId,
179 evh.getSubmittedValue(), requestMap, context.getFacesContext());
180
181
182 final Object localValue = evh.getLocalValue();
183 _createFieldDebugInfosIfNecessary(LOCAL_VALUE_FIELD, clientId,
184 localValue, requestMap, context.getFacesContext());
185
186
187 final Object value = _getRealValue(evh, target, localValue,
188 context.getFacesContext().getELContext());
189 _createFieldDebugInfosIfNecessary(VALUE_FIELD, clientId,
190 value, requestMap, context.getFacesContext());
191 }
192 else
193 {
194
195
196
197 requestMap.put(ErrorPageWriter.DEBUG_INFO_KEY + clientId
198 + SUBMITTED_VALUE_FIELD, evh.getSubmittedValue());
199
200
201 final Object localValue = evh.getLocalValue();
202 requestMap.put(ErrorPageWriter.DEBUG_INFO_KEY + clientId
203 + LOCAL_VALUE_FIELD, localValue);
204
205
206 final Object value = _getRealValue(evh, target, localValue,
207 context.getFacesContext().getELContext());
208 requestMap.put(ErrorPageWriter.DEBUG_INFO_KEY + clientId
209 + VALUE_FIELD, value);
210 }
211 }
212
213 return VisitResult.ACCEPT;
214 }
215
216
217
218
219
220
221
222
223
224
225 private void _createFieldDebugInfosIfNecessary(final String field,
226 final String clientId, Object newValue,
227 Map<String, Object> requestMap, FacesContext facesContext)
228 {
229
230 List<Object[]> fieldDebugInfos = getFieldDebugInfos(field, clientId);
231 boolean found = false;
232 for (int i = 0, size = fieldDebugInfos.size(); i < size; i++)
233 {
234 Object[] debugInfo = fieldDebugInfos.get(i);
235 if (debugInfo[0].equals(_currentPhase))
236 {
237 found = true;
238 break;
239 }
240 }
241 if (!found)
242 {
243
244
245 Object oldValue = requestMap.remove(ErrorPageWriter.DEBUG_INFO_KEY
246 + clientId + field);
247 createFieldDebugInfo(facesContext, field,
248 oldValue, newValue, clientId);
249 }
250 }
251
252
253
254
255
256
257
258
259
260
261
262 private Object _getRealValue(EditableValueHolder evh, UIComponent target,
263 final Object localValue, ELContext elCtx)
264 {
265 Object value = evh.getValue();
266 if (localValue != null && localValue.equals(value))
267 {
268
269
270 ValueExpression valueExpression = target.getValueExpression("value");
271 if (valueExpression != null)
272 {
273 value = valueExpression.getValue(elCtx);
274 }
275 }
276 return value;
277 }
278
279 }
280
281 private boolean _afterPhase = false;
282 private PhaseId _currentPhase;
283 private DebugVisitCallback _visitCallback = new DebugVisitCallback();
284
285 public void afterPhase(PhaseEvent event)
286 {
287 _doTreeVisit(event, true);
288 }
289
290 public void beforePhase(PhaseEvent event)
291 {
292 _doTreeVisit(event, false);
293 }
294
295 public PhaseId getPhaseId()
296 {
297 return PhaseId.ANY_PHASE;
298 }
299
300 private void _doTreeVisit(PhaseEvent event, boolean afterPhase)
301 {
302 _afterPhase = afterPhase;
303 _currentPhase = event.getPhaseId();
304
305
306 UIViewRoot viewroot = event.getFacesContext().getViewRoot();
307 if (viewroot != null)
308 {
309
310
311 viewroot.visitTree(VisitContext.createVisitContext(
312 event.getFacesContext(), null,
313 EnumSet.of(VisitHint.SKIP_UNRENDERED)),
314 _visitCallback);
315 }
316 }
317
318 }