/* GNU GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Contact info: lobochief@users.sourceforge.net */ package org.lobobrowser.primary.ext; import java.awt.Component; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.util.logging.Level; import java.util.logging.Logger; import org.lobobrowser.clientlet.ClientletException; import org.lobobrowser.clientlet.ClientletResponse; import org.lobobrowser.clientlet.ComponentContent; import org.lobobrowser.clientlet.JavaVersionException; import org.lobobrowser.clientlet.NavigatorVersionException; import org.lobobrowser.html.HtmlRendererContext; import org.lobobrowser.html.gui.HtmlPanel; import org.lobobrowser.js.JavaScript; import org.lobobrowser.main.PlatformInit; import org.lobobrowser.primary.clientlets.PrimaryClientletSelector; import org.lobobrowser.primary.clientlets.html.HtmlContent; import org.lobobrowser.primary.clientlets.html.HtmlRendererContextImpl; import org.lobobrowser.request.UserAgentImpl; import org.lobobrowser.ua.NavigationEntry; import org.lobobrowser.ua.NavigatorErrorListener; import org.lobobrowser.ua.NavigatorExceptionEvent; import org.lobobrowser.ua.NavigatorExtension; import org.lobobrowser.ua.NavigatorExtensionContext; import org.lobobrowser.ua.NavigatorFrame; import org.lobobrowser.ua.NavigatorWindow; import org.lobobrowser.util.Html; import org.lobobrowser.util.Strings; import org.w3c.dom.html.HTMLDocument; public class ExtensionImpl implements NavigatorExtension { private static final Logger logger = Logger.getLogger(ExtensionImpl.class.getName()); public void destroy() { } public void init(final NavigatorExtensionContext pcontext) { pcontext.addURLStreamHandlerFactory(new PrimaryStreamHandlerFactory()); pcontext.addClientletSelector(new PrimaryClientletSelector()); pcontext.addNavigatorErrorListener(new NavigatorErrorListener() { public void errorOcurred(final NavigatorExceptionEvent event) { showError(event.getNavigatorFrame(), event.getResponse(), event.getException()); } }); JavaScript.init(); } public void windowClosing(final NavigatorWindow wcontext) { NavigationHistory.getInstance().save(); } public void windowOpening(final NavigatorWindow wcontext) { final ComponentSource cs = new ComponentSource(wcontext); final Component[] abc = cs.getAddressBarComponents(); for (final Component c : abc) { wcontext.addAddressBarComponent(c); } final Component[] sbc = cs.getStatusBarComponents(); for (final Component c : sbc) { wcontext.addStatusBarComponent(c); } wcontext.addMenu("lobo.file", cs.getFileMenu()); wcontext.addMenu("lobo.edit", cs.getEditMenu()); wcontext.addMenu("lobo.view", cs.getViewMenu()); wcontext.addMenu("lobo.navigation", cs.getNavigationMenu()); wcontext.addMenu("lobo.bookmarks", cs.getBookmarksMenu()); wcontext.addMenu("lobo.directory", cs.getDirectoryMenu()); wcontext.addMenu("lobo.page.services", cs.getPageServicesMenu()); wcontext.addMenu("lobo.tools", cs.getToolsMenu()); // wcontext.addMenu("lobo.extensions", cs.getExtensionsMenu()); wcontext.addMenu("lobo.help", cs.getHelpMenu()); wcontext.addNavigatorWindowListener(cs); final NavigationEntry firstEntry = wcontext.getCurrentNavigationEntry(); cs.setNavigationEntry(firstEntry); } public static void showError(final NavigatorFrame frame, final ClientletResponse response, final Throwable exception) { if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, "showError(): An error occurred trying to process document " + (response == null ? "[null]" : response.getResponseURL()), exception); } final ComponentContent errorComponent = getErrorComponent(frame, response, exception); frame.replaceContent(response, errorComponent); // TODO: Get window or something, and ensure current URL is shown. } private static ComponentContent getErrorComponent(final NavigatorFrame frame, final ClientletResponse response, final Throwable exception) { final HtmlPanel panel = new HtmlPanel(); final HtmlRendererContext rcontext = HtmlRendererContextImpl.getHtmlRendererContext(frame); panel.setHtml(getErrorHtml(response, exception), "about:error", rcontext); String sourceCode = "[NOT AVAILABLE]"; if (exception instanceof ClientletException) { final ClientletException ce = (ClientletException) exception; final String sc = ce.getSourceCode(); if (sc != null) { sourceCode = sc; } } return new HtmlContent((HTMLDocument) panel.getRootNode(), panel, sourceCode); } private static Throwable getRootCause(Throwable t) { while (t.getCause() != null) { t = t.getCause(); } return t; } static String getErrorHtml(final ClientletResponse response, final Throwable exception) { final java.net.URL url = response == null ? null : response.getResponseURL(); final String method = response == null ? null : response.getLastRequestMethod(); final Writer swriter = new StringWriter(); final PrintWriter writer = new PrintWriter(swriter); writer.println("<html><body>"); writer.println("<dl style='background-color: #FFE0E0; border: 1px solid red; padding: 1em;'>"); writer.println(" <big>An <strong>error</strong> occurred trying to process a request.</big>"); writer.println(" <br>"); if (url != null) { writer.println(" <h3>URL:</h3>"); writer.println(" <dd>" + getErrorUrlText(url, method) + "</dd>"); } writer.println(" <h3>Exception:</h3>"); writer.println(" <p>" + exception.getClass().getName() + "</p>"); writer.println(" <h3>Meaning</h3>"); writer.println(" <div>" + getExceptionMeaning(url, exception) + "</div>"); writer.println(" <h3>Message:</h3>"); writer.println(" <div>" + Html.textToHTML(exception.getMessage()) + "</div>"); writer.println("</dl>"); writer.println("<p></p>"); if (PlatformInit.getInstance().debugOn) { writer.println("<table border='1' width='100%' style='background-color: #E0E0FF; bolder: solid red 2px;'>"); writer.println(" <tr><th style='padding:.2em'>Details</th></tr>"); writer.println(" <tr><td style='padding:.2em'>"); final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw); exception.printStackTrace(pw); pw.flush(); writer.println(Html.textToHTML(sw.toString())); if (exception.getCause() != null) { final Throwable rootCause = getRootCause(exception); final StringWriter sw2 = new StringWriter(); final PrintWriter pw2 = new PrintWriter(sw2); rootCause.printStackTrace(pw2); pw2.flush(); writer.println("<p><strong>Root Cause</strong></p>"); writer.println(Html.textToHTML(sw2.toString())); } writer.println(" </td></tr>"); writer.println("</table>"); } writer.println("</body><html>"); writer.flush(); return swriter.toString(); } private static String getErrorUrlText(final java.net.URL url, final String method) { final StringBuffer buf = new StringBuffer(); final boolean isGet = "GET".equals(method); if (isGet) { buf.append("<a href=\"" + url.toExternalForm() + "\">"); } buf.append(Strings.truncate(url.toExternalForm(), 80)); if (isGet) { buf.append("</a>"); } return buf.toString(); } private static String getExceptionMeaning(final java.net.URL url, final Throwable exception) { if (exception instanceof org.lobobrowser.clientlet.JavaVersionException) { final JavaVersionException jve = (JavaVersionException) exception; return "This exception is thrown when the content expects the user's Java Virtual Machine " + "to be more up to date than it currently is. In this case the content is " + "expecting version " + jve.getExpectingVersion() + " whereas the version running " + "the browser is " + System.getProperty("java.version") + "."; } else if (exception instanceof NavigatorVersionException) { final NavigatorVersionException nve = (NavigatorVersionException) exception; return "This exception is thrown when the content expects the browser version " + "to be more up to date than it currently is. In this case the content is " + "expecting version " + nve.getExpectingVersion() + " whereas the user agent " + "version is " + UserAgentImpl.getInstance().getVersion() + "."; } else { Throwable cause = exception; if (exception instanceof ClientletException) { cause = ((ClientletException) exception).getCause(); if (cause == null) { // oops cause = exception; } } else if (exception instanceof java.lang.reflect.InvocationTargetException) { cause = ((java.lang.reflect.InvocationTargetException) exception).getCause(); } if (cause instanceof java.net.MalformedURLException) { return "A URL or URI was not formatted correctly."; } else if (cause instanceof javax.net.ssl.SSLHandshakeException) { return "<p>This is most likely caused due to a JVM with crippled cipher suites.</p>" + "<p>We are actively working on this. Please see https://github.com/UprootLabs/gngr/wiki/SSL-Handshake-Failures</p>"; } else if (cause instanceof java.net.UnknownHostException) { return "The host named '" + ((java.net.UnknownHostException) cause).getMessage() + "' could not be found by the Domain Name Service (DNS)."; } else if (cause instanceof java.lang.SecurityException) { return "An attempted security violation has been detected and stopped."; } else if (cause instanceof java.net.ProtocolException) { return "Indicates there is an error in the underlying communications protocol."; } else if (cause instanceof java.net.SocketTimeoutException) { return "It means the server accepted the connection, but failed to respond after a long period of time. This is usually indicative of a server problem."; } else if (cause instanceof java.net.ConnectException) { return "It means a connection to the server could not be obtained. Typically, the server has refused the connection, i.e. it's not accepting connections on a given port."; } else if (cause instanceof java.net.SocketException) { return "Indicates there was an error in the underlying protocol, e.g. TCP/IP."; } else if (cause instanceof java.io.IOException) { return "Indicates an Input/Output error has occurred. This is typically due " + "to a network connection that cannot be establised or one that has failed, " + "but it can also mean that a file could not be accessed or found."; } else if ((cause instanceof java.lang.NullPointerException) || (cause instanceof java.lang.ClassCastException)) { return "This is a common Java exception that generally occurs due to a programming error. " + "The stack trace will show if the error is in browser code, an extension or the document itself."; } else if (cause instanceof ClientletException) { return "A " + ClientletException.class.getSimpleName() + " is thrown by extensions or documents typically to indicate an unexpected state has been encountered."; } else { return "Unknown."; } } } }