Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java =================================================================== --- src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java (revision 2091) +++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java (working copy) @@ -16,7 +16,6 @@ import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.DataSource; -import org.openstreetmap.josm.gui.ExceptionDialogUtil; import org.openstreetmap.josm.gui.PleaseWaitRunnable; import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask; import org.openstreetmap.josm.gui.layer.Layer; @@ -27,6 +26,7 @@ import org.openstreetmap.josm.io.OsmServerLocationReader; import org.openstreetmap.josm.io.OsmServerReader; import org.openstreetmap.josm.io.OsmTransferException; +import org.openstreetmap.josm.tools.ExceptionUtil; import org.xml.sax.SAXException; @@ -106,15 +106,14 @@ if (canceled) return; if (lastException != null) { - ExceptionDialogUtil.explainException(lastException); + getProgressMonitor().setErrorMessage(ExceptionUtil.explainException(lastException)); DownloadOsmTask.this.setFailed(true); return; } if (dataSet == null) return; // user canceled download or error occurred - if (currentBounds == null) { + if (currentBounds == null) return; // no data retrieved - } if (dataSet.allPrimitives().isEmpty()) { progressMonitor.setErrorMessage(tr("No data imported.")); // need to synthesize a download bounds lest the visual indication of downloaded Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java =================================================================== --- src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java (revision 2091) +++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java (working copy) @@ -94,11 +94,14 @@ progressMonitor.finishTask(); String errors = ""; + LinkedList shown = new LinkedList(); for(DownloadTask dt : osmTasks) { String err = dt.getErrorMessage(); - if(err.equals("")) { + // avoid display of identical messages + if (err.equals("") || shown.contains(err.hashCode())) { continue; } + shown.add(err.hashCode()); errors += "
* " + err; } Index: src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java =================================================================== --- src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java (revision 2091) +++ src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java (working copy) @@ -5,19 +5,17 @@ import java.io.IOException; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.SocketException; -import java.net.URL; import java.net.UnknownHostException; import javax.swing.JOptionPane; import org.openstreetmap.josm.Main; -import org.openstreetmap.josm.io.OsmApi; import org.openstreetmap.josm.io.OsmApiException; import org.openstreetmap.josm.io.OsmApiInitializationException; import org.openstreetmap.josm.io.OsmChangesetCloseException; import org.openstreetmap.josm.io.OsmTransferException; +import org.openstreetmap.josm.tools.ExceptionUtil; /** * This utility class provides static methods which explain various exceptions to the user. @@ -28,7 +26,8 @@ /** * just static utility functions. no constructor */ - private ExceptionDialogUtil() {} + private ExceptionDialogUtil() { + } /** * handles an exception caught during OSM API initialization @@ -36,16 +35,8 @@ * @param e the exception */ public static void explainOsmApiInitializationException(OsmApiInitializationException e) { - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - tr( "Failed to initialize communication with the OSM server {0}.
" - + "Check the server URL in your preferences and your internet connection.", - Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api") - ), - tr("Error"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainOsmApiInitializationException(e), tr("Error"), + JOptionPane.ERROR_MESSAGE); } /** @@ -54,60 +45,28 @@ * @param e the exception */ public static void explainOsmChangesetCloseException(OsmChangesetCloseException e) { - e.printStackTrace(); - String changsetId = e.getChangeset() == null ? tr("unknown") : Long.toString(e.getChangeset().getId()); - JOptionPane.showMessageDialog( - Main.parent, - tr( "Failed to close changeset ''{0}'' on the OSM server ''{1}''.
" - + "The changeset will automatically be closed by the server after a timeout.", - changsetId, - Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api") - ), - tr("Error"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainOsmChangesetCloseException(e), tr("Error"), + JOptionPane.ERROR_MESSAGE); } - /** * 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) { - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - tr("Uploading to the server failed because your current
" - +"dataset violates a precondition.
" - +"The error message is:
" - + "{0}" - + "", - e.getMessage().replace("&", "&").replace("<", "<").replace(">", ">") - ), - tr("Precondition violation"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainPreconditionFailed(e), + tr("Precondition violation"), JOptionPane.ERROR_MESSAGE); } - /** * Explains an exception with a generic message dialog * * @param e the exception */ public static void explainGeneric(Exception e) { - String msg = e.getMessage(); - if (msg == null || msg.trim().equals("")) { - msg = e.toString(); - } - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - msg, - tr("Error"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainGeneric(e), tr("Error"), + JOptionPane.ERROR_MESSAGE); } /** @@ -119,26 +78,8 @@ */ public static void explainSecurityException(OsmTransferException e) { - String apiUrl = OsmApi.getOsmApi().getBaseUrl(); - String host = tr("unknown"); - try { - host = new URL(apiUrl).getHost(); - } catch(MalformedURLException ex) { - // shouldn't happen - } - - String message = tr("Failed to open a connection to the remote server
" - + "''{0}''
" - + "for security reasons. This is most likely because you are running
" - + "in an applet and because you didn''t load your applet from ''{1}''.", - apiUrl, host - ); - JOptionPane.showMessageDialog( - Main.parent, - message, - tr("Security exception"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainSecurityException(e), tr("Security exception"), + JOptionPane.ERROR_MESSAGE); } /** @@ -150,19 +91,8 @@ */ public static void explainNestedSocketException(OsmTransferException e) { - String apiUrl = OsmApi.getOsmApi().getBaseUrl(); - String message = tr("Failed to open a connection to the remote server
" - + "''{0}''.
" - + "Please check your internet connection.", - apiUrl - ); - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - message, - tr("Network exception"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainNestedSocketException(e), + tr("Network exception"), JOptionPane.ERROR_MESSAGE); } /** @@ -174,21 +104,8 @@ */ public static void explainNestedIOException(OsmTransferException e) { - IOException ioe = getNestedException(e, IOException.class); - String apiUrl = OsmApi.getOsmApi().getBaseUrl(); - String message = tr("Failed to upload data to or download data from
" - + "''{0}''
" - + "due to a problem with transferring data.
" - + "Details(untranslated): {1}", - apiUrl, ioe.getMessage() - ); - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - message, - tr("IO Exception"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainNestedIOException(e), tr("IO Exception"), + JOptionPane.ERROR_MESSAGE); } /** @@ -199,20 +116,8 @@ */ public static void explainInternalServerError(OsmTransferException e) { - String apiUrl = OsmApi.getOsmApi().getBaseUrl(); - String message = tr("The OSM server
" - + "''{0}''
" - + "reported an internal server error.
" - + "This is most likely a temporary problem. Please try again later.", - apiUrl - ); - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - message, - tr("Internal Server Error"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainInternalServerError(e), + tr("Internal Server Error"), JOptionPane.ERROR_MESSAGE); } /** @@ -222,24 +127,8 @@ * @param e the exception */ public static void explainBadRequest(OsmApiException e) { - String apiUrl = OsmApi.getOsmApi().getBaseUrl(); - String message = tr("The OSM server ''{0}'' reported a bad request.
", - apiUrl - ); - if (e.getErrorHeader() != null && e.getErrorHeader().startsWith("The maximum bbox")) { - message += "
" + tr("The area you tried to download is too big or your request was too large." - + "
Either request a smaller area or use an export file provided by the OSM community."); - } else if (e.getErrorHeader() != null){ - message += tr("
Error message(untranslated): {0}", e.getErrorHeader()); - } - message = "" + message + ""; - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - message, - tr("Bad Request"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainBadRequest(e), tr("Bad Request"), + JOptionPane.ERROR_MESSAGE); } /** @@ -251,27 +140,8 @@ */ public static void explainNestedUnkonwnHostException(OsmTransferException e) { - String apiUrl = OsmApi.getOsmApi().getBaseUrl(); - String host = tr("unknown"); - try { - host = new URL(apiUrl).getHost(); - } catch(MalformedURLException ex) { - // shouldn't happen - } - - String message = tr("Failed to open a connection to the remote server
" - + "''{0}''.
" - + "Host name ''{1}'' couldn''t be resolved.
" - + "Please check the API URL in your preferences and your internet connection.", - apiUrl, host - ); - e.printStackTrace(); - JOptionPane.showMessageDialog( - Main.parent, - message, - tr("Unknown host"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainNestedUnkonwnHostException(e), + tr("Unknown host"), JOptionPane.ERROR_MESSAGE); } /** @@ -289,7 +159,7 @@ while (t != null && !(nestedClass.isInstance(t))) { t = t.getCause(); } - if (t== null) + if (t == null) return null; else if (nestedClass.isInstance(t)) return nestedClass.cast(t); @@ -318,17 +188,17 @@ explainNestedIOException(e); return; } - if (e instanceof OsmApiInitializationException){ - explainOsmApiInitializationException((OsmApiInitializationException)e); + if (e instanceof OsmApiInitializationException) { + explainOsmApiInitializationException((OsmApiInitializationException) e); return; } - if (e instanceof OsmChangesetCloseException){ - explainOsmChangesetCloseException((OsmChangesetCloseException)e); + if (e instanceof OsmChangesetCloseException) { + explainOsmChangesetCloseException((OsmChangesetCloseException) e); return; } if (e instanceof OsmApiException) { - OsmApiException oae = (OsmApiException)e; + OsmApiException oae = (OsmApiException) e; if (oae.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) { explainPreconditionFailed(oae); return; @@ -357,20 +227,8 @@ * @param e the exception */ public static void explainGoneForUnknownPrimitive(OsmApiException e) { - String msg = tr("Uploading failed because a primitive you tried to
" - + "delete on the server is already deleted.
" - + "
" - + "The error message is:
" - + "{0}" - + "", - e.getMessage().replace("&", "&").replace("<", "<").replace(">", ">") - ); - JOptionPane.showMessageDialog( - Main.parent, - msg, - tr("Primitive already deleted"), - JOptionPane.ERROR_MESSAGE - ); + JOptionPane.showMessageDialog(Main.parent, ExceptionUtil.explainGoneForUnknownPrimitive(e), + tr("Primitive already deleted"), JOptionPane.ERROR_MESSAGE); } @@ -381,7 +239,7 @@ */ public static void explainException(Exception e) { if (e instanceof OsmTransferException) { - explainOsmTransferException((OsmTransferException)e); + explainOsmTransferException((OsmTransferException) e); return; } explainGeneric(e); Index: src/org/openstreetmap/josm/tools/ExceptionUtil.java =================================================================== --- src/org/openstreetmap/josm/tools/ExceptionUtil.java (revision 0) +++ src/org/openstreetmap/josm/tools/ExceptionUtil.java (revision 0) @@ -0,0 +1,279 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.tools; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.SocketException; +import java.net.URL; +import java.net.UnknownHostException; + +import org.openstreetmap.josm.Main; +import org.openstreetmap.josm.io.OsmApi; +import org.openstreetmap.josm.io.OsmApiException; +import org.openstreetmap.josm.io.OsmApiInitializationException; +import org.openstreetmap.josm.io.OsmChangesetCloseException; +import org.openstreetmap.josm.io.OsmTransferException; + +public class ExceptionUtil { + private ExceptionUtil() { + } + + /** + * handles an exception caught during OSM API initialization + * + * @param e the exception + */ + public static String explainOsmApiInitializationException(OsmApiInitializationException e) { + e.printStackTrace(); + String msg = tr( + "Failed to initialize communication with the OSM server {0}.
" + + "Check the server URL in your preferences and your internet connection.", Main.pref.get( + "osm-server.url", "http://api.openstreetmap.org/api")); + return msg; + } + + /** + * handles an exception caught during OSM API initialization + * + * @param e the exception + */ + public static String explainOsmChangesetCloseException(OsmChangesetCloseException e) { + e.printStackTrace(); + String changsetId = e.getChangeset() == null ? tr("unknown") : Long.toString(e.getChangeset().getId()); + String msg = tr( + "Failed to close changeset ''{0}'' on the OSM server ''{1}''.
" + + "The changeset will automatically be closed by the server after a timeout.", changsetId, + Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api")); + return msg; + } + + + /** + * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412 + * + * @param e the exception + */ + public static String explainPreconditionFailed(OsmApiException e) { + e.printStackTrace(); + String msg = tr( + "Uploading to the server failed because your current
" + + "dataset violates a precondition.
" + "The error message is:
" + "{0}" + "", e + .getMessage().replace("&", "&").replace("<", "<").replace(">", ">")); + return msg; + } + + /** + * Explains an exception with a generic message dialog + * + * @param e the exception + */ + public static String explainGeneric(Exception e) { + String msg = e.getMessage(); + if (msg == null || msg.trim().equals("")) { + msg = e.toString(); + } + e.printStackTrace(); + return msg; + } + + /** + * 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 String explainSecurityException(OsmTransferException e) { + String apiUrl = OsmApi.getOsmApi().getBaseUrl(); + String host = tr("unknown"); + try { + host = new URL(apiUrl).getHost(); + } catch (MalformedURLException ex) { + // shouldn't happen + } + + String message = tr("Failed to open a connection to the remote server
" + "''{0}''
" + + "for security reasons. This is most likely because you are running
" + + "in an applet and because you didn''t load your applet from ''{1}''.", apiUrl, host); + return message; + } + + /** + * 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 String explainNestedSocketException(OsmTransferException e) { + String apiUrl = OsmApi.getOsmApi().getBaseUrl(); + String message = tr("Failed to open a connection to the remote server
" + "''{0}''.
" + + "Please check your internet connection.", apiUrl); + e.printStackTrace(); + return message; + } + + /** + * 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 String explainNestedIOException(OsmTransferException e) { + IOException ioe = getNestedException(e, IOException.class); + String apiUrl = OsmApi.getOsmApi().getBaseUrl(); + String message = tr("Failed to upload data to or download data from
" + "''{0}''
" + + "due to a problem with transferring data.
" + "Details(untranslated): {1}", apiUrl, ioe + .getMessage()); + e.printStackTrace(); + return message; + } + + /** + * Explains a {@see OsmApiException} which was thrown because of an internal server + * error in the OSM API server.. + * + * @param e the exception + */ + + public static String explainInternalServerError(OsmTransferException e) { + String apiUrl = OsmApi.getOsmApi().getBaseUrl(); + String message = tr("The OSM server
" + "''{0}''
" + "reported an internal server error.
" + + "This is most likely a temporary problem. Please try again later.", apiUrl); + e.printStackTrace(); + return message; + } + + /** + * Explains a {@see OsmApiException} which was thrown because of a bad + * request + * + * @param e the exception + */ + public static String explainBadRequest(OsmApiException e) { + String apiUrl = OsmApi.getOsmApi().getBaseUrl(); + String message = tr("The OSM server ''{0}'' reported a bad request.
", apiUrl); + if (e.getErrorHeader() != null && e.getErrorHeader().startsWith("The maximum bbox")) { + message += "
" + + tr("The area you tried to download is too big or your request was too large." + + "
Either request a smaller area or use an export file provided by the OSM community."); + } else if (e.getErrorHeader() != null) { + message += tr("
Error message(untranslated): {0}", e.getErrorHeader()); + } + message = "" + message + ""; + e.printStackTrace(); + return message; + } + + /** + * 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 String explainNestedUnkonwnHostException(OsmTransferException e) { + String apiUrl = OsmApi.getOsmApi().getBaseUrl(); + String host = tr("unknown"); + try { + host = new URL(apiUrl).getHost(); + } catch (MalformedURLException ex) { + // shouldn't happen + } + + String message = tr("Failed to open a connection to the remote server
" + "''{0}''.
" + + "Host name ''{1}'' couldn''t be resolved.
" + + "Please check the API URL in your preferences and your internet connection.", apiUrl, host); + e.printStackTrace(); + return message; + } + + /** + * Replies the first nested exception of type nestedClass (including + * the root exception e) or null, if no such exception is found. + * + * @param + * @param e the root exception + * @param nestedClass the type of the nested exception + * @return the first nested exception of type nestedClass (including + * the root exception e) or null, if no such exception is found. + */ + protected static T getNestedException(Exception e, Class 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 String explainOsmTransferException(OsmTransferException e) { + if (getNestedException(e, SecurityException.class) != null) + return explainSecurityException(e); + if (getNestedException(e, SocketException.class) != null) + return explainNestedSocketException(e); + if (getNestedException(e, UnknownHostException.class) != null) + return explainNestedUnkonwnHostException(e); + if (getNestedException(e, IOException.class) != null) + return explainNestedIOException(e); + if (e instanceof OsmApiInitializationException) + return explainOsmApiInitializationException((OsmApiInitializationException) e); + if (e instanceof OsmChangesetCloseException) + return explainOsmChangesetCloseException((OsmChangesetCloseException) e); + + if (e instanceof OsmApiException) { + OsmApiException oae = (OsmApiException) e; + if (oae.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) + return explainPreconditionFailed(oae); + if (oae.getResponseCode() == HttpURLConnection.HTTP_GONE) + return explainGoneForUnknownPrimitive(oae); + if (oae.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) + return explainInternalServerError(oae); + if (oae.getResponseCode() == HttpURLConnection.HTTP_BAD_REQUEST) + return explainBadRequest(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 String explainGoneForUnknownPrimitive(OsmApiException e) { + String msg = tr("Uploading failed because a primitive you tried to
" + + "delete on the server is already deleted.
" + "
" + "The error message is:
" + "{0}" + + "", e.getMessage().replace("&", "&").replace("<", "<").replace(">", ">")); + return msg; + + } + + /** + * Explains an {@see Exception} to the user. + * + * @param e the {@see Exception} + */ + public static String explainException(Exception e) { + if (e instanceof OsmTransferException) + return explainOsmTransferException((OsmTransferException) e); + return explainGeneric(e); + } +}