1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.shared.context;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.LinkedList;
25 import java.util.List;
26 import java.util.Queue;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import javax.el.ELException;
31 import javax.faces.FacesException;
32 import javax.faces.context.ExceptionHandler;
33 import javax.faces.context.ExternalContext;
34 import javax.faces.context.FacesContext;
35 import javax.faces.context.PartialResponseWriter;
36 import javax.faces.context.PartialViewContext;
37 import javax.faces.event.AbortProcessingException;
38 import javax.faces.event.ExceptionQueuedEvent;
39 import javax.faces.event.ExceptionQueuedEventContext;
40 import javax.faces.event.SystemEvent;
41
42
43
44
45
46 public class AjaxExceptionHandlerImpl extends ExceptionHandler
47 {
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 private static final Logger log = Logger.getLogger(AjaxExceptionHandlerImpl.class.getName());
70
71 private Queue<ExceptionQueuedEvent> handled;
72 private Queue<ExceptionQueuedEvent> unhandled;
73 private ExceptionQueuedEvent handledAndThrown;
74
75 public AjaxExceptionHandlerImpl()
76 {
77 }
78
79
80
81
82 @Override
83 public ExceptionQueuedEvent getHandledExceptionQueuedEvent()
84 {
85 return handledAndThrown;
86 }
87
88
89
90
91 @Override
92 public Iterable<ExceptionQueuedEvent> getHandledExceptionQueuedEvents()
93 {
94 return handled == null ? Collections.<ExceptionQueuedEvent>emptyList() : handled;
95 }
96
97
98
99
100 @Override
101 public Throwable getRootCause(Throwable t)
102 {
103 if (t == null)
104 {
105 throw new NullPointerException("t");
106 }
107
108 while (t != null)
109 {
110 Class<?> clazz = t.getClass();
111 if (!clazz.equals(FacesException.class) && !clazz.equals(ELException.class))
112 {
113 return t;
114 }
115
116 t = t.getCause();
117 }
118
119 return null;
120 }
121
122
123
124
125 @Override
126 public Iterable<ExceptionQueuedEvent> getUnhandledExceptionQueuedEvents()
127 {
128 return unhandled == null ? Collections.<ExceptionQueuedEvent>emptyList() : unhandled;
129 }
130
131
132
133
134 @Override
135 public void handle() throws FacesException
136 {
137 if (unhandled != null && !unhandled.isEmpty())
138 {
139 if (handled == null)
140 {
141 handled = new LinkedList<ExceptionQueuedEvent>();
142 }
143
144 List<Throwable> throwableList = new ArrayList<Throwable>();
145 FacesContext facesContext = null;
146
147 do
148 {
149
150
151
152 ExceptionQueuedEvent event = unhandled.peek();
153 try
154 {
155
156 ExceptionQueuedEventContext context = event.getContext();
157
158 if (facesContext == null)
159 {
160 facesContext = event.getContext().getContext();
161 }
162
163
164 Throwable exception = context.getException();
165
166
167
168 if (!shouldSkip(exception))
169 {
170
171 handledAndThrown = event;
172
173 Throwable rootCause = getRootCause(exception);
174
175 throwableList.add(rootCause == null ? exception : rootCause);
176
177
178 }
179 else
180 {
181
182
183 log.log(Level.SEVERE, exception.getClass().getName() + " occured while processing " +
184 (context.inBeforePhase() ? "beforePhase() of " :
185 (context.inAfterPhase() ? "afterPhase() of " : "")) +
186 "phase " + context.getPhaseId() + ": " +
187 "UIComponent-ClientId=" +
188 (context.getComponent() != null ?
189 context.getComponent().getClientId(context.getContext()) : "") + ", " +
190 "Message=" + exception.getMessage());
191
192 log.log(Level.SEVERE, exception.getMessage(), exception);
193 }
194 }
195 finally
196 {
197
198
199 handled.add(event);
200 unhandled.remove(event);
201 }
202 } while (!unhandled.isEmpty());
203
204 if (!throwableList.isEmpty())
205 {
206 PartialResponseWriter partialWriter = null;
207 boolean responseComplete = false;
208
209
210 if (facesContext == null)
211 {
212 facesContext = FacesContext.getCurrentInstance();
213 }
214
215 facesContext = (facesContext == null) ? FacesContext.getCurrentInstance() : facesContext;
216 ExternalContext externalContext = facesContext.getExternalContext();
217
218
219 if (!facesContext.getExternalContext().isResponseCommitted())
220 {
221 facesContext.getExternalContext().responseReset();
222 }
223
224 PartialViewContext partialViewContext = facesContext.getPartialViewContext();
225 partialWriter = partialViewContext.getPartialResponseWriter();
226
227
228 externalContext.setResponseContentType("text/xml");
229 externalContext.setResponseCharacterEncoding("UTF-8");
230 externalContext.addResponseHeader("Cache-control", "no-cache");
231
232 try
233 {
234 partialWriter.startDocument();
235
236 for (Throwable t : throwableList)
237 {
238 renderAjaxError(partialWriter, t);
239 }
240
241 responseComplete = true;
242 }
243 catch (IOException e)
244 {
245 if (log.isLoggable(Level.SEVERE))
246 {
247 log.log(Level.SEVERE, "Cannot render exception on ajax request", e);
248 }
249 }
250 finally
251 {
252 if (responseComplete)
253 {
254 try
255 {
256 partialWriter.endDocument();
257 facesContext.responseComplete();
258 }
259 catch (IOException e1)
260 {
261 if (log.isLoggable(Level.SEVERE))
262 {
263 log.log(Level.SEVERE, "Cannot render exception on ajax request", e1);
264 }
265 }
266 }
267 }
268 }
269 }
270 }
271
272 private void renderAjaxError(PartialResponseWriter partialWriter, Throwable ex) throws IOException
273 {
274 partialWriter.startError(ex.getClass().getName());
275 if (ex.getCause() != null)
276 {
277 partialWriter.write(ex.getCause().toString());
278 }
279 else if (ex.getMessage() != null)
280 {
281 partialWriter.write(ex.getMessage());
282 }
283 partialWriter.endError();
284 }
285
286
287
288
289 @Override
290 public boolean isListenerForSource(Object source)
291 {
292 return source instanceof ExceptionQueuedEventContext;
293 }
294
295
296
297
298 @Override
299 public void processEvent(SystemEvent exceptionQueuedEvent) throws AbortProcessingException
300 {
301 if (unhandled == null)
302 {
303 unhandled = new LinkedList<ExceptionQueuedEvent>();
304 }
305
306 unhandled.add((ExceptionQueuedEvent)exceptionQueuedEvent);
307 }
308
309 protected Throwable getRethrownException(Throwable exception)
310 {
311
312
313 Throwable toRethrow = getRootCause(exception);
314 if (toRethrow == null)
315 {
316 toRethrow = exception;
317 }
318
319 return toRethrow;
320 }
321
322 protected FacesException wrap(Throwable exception)
323 {
324 if (exception instanceof FacesException)
325 {
326 return (FacesException) exception;
327 }
328 return new FacesException(exception);
329 }
330
331 protected boolean shouldSkip(Throwable exception)
332 {
333 return exception instanceof AbortProcessingException;
334 }
335
336 }