1 package net.jaekl.frank;
3 import java.io.ByteArrayOutputStream;
4 import java.io.PrintStream;
5 import java.io.PrintWriter;
6 import java.net.SocketTimeoutException;
7 import java.text.MessageFormat;
8 import java.util.Locale;
10 import net.jaekl.qd.http.InvalidResponseException;
12 public class ErrorHandler {
13 static final String JAVASCRIPT_PART1 =
15 " var show_hide = function() {\n" +
16 " var theDiv = document.getElementById('details');\n" +
17 " var theButton = document.getElementById('details_btn');\n" +
18 " if (theDiv.style.display === 'block' || theDiv.style.display === '') {\n" +
19 " theDiv.style.display = 'none';\n" +
20 " theButton.value = '";
21 // insert "show details" text here
22 static final String JAVASCRIPT_PART2 = "';\n" +
25 " theDiv.style.display = 'block';\n" +
26 " theButton.value = '";
27 // insert "hide details" text here
28 static final String JAVASCRIPT_PART3 = "';\n" +
33 void writeScript(PrintWriter pw, FrankBundle bundle) {
34 String javaScript = JAVASCRIPT_PART1 +
35 bundle.get(FrankBundle.SHOW_DETAILS) +
37 bundle.get(FrankBundle.HIDE_DETAILS) +
40 pw.println(javaScript);
43 void explain(PrintWriter pw, Throwable t, FrankBundle bundle) {
45 if (t instanceof FrankException) {
46 if (null != t.getCause()) {
52 if (cause instanceof InvalidResponseException) {
53 InvalidResponseException ire = (InvalidResponseException)cause;
55 pw.println(bundle.get(FrankBundle.INVALID_RESPONSE));
56 pw.println("<P ID=\"errtable\">");
57 pw.println(" <TABLE>");
58 pw.println(" <TR><TD CLASS=\"head\">" + bundle.get(FrankBundle.URL_CONTACTED)
59 + "</TD><TD>" + ire.getUrl() + "</TD></TR>");
60 pw.println(" <TR CLASS=\"alt\"><TD CLASS=\"head\">" + bundle.get(FrankBundle.REQUEST_MADE)
61 + "</TD><TD>" + ire.getMethod() + "</TD></TR>");
62 pw.println(" <TR><TD CLASS=\"head\">" + bundle.get(FrankBundle.ANSWER_RECEIVED)
63 + "</TD><TD>" + ire.getResponse() + "</TD></TR>");
64 pw.println(" </TABLE>");
66 pw.println("<P>" + bundle.get(FrankBundle.MAYBE_SERVER_PROBLEM) + "</P>");
68 else if (cause instanceof SocketTimeoutException) {
69 pw.println(bundle.get(FrankBundle.SERVER_TIMEOUT));
72 pw.println(bundle.get(FrankBundle.UNEXPECTED_EXCEPTION));
77 void writeErrorPage(PrintWriter pw, Throwable t, Locale locale) {
78 Style style = new Style();
79 ByteArrayOutputStream baos = new ByteArrayOutputStream();
80 PrintStream ps = new PrintStream(baos);
81 FrankBundle bundle = FrankBundle.getInst(locale);
83 pw.println("<HTML><HEAD>");
84 pw.println("<TITLE>" +
85 bundle.get(FrankBundle.FRANK) + ": " +
86 bundle.get(FrankBundle.ERROR_PAGE) +
89 writeScript(pw, bundle);
90 pw.println("</HEAD>");
93 pw.println("<TABLE ID=\"errhead\" WIDTH=\"100%\"><TR><TD>" +
94 bundle.get(FrankBundle.FRANK) + ": " +
95 bundle.get(FrankBundle.UNEXPECTED_ERROR) +
96 "</TD></TR></TABLE>");
98 explain(pw, t, bundle);
100 // Note that, if we cared about security, we would log this stack trace to a
101 // server log, and only report a cross-reference to the log file back to the
102 // end user's browser, to avoid potentially exposing internal info that we
103 // don't want to share.
104 // At least at this point, we don't care (that much), and trade off a
105 // potential information leak in favour of reducing our code complexity
106 // and the administrator's workload.
108 pw.println("<P><INPUT TYPE=\"button\" ID=\"details_btn\" VALUE=\"" +
109 bundle.get(FrankBundle.SHOW_DETAILS) +
110 "\" ONCLICK=\"show_hide();\"/></P>");
112 pw.println("<DIV ID=\"details\" STYLE=\"display: none;\"><PRE>");
114 t.printStackTrace(ps);
115 String stackTrace = baos.toString();
116 pw.println(stackTrace);
118 pw.println("</PRE>\n</P>\n</DIV>");
120 String returnToMainFormat = bundle.get(FrankBundle.RETURN_TO_MAIN_PAGE);
121 String returnToMain = MessageFormat.format(returnToMainFormat, "/");
122 pw.println("<P>" + returnToMain + "</P>");
123 pw.println("</BODY></HTML>");