// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui; import static org.openstreetmap.josm.gui.help.HelpUtil.ht; import static org.openstreetmap.josm.tools.I18n.tr; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.HttpURLConnection; import java.net.SocketException; import java.net.UnknownHostException; import javax.swing.JOptionPane; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.io.ChangesetClosedException; import org.openstreetmap.josm.io.IllegalDataException; import org.openstreetmap.josm.io.MissingOAuthAccessTokenException; import org.openstreetmap.josm.io.OsmApiException; import org.openstreetmap.josm.io.OsmApiInitializationException; import org.openstreetmap.josm.io.OsmTransferException; import org.openstreetmap.josm.tools.BugReportExceptionHandler; import org.openstreetmap.josm.tools.ExceptionUtil; /** * This utility class provides static methods which explain various exceptions to the user. * */ public class ExceptionDialogUtil { /** * just static utility functions. no constructor */ private ExceptionDialogUtil() { } /** * handles an exception caught during OSM API initialization * * @param e the exception */ public static void explainOsmApiInitializationException(OsmApiInitializationException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainOsmApiInitializationException(e), tr("Error"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#OsmApiInitializationException") ); } /** * handles a ChangesetClosedException * * @param e the exception */ public static void explainChangesetClosedException(ChangesetClosedException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainChangesetClosedException(e), tr("Error"), JOptionPane.ERROR_MESSAGE, ht("/Action/Upload#ChangesetClosed") ); } /** * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412 * * @param e the exception */ public static void explainPreconditionFailed(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainPreconditionFailed(e), tr("Precondition violation"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#OsmApiException") ); } /** * Explains an exception with a generic message dialog * * @param e the exception */ public static void explainGeneric(Exception e) { e.printStackTrace(); BugReportExceptionHandler.handleException(e); } /** * Explains a {@see SecurityException} which has caused an {@see OsmTransferException}. * This is most likely happening when user tries to access the OSM API from within an * applet which wasn't loaded from the API server. * * @param e the exception */ public static void explainSecurityException(OsmTransferException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainSecurityException(e), tr("Security exception"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#SecurityException") ); } /** * Explains a {@see SocketException} which has caused an {@see OsmTransferException}. * This is most likely because there's not connection to the Internet or because * the remote server is not reachable. * * @param e the exception */ public static void explainNestedSocketException(OsmTransferException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainNestedSocketException(e), tr("Network exception"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#NestedSocketException") ); } /** * Explains a {@see IOException} which has caused an {@see OsmTransferException}. * This is most likely happening when the communication with the remote server is * interrupted for any reason. * * @param e the exception */ public static void explainNestedIOException(OsmTransferException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainNestedIOException(e), tr("IO Exception"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#NestedIOException") ); } /** * Explains a {@see IllegalDataException} which has caused an {@see OsmTransferException}. * This is most likely happening when JOSM tries to load data in in an unsupported format. * * @param e the exception */ public static void explainNestedIllegalDataException(OsmTransferException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainNestedIllegalDataException(e), tr("Illegal Data"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#IllegalDataException") ); } /** * Explains a {@see InvocationTargetException } * * @param e the exception */ public static void explainNestedInvocationTargetException(Exception e) { InvocationTargetException ex = getNestedException(e, InvocationTargetException.class); if (ex != null) { // Users should be able to submit a bug report for an invocation target exception // BugReportExceptionHandler.handleException(ex); return; } } /** * Explains a {@see OsmApiException} which was thrown because of an internal server * error in the OSM API server. * * @param e the exception */ public static void explainInternalServerError(OsmTransferException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainInternalServerError(e), tr("Internal Server Error"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#InternalServerError") ); } /** * Explains a {@see OsmApiException} which was thrown because of a bad * request * * @param e the exception */ public static void explainBadRequest(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainBadRequest(e), tr("Bad Request"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#BadRequest") ); } /** * Explains a {@see OsmApiException} which was thrown because a resource wasn't found * on the server * * @param e the exception */ public static void explainNotFound(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainNotFound(e), tr("Not Found"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#NotFound") ); } /** * Explains a {@see OsmApiException} which was thrown because of a conflict * * @param e the exception */ public static void explainConflict(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainConflict(e), tr("Conflict"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#Conflict") ); } /** * Explains a {@see OsmApiException} which was thrown because the authentication at * the OSM server failed * * @param e the exception */ public static void explainAuthenticationFailed(OsmApiException e) { String authMethod = Main.pref.get("osm-server.auth-method", "basic"); String msg; if (authMethod.equals("oauth")) { msg = ExceptionUtil.explainFailedOAuthAuthentication(e); } else { msg = ExceptionUtil.explainFailedBasicAuthentication(e); } HelpAwareOptionPane.showOptionDialog( Main.parent, msg, tr("Authentication Failed"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#AuthenticationFailed") ); } /** * Explains a {@see OsmApiException} which was thrown because accessing a protected * resource was forbidden. * * @param e the exception */ public static void explainAuthorizationFailed(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainFailedOAuthAuthorisation(e), tr("Authorisation Failed"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#AuthenticationFailed") ); } /** * Explains a {@see OsmApiException} which was thrown because of a * client timeout (HTTP 408) * * @param e the exception */ public static void explainClientTimeout(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainClientTimeout(e), tr("Client Time Out"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#ClientTimeOut") ); } /** * Explains a {@see OsmApiException} with a generic error * message. * * @param e the exception */ public static void explainGenericHttpException(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainClientTimeout(e), tr("Communication with OSM server failed"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#GenericCommunicationError") ); } /** * Explains a {@see OsmApiException} which was thrown because accessing a protected * resource was forbidden. * * @param e the exception */ public static void explainMissingOAuthAccessTokenException(MissingOAuthAccessTokenException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainMissingOAuthAccessTokenException(e), tr("Authentication failed"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#MissingOAuthAccessToken") ); } /** * Explains a {@see UnknownHostException} which has caused an {@see OsmTransferException}. * This is most likely happening when there is an error in the API URL or when * local DNS services are not working. * * @param e the exception */ public static void explainNestedUnkonwnHostException(OsmTransferException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainNestedUnkonwnHostException(e), tr("Unknown host"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#UnknownHost") ); } /** * Replies the first nested exception of type <code>nestedClass</code> (including * the root exception <code>e</code>) or null, if no such exception is found. * * @param <T> * @param e the root exception * @param nestedClass the type of the nested exception * @return the first nested exception of type <code>nestedClass</code> (including * the root exception <code>e</code>) or null, if no such exception is found. */ protected static <T> T getNestedException(Exception e, Class<T> nestedClass) { Throwable t = e; while (t != null && !(nestedClass.isInstance(t))) { t = t.getCause(); } if (t == null) return null; else if (nestedClass.isInstance(t)) return nestedClass.cast(t); return null; } /** * Explains an {@see OsmTransferException} to the user. * * @param e the {@see OsmTransferException} */ public static void explainOsmTransferException(OsmTransferException e) { if (getNestedException(e, SecurityException.class) != null) { explainSecurityException(e); return; } if (getNestedException(e, SocketException.class) != null) { explainNestedSocketException(e); return; } if (getNestedException(e, UnknownHostException.class) != null) { explainNestedUnkonwnHostException(e); return; } if (getNestedException(e, IOException.class) != null) { explainNestedIOException(e); return; } if (getNestedException(e, IllegalDataException.class) != null) { explainNestedIllegalDataException(e); return; } if (e instanceof OsmApiInitializationException) { explainOsmApiInitializationException((OsmApiInitializationException) e); return; } if (e instanceof ChangesetClosedException) { explainChangesetClosedException((ChangesetClosedException)e); return; } if (e instanceof MissingOAuthAccessTokenException) { explainMissingOAuthAccessTokenException((MissingOAuthAccessTokenException)e); return; } if (e instanceof OsmApiException) { OsmApiException oae = (OsmApiException) e; switch(oae.getResponseCode()) { case HttpURLConnection.HTTP_PRECON_FAILED: explainPreconditionFailed(oae); return; case HttpURLConnection.HTTP_GONE: explainGoneForUnknownPrimitive(oae); return; case HttpURLConnection.HTTP_INTERNAL_ERROR: explainInternalServerError(oae); return; case HttpURLConnection.HTTP_BAD_REQUEST: explainBadRequest(oae); return; case HttpURLConnection.HTTP_NOT_FOUND: explainNotFound(oae); return; case HttpURLConnection.HTTP_CONFLICT: explainConflict(oae); return; case HttpURLConnection.HTTP_UNAUTHORIZED: explainAuthenticationFailed(oae); return; case HttpURLConnection.HTTP_FORBIDDEN: explainAuthorizationFailed(oae); return; case HttpURLConnection.HTTP_CLIENT_TIMEOUT: explainClientTimeout(oae); return; default: explainGenericHttpException(oae); return; } } explainGeneric(e); } /** * explains the case of an error due to a delete request on an already deleted * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which * {@see OsmPrimitive} is causing the error. * * @param e the exception */ public static void explainGoneForUnknownPrimitive(OsmApiException e) { HelpAwareOptionPane.showOptionDialog( Main.parent, ExceptionUtil.explainGoneForUnknownPrimitive(e), tr("Object deleted"), JOptionPane.ERROR_MESSAGE, ht("/ErrorMessages#GoneForUnknownPrimitive") ); } /** * Explains an {@see Exception} to the user. * * @param e the {@see Exception} */ public static void explainException(Exception e) { if (getNestedException(e, InvocationTargetException.class) != null) { explainNestedInvocationTargetException(e); return; } if (e instanceof OsmTransferException) { explainOsmTransferException((OsmTransferException) e); return; } explainGeneric(e); } }