1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.tomahawk.util;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23
24 import javax.faces.context.FacesContext;
25 import javax.faces.context.ExternalContext;
26 import javax.faces.component.UIComponent;
27 import javax.el.Expression;
28 import javax.el.ValueExpression;
29 import javax.servlet.ServletException;
30 import javax.servlet.http.HttpServletResponse;
31 import java.beans.BeanInfo;
32 import java.beans.Introspector;
33 import java.beans.PropertyDescriptor;
34 import java.io.*;
35 import java.lang.reflect.Method;
36 import java.text.DateFormat;
37 import java.util.*;
38 import java.util.regex.Pattern;
39 import java.util.regex.Matcher;
40
41
42
43
44
45
46
47
48
49 public class ErrorPageWriter {
50
51 private static final Log log = LogFactory.getLog(ErrorPageWriter.class);
52
53 private final static String TS = "<";
54
55 private static final String ERROR_TEMPLATE = "META-INF/rsc/myfaces-dev-error.xml";
56
57 private static final String ERROR_TEMPLATE_RESOURCE = "org.apache.myfaces.ERROR_TEMPLATE_RESOURCE";
58
59 private static String[] ERROR_PARTS;
60
61 private static final String DEBUG_TEMPLATE = "META-INF/rsc/myfaces-dev-debug.xml";
62
63 private static final String DEBUG_TEMPLATE_RESOURCE = "org.apache.myfaces.DEBUG_TEMPLATE_RESOURCE";
64
65 private static String[] DEBUG_PARTS;
66
67 public ErrorPageWriter() {
68 super();
69 }
70
71 private static String getErrorTemplate(FacesContext context)
72 {
73 String errorTemplate = context.getExternalContext().getInitParameter(ERROR_TEMPLATE_RESOURCE);
74 if (errorTemplate != null)
75 {
76 return errorTemplate;
77 }
78 return ERROR_TEMPLATE;
79 }
80
81 private static String getDebugTemplate(FacesContext context)
82 {
83 String debugTemplate = context.getExternalContext().getInitParameter(DEBUG_TEMPLATE_RESOURCE);
84 if (debugTemplate != null)
85 {
86 return debugTemplate;
87 }
88 return DEBUG_TEMPLATE;
89 }
90
91 private static void init(FacesContext context) throws IOException {
92 if (ERROR_PARTS == null) {
93 ERROR_PARTS = splitTemplate(getErrorTemplate(context));
94 }
95
96 if (DEBUG_PARTS == null) {
97 DEBUG_PARTS = splitTemplate(getDebugTemplate(context));
98 }
99 }
100
101 private static String[] splitTemplate(String rsc) throws IOException {
102 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(rsc);
103 if (is == null) {
104 throw new FileNotFoundException(rsc);
105 }
106 ByteArrayOutputStream baos = new ByteArrayOutputStream();
107 byte[] buff = new byte[512];
108 int read;
109 while ((read = is.read(buff)) != -1) {
110 baos.write(buff, 0, read);
111 }
112 String str = baos.toString();
113 return str.split("@@");
114 }
115
116 public static ArrayList getErrorId(Throwable e){
117 String message = e.getMessage();
118
119 if(message==null)
120 return null;
121
122 ArrayList list = new ArrayList();
123 Pattern pattern = Pattern.compile(".*?\\Q,Id:\\E\\s*(\\S+)\\s*\\].*?");
124 Matcher matcher = pattern.matcher(message);
125
126 while (matcher.find()){
127 list.add(matcher.group(1));
128 }
129 if (list.size()>0) return list;
130 return null;
131 }
132
133 public static void writeCause(Writer writer, Throwable ex) throws IOException {
134 String msg = ex.getMessage();
135 while (ex.getCause()!=null){
136 ex=ex.getCause();
137 if (ex.getMessage()!=null) msg = ex.getMessage();
138 }
139
140 if (msg != null) {
141 msg =ex.getClass().getName() + " - " + msg;
142 writer.write(msg.replaceAll("<", TS));
143 } else {
144 writer.write(ex.getClass().getName());
145 }
146 }
147
148 public static void debugHtml(Writer writer, FacesContext faces, Throwable e) throws IOException {
149 init(faces);
150 Date now = new Date();
151 for (int i = 0; i < ERROR_PARTS.length; i++) {
152 if ("message".equals(ERROR_PARTS[i])) {
153 String msg = e.getMessage();
154 if (msg != null) {
155 writer.write(msg.replaceAll("<", TS));
156 } else {
157 writer.write(e.getClass().getName());
158 }
159 } else if ("trace".equals(ERROR_PARTS[i])) {
160 writeException(writer, e);
161 } else if ("now".equals(ERROR_PARTS[i])) {
162 writer.write(DateFormat.getDateTimeInstance().format(now));
163 } else if ("tree".equals(ERROR_PARTS[i])) {
164 if (faces.getViewRoot() != null) {
165 writeComponent(writer, faces.getViewRoot(), getErrorId(e));
166 }
167 } else if ("vars".equals(ERROR_PARTS[i])) {
168 writeVariables(writer, faces);
169 } else if ("cause".equals(ERROR_PARTS[i])) {
170 writeCause(writer, e);
171 } else {
172 writer.write(ERROR_PARTS[i]);
173 }
174 }
175 }
176
177 public static void debugHtml(Writer writer, FacesContext faces, List exceptionList) throws IOException
178 {
179 init(faces);
180 Date now = new Date();
181 for (int i = 0; i < ERROR_PARTS.length; i++)
182 {
183 if ("message".equals(ERROR_PARTS[i]))
184 {
185 for (int j = 0; j < exceptionList.size(); j++)
186 {
187 Exception e = (Exception) exceptionList.get(j);
188 String msg = e.getMessage();
189 if (msg != null)
190 {
191 writer.write(msg.replaceAll("<", TS));
192 }
193 else
194 {
195 writer.write(e.getClass().getName());
196 }
197 if (!(j+1==exceptionList.size()))
198 {
199 writer.write("<br>");
200 }
201 }
202 }
203 else if ("trace".equals(ERROR_PARTS[i]))
204 {
205 for (int j = 0; j < exceptionList.size(); j++)
206 {
207 Exception e = (Exception) exceptionList.get(j);
208 writeException(writer, e);
209 }
210 }
211 else if ("now".equals(ERROR_PARTS[i]))
212 {
213 writer.write(DateFormat.getDateTimeInstance().format(now));
214 }
215 else if ("tree".equals(ERROR_PARTS[i]))
216 {
217 if (faces.getViewRoot() != null)
218 {
219 List highlightId = null;
220 for (int j = 0; j < exceptionList.size(); j++)
221 {
222 Exception e = (Exception) exceptionList.get(j);
223 if (highlightId == null)
224 {
225 highlightId = getErrorId(e);
226 }
227 else
228 {
229 highlightId.addAll(getErrorId(e));
230 }
231 }
232 writeComponent(writer, faces.getViewRoot(), highlightId);
233 }
234 }
235 else if ("vars".equals(ERROR_PARTS[i]))
236 {
237 writeVariables(writer, faces);
238 }
239 else if ("cause".equals(ERROR_PARTS[i]))
240 {
241 for (int j = 0; j < exceptionList.size(); j++)
242 {
243 Exception e = (Exception) exceptionList.get(j);
244 writeCause(writer, e);
245 if (!(j+1==exceptionList.size()))
246 {
247 writer.write("<br>");
248 }
249 }
250 }
251 else
252 {
253 writer.write(ERROR_PARTS[i]);
254 }
255 }
256 }
257
258 private static void writeException(Writer writer, Throwable e) throws IOException {
259 StringWriter str = new StringWriter(256);
260 PrintWriter pstr = new PrintWriter(str);
261 e.printStackTrace(pstr);
262 pstr.close();
263 writer.write(str.toString().replaceAll("<", TS));
264 }
265
266 public static void debugHtml(Writer writer, FacesContext faces) throws IOException {
267 init(faces);
268 Date now = new Date();
269 for (int i = 0; i < DEBUG_PARTS.length; i++) {
270 if ("message".equals(DEBUG_PARTS[i])) {
271 writer.write(faces.getViewRoot().getViewId());
272 } else if ("now".equals(DEBUG_PARTS[i])) {
273 writer.write(DateFormat.getDateTimeInstance().format(now));
274 } else if ("tree".equals(DEBUG_PARTS[i])) {
275 writeComponent(writer, faces.getViewRoot(), null);
276 } else if ("vars".equals(DEBUG_PARTS[i])) {
277 writeVariables(writer, faces);
278 } else {
279 writer.write(DEBUG_PARTS[i]);
280 }
281 }
282 }
283
284 public static void writeVariables(Writer writer, FacesContext faces) throws IOException {
285 ExternalContext ctx = faces.getExternalContext();
286 writeVariables(writer, ctx.getRequestParameterMap(), "Request Parameters");
287 writeVariables(writer, ctx.getRequestMap(), "Request Attributes");
288 if (ctx.getSession(false) != null) {
289 writeVariables(writer, ctx.getSessionMap(), "Session Attributes");
290 }
291 writeVariables(writer, ctx.getApplicationMap(), "Application Attributes");
292 }
293
294 private static void writeVariables(Writer writer, Map vars, String caption) throws IOException {
295 writer.write("<table><caption>");
296 writer.write(caption);
297 writer.write("</caption><thead><tr><th style=\"width: 10%; \">Name</th><th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
298 boolean written = false;
299 if (!vars.isEmpty()) {
300 SortedMap map = new TreeMap(vars);
301 Map.Entry entry = null;
302 String key = null;
303 for (Iterator itr = map.entrySet().iterator(); itr.hasNext(); ) {
304 entry = (Map.Entry) itr.next();
305 key = entry.getKey().toString();
306 if (key.indexOf('.') == -1) {
307 writer.write("<tr><td>");
308 writer.write(key.replaceAll("<", TS));
309 writer.write("</td><td>");
310 writer.write(entry.getValue().toString().replaceAll("<", TS));
311 writer.write("</td></tr>");
312 written = true;
313 }
314 }
315 }
316 if (!written) {
317 writer.write("<tr><td colspan=\"2\"><em>None</em></td></tr>");
318 }
319 writer.write("</tbody></table>");
320 }
321
322 public static void writeComponent(Writer writer, UIComponent c, List highlightId) throws IOException {
323 writer.write("<dl><dt");
324 if (isText(c)) {
325 writer.write(" class=\"uicText\"");
326 }
327 if (highlightId != null){
328 if ((highlightId.size() > 0) && (highlightId.get(0).equals(c.getId()))){
329 highlightId.remove(0);
330 if (highlightId.size()==0){
331 writer.write(" class=\"highlightComponent\"");
332 }
333 }
334 }
335 writer.write(">");
336
337 boolean hasChildren = c.getChildCount() > 0 || c.getFacets().size() > 0;
338
339 writeStart(writer, c, hasChildren);
340 writer.write("</dt>");
341 if (hasChildren) {
342 if (c.getFacets().size() > 0) {
343 Map.Entry entry;
344 for (Iterator itr = c.getFacets().entrySet().iterator(); itr.hasNext(); ) {
345 entry = (Map.Entry) itr.next();
346 writer.write("<dd class=\"uicFacet\">");
347 writer.write("<span>");
348 writer.write((String) entry.getKey());
349 writer.write("</span>");
350 writeComponent(writer, (UIComponent) entry.getValue(), highlightId);
351 writer.write("</dd>");
352 }
353 }
354 if (c.getChildCount() > 0) {
355 for (Iterator itr = c.getChildren().iterator(); itr.hasNext(); ) {
356 writer.write("<dd>");
357 writeComponent(writer, (UIComponent) itr.next(), highlightId);
358 writer.write("</dd>");
359 }
360 }
361 writer.write("<dt>");
362 writeEnd(writer, c);
363 writer.write("</dt>");
364 }
365 writer.write("</dl>");
366 }
367
368 private static void writeEnd(Writer writer, UIComponent c) throws IOException {
369 if (!isText(c)) {
370 writer.write(TS);
371 writer.write('/');
372 writer.write(getName(c));
373 writer.write('>');
374 }
375 }
376
377 private final static String[] IGNORE = new String[] { "parent", "rendererType" };
378
379 private static void writeAttributes(Writer writer, UIComponent c) {
380 try {
381 BeanInfo info = Introspector.getBeanInfo(c.getClass());
382 PropertyDescriptor[] pd = info.getPropertyDescriptors();
383 Method m = null;
384 Object v = null;
385 String str = null;
386 for (int i = 0; i < pd.length; i++) {
387 if (pd[i].getWriteMethod() != null && Arrays.binarySearch(IGNORE, pd[i].getName()) < 0) {
388 m = pd[i].getReadMethod();
389 try {
390 v = m.invoke(c, null);
391 if (v != null) {
392 if (v instanceof Collection || v instanceof Map || v instanceof Iterator) {
393 continue;
394 }
395 writer.write(" ");
396 writer.write(pd[i].getName());
397 writer.write("=\"");
398 if (v instanceof Expression) {
399 str = ((Expression) v).getExpressionString();
400 }
401 writer.write(str.replaceAll("<", TS));
402 writer.write("\"");
403 }
404 } catch (Exception e) {
405
406 }
407 }
408 }
409
410 ValueExpression binding = c.getValueExpression("binding");
411 if (binding != null) {
412 writer.write(" binding=\"");
413 writer.write(binding.getExpressionString().replaceAll("<", TS));
414 writer.write("\"");
415 }
416 } catch (Exception e) {
417
418 }
419 }
420
421 private static void writeStart(Writer writer, UIComponent c, boolean children) throws IOException {
422 if (isText(c)) {
423 String str = c.toString().trim();
424 writer.write(str.replaceAll("<", TS));
425 } else {
426 writer.write(TS);
427 writer.write(getName(c));
428 writeAttributes(writer, c);
429 if (children) {
430 writer.write('>');
431 } else {
432 writer.write("/>");
433 }
434 }
435 }
436
437 private static String getName(UIComponent c) {
438 String nm = c.getClass().getName();
439 return nm.substring(nm.lastIndexOf('.') + 1);
440 }
441
442 private static boolean isText(UIComponent c) {
443 return (c.getClass().getName().startsWith("com.sun.facelets.compiler"));
444 }
445
446 public static void handleException(FacesContext facesContext, Exception ex) throws ServletException, IOException
447 {
448 handleThrowable(facesContext, ex);
449 }
450
451 public static void handleThrowable(FacesContext facesContext, Throwable ex) throws ServletException, IOException {
452
453 prepareExceptionStack(ex);
454
455 Object response = facesContext.getExternalContext().getResponse();
456 if(response instanceof HttpServletResponse) {
457 HttpServletResponse httpResp = (HttpServletResponse) response;
458 if (!httpResp.isCommitted()) {
459 httpResp.reset();
460 httpResp.setContentType("text/html; charset=UTF-8");
461 Writer writer = httpResp.getWriter();
462
463 debugHtml(writer, facesContext, ex);
464
465 log.error("An exception occurred", ex);
466 }
467 else {
468 throwException(ex);
469 }
470 }
471 else {
472 throwException(ex);
473 }
474 }
475
476 public static void handleExceptionList(FacesContext facesContext, List exceptionList) throws ServletException, IOException
477 {
478 for (int i = 0; i < exceptionList.size(); i++)
479 {
480 prepareExceptionStack( (Exception) exceptionList.get(i));
481 }
482
483 Object response = facesContext.getExternalContext().getResponse();
484 if(response instanceof HttpServletResponse)
485 {
486 HttpServletResponse httpResp = (HttpServletResponse) response;
487 if (!httpResp.isCommitted())
488 {
489 httpResp.reset();
490 httpResp.setContentType("text/html; charset=UTF-8");
491 Writer writer = httpResp.getWriter();
492
493 debugHtml(writer, facesContext, exceptionList);
494
495 for (int i = 0; i < exceptionList.size(); i++)
496 {
497 log.error("An exception occurred", (Exception) exceptionList.get(i));
498 }
499 }
500 else
501 {
502 throwException((Exception)exceptionList.get(0));
503 }
504 }
505 else
506 {
507 throwException((Exception)exceptionList.get(0));
508 }
509 }
510
511 private static void prepareExceptionStack(Throwable ex) {
512
513 if(ex==null)
514 return;
515
516
517 if(!initCausePerReflection(ex,"getRootCause")) {
518 initCausePerReflection(ex,"getCause");
519 }
520
521 prepareExceptionStack(ex.getCause());
522 }
523
524 private static boolean initCausePerReflection(Throwable ex, String methodName) {
525 try {
526 Method causeGetter = ex.getClass().getMethod(methodName,new Class[]{});
527 Throwable rootCause = (Throwable) causeGetter.invoke(ex,new Class[]{});
528 return initCauseIfAvailable(ex,rootCause);
529 } catch (Exception e1) {
530 return false;
531 }
532 }
533
534 static void throwException(Throwable e) throws IOException, ServletException {
535
536 prepareExceptionStack(e);
537
538 if (e instanceof IOException)
539 {
540 throw (IOException)e;
541 }
542 else if (e instanceof ServletException)
543 {
544 throw (ServletException)e;
545 }
546 else
547 {
548 ServletException ex;
549
550 if (e.getMessage() != null) {
551 ex=new ServletException(e.getMessage(), e);
552 }
553 else {
554 ex=new ServletException(e);
555 }
556
557 initCauseIfAvailable(ex, e);
558
559 throw ex;
560 }
561 }
562
563 private static boolean initCauseIfAvailable(Throwable th, Throwable cause) {
564
565 if(cause == null)
566 return false;
567
568 try {
569 Method m = Throwable.class.getMethod("initCause",new Class[]{Throwable.class});
570 m.invoke(th,new Object[]{cause});
571 return true;
572 }
573 catch(Exception e) {
574 return false;
575 }
576 }
577 }
578