--- /dev/null
+package net.jaekl.frank;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+import net.jaekl.qd.http.InvalidResponseException;
+
+public class ErrorHandler {
+ static final String JAVASCRIPT =
+ "<SCRIPT>\n" +
+ " var show_hide = function() {\n" +
+ " var theDiv = document.getElementById('details');\n" +
+ " var theButton = document.getElementById('details_btn');\n" +
+ " if (theDiv.style.display === 'block' || theDiv.style.display === '') {\n" +
+ " theDiv.style.display = 'none';\n" +
+ " theButton.value = 'Show details';\n" +
+ " }\n" +
+ " else {\n" +
+ " theDiv.style.display = 'block';\n" +
+ " theButton.value = 'Hide details';\n" +
+ " }\n" +
+ "}\n" +
+ "</SCRIPT>";
+
+ void writeScript(PrintWriter pw) {
+ pw.println(JAVASCRIPT);
+ }
+
+ void explain(PrintWriter pw, Throwable t, FrankBundle bundle) {
+ Throwable cause = t;
+ if (t instanceof FrankException) {
+ if (null != t.getCause()) {
+ cause = t.getCause();
+ }
+ }
+
+ pw.println("<P>");
+ if (cause instanceof InvalidResponseException) {
+ InvalidResponseException ire = (InvalidResponseException)cause;
+
+ pw.println(bundle.get(FrankBundle.INVALID_RESPONSE));
+ pw.println("<P ID=\"errtable\">");
+ pw.println(" <TABLE>");
+ pw.println(" <TR><TD CLASS=\"head\">" + bundle.get(FrankBundle.URL_CONTACTED)
+ + "</TD><TD>" + ire.getUrl() + "</TD></TR>");
+ pw.println(" <TR CLASS=\"alt\"><TD CLASS=\"head\">" + bundle.get(FrankBundle.REQUEST_MADE)
+ + "</TD><TD>" + ire.getMethod() + "</TD></TR>");
+ pw.println(" <TR><TD CLASS=\"head\">" + bundle.get(FrankBundle.ANSWER_RECEIVED)
+ + "</TD><TD>" + ire.getResponse() + "</TD></TR>");
+ pw.println(" </TABLE>");
+ pw.println("</P>");
+ pw.println("<P>" + bundle.get(FrankBundle.MAYBE_SERVER_PROBLEM) + "</P>");
+ }
+ else {
+ pw.println(bundle.get(FrankBundle.UNEXPECTED_EXCEPTION));
+ }
+ pw.println("</P>");
+ }
+
+ void writeErrorPage(PrintWriter pw, Throwable t, Locale locale) {
+ Style style = new Style();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ FrankBundle bundle = FrankBundle.getInst(locale);
+
+ pw.println("<HTML><HEAD>");
+ pw.println("<TITLE>" +
+ bundle.get(FrankBundle.FRANK) + ": " +
+ bundle.get(FrankBundle.ERROR_PAGE) +
+ "</TITLE>");
+ style.writeStyle(pw);
+ writeScript(pw);
+ pw.println("</HEAD>");
+
+ pw.println("<BODY>");
+ pw.println("<TABLE ID=\"errhead\" WIDTH=\"100%\"><TR><TD>" +
+ bundle.get(FrankBundle.FRANK) + ": " +
+ bundle.get(FrankBundle.UNEXPECTED_ERROR) +
+ "</TD></TR></TABLE>");
+
+ explain(pw, t, bundle);
+
+ // Note that, if we cared about security, we would log this stack trace to a
+ // server log, and only report a cross-reference to the log file back to the
+ // end user's browser, to avoid potentially exposing internal info that we
+ // don't want to share.
+ // At least at this point, we don't care (that much), and trade off a
+ // potential information leak in favour of reducing our code complexity
+ // and the administrator's workload.
+
+ pw.println("<P><INPUT TYPE=\"button\" ID=\"details_btn\" VALUE=\"Show details\" ONCLICK=\"show_hide();\"/></P>");
+ pw.println("<P>");
+ pw.println("<DIV ID=\"details\" STYLE=\"display: none;\"><PRE>");
+
+ t.printStackTrace(ps);
+ String stackTrace = baos.toString();
+ pw.println(stackTrace);
+
+ pw.println("</PRE>\n</P>\n</DIV>");
+ pw.println("<P>Click <A HREF=\"/\">here</A> to return to the main page.</P>");
+ pw.println("</BODY></HTML>");
+ }
+}