Changeset 1885 in josm for trunk/src/org


Ignore:
Timestamp:
2009-08-02T20:15:38+02:00 (15 years ago)
Author:
Gubaer
Message:

Improved exception handling

Location:
trunk/src/org/openstreetmap/josm
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/ApiPreconditionChecker.java

    r1862 r1885  
    1515import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1616import org.openstreetmap.josm.data.osm.Way;
     17import org.openstreetmap.josm.gui.ExceptionDialogUtil;
    1718import org.openstreetmap.josm.gui.OptionPaneUtil;
    1819import org.openstreetmap.josm.io.OsmApi;
     
    6162            }
    6263        } catch (OsmApiInitializationException e) {
    63             e.printStackTrace();
    64             OptionPaneUtil.showMessageDialog(
    65                     Main.parent,
    66                     tr("Failed to initialize API. Please try again later."),
    67                     tr("API initialization failed"),
    68                     JOptionPane.ERROR_MESSAGE
    69             );
     64            ExceptionDialogUtil.explainOsmTransferException(e);
    7065            return false;
    7166        }
  • trunk/src/org/openstreetmap/josm/actions/UploadAction.java

    r1876 r1885  
    2323import javax.swing.JOptionPane;
    2424import javax.swing.JPanel;
    25 import javax.swing.JRadioButton;
    2625import javax.swing.JScrollPane;
    2726
     
    2928import org.openstreetmap.josm.data.conflict.ConflictCollection;
    3029import org.openstreetmap.josm.data.osm.OsmPrimitive;
     30import org.openstreetmap.josm.gui.ExceptionDialogUtil;
    3131import org.openstreetmap.josm.gui.ExtendedDialog;
    3232import org.openstreetmap.josm.gui.OptionPaneUtil;
     
    166166                return;
    167167
    168         final OsmServerWriter server = new OsmServerWriter();
    169168        final Collection<OsmPrimitive> all = new LinkedList<OsmPrimitive>();
    170169        all.addAll(add);
     
    172171        all.addAll(delete);
    173172
    174         class UploadDiffTask extends  PleaseWaitRunnable {
    175 
    176             private boolean uploadCancelled = false;
    177             private boolean uploadFailed = false;
    178             private Exception lastException = null;
    179 
    180             public UploadDiffTask() {
    181                 super(tr("Uploading"),false /* don't ignore exceptions */);
    182             }
    183 
    184             @Override protected void realRun() throws SAXException, IOException {
    185                 try {
    186                     server.uploadOsm(getCurrentDataSet().version, all, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    187                     getEditLayer().cleanData(server.processed, !add.isEmpty());
    188                 } catch (Exception sxe) {
    189                     if (uploadCancelled) {
    190                         System.out.println("Ignoring exception caught because upload is cancelled. Exception is: " + sxe.toString());
    191                         return;
    192                     }
    193                     uploadFailed = true;
    194                     lastException = sxe;
    195                 }
    196             }
    197 
    198             @Override protected void finish() {
    199                 if (uploadFailed) {
    200                     handleFailedUpload(lastException);
    201                 }
    202             }
    203 
    204             @Override protected void cancel() {
    205                 server.disconnectActiveConnection();
    206                 uploadCancelled = true;
    207             }
    208         }
    209 
    210         Main.worker.execute(new UploadDiffTask());
     173        Main.worker.execute(new UploadDiffTask(all));
    211174    }
    212175
     
    272235        );
    273236        switch(ret) {
    274             case JOptionPane.CLOSED_OPTION: return;
    275             case JOptionPane.CANCEL_OPTION: return;
    276             case 0: synchronizePrimitive(id); break;
    277             case 1: synchronizeDataSet(); break;
    278             default:
    279                 // should not happen
    280                 throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
     237        case JOptionPane.CLOSED_OPTION: return;
     238        case JOptionPane.CANCEL_OPTION: return;
     239        case 0: synchronizePrimitive(id); break;
     240        case 1: synchronizeDataSet(); break;
     241        default:
     242            // should not happen
     243            throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
    281244        }
    282245    }
     
    311274        );
    312275        switch(ret) {
    313             case JOptionPane.CLOSED_OPTION: return;
    314             case 1: return;
    315             case 0: synchronizeDataSet(); break;
    316             default:
    317                 // should not happen
    318                 throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
     276        case JOptionPane.CLOSED_OPTION: return;
     277        case 1: return;
     278        case 0: synchronizeDataSet(); break;
     279        default:
     280            // should not happen
     281            throw new IllegalStateException(tr("unexpected return value. Got {0}", ret));
    319282        }
    320283    }
     
    338301
    339302    /**
    340      * Handles an upload error due to a violated precondition, i.e. a HTTP return code 412
    341      *
    342      * @param e the exception
    343      */
    344     protected void handlePreconditionFailed(OsmApiException e) {
    345         OptionPaneUtil.showMessageDialog(
    346                 Main.parent,
    347                 tr("<html>Uploading to the server <strong>failed</strong> because your current<br>"
    348                         +"dataset violates a precondition.<br>"
    349                         +"The error message is:<br>"
    350                         + "{0}"
    351                         + "</html>",
    352                         e.getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
    353                 ),
    354                 tr("Precondition violation"),
    355                 JOptionPane.ERROR_MESSAGE
    356         );
    357         e.printStackTrace();
    358     }
    359 
    360 
    361     /**
    362303     * Handles an error due to a delete request on an already deleted
    363304     * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we know what
     
    375316        UpdateSelectionAction act = new UpdateSelectionAction();
    376317        act.handlePrimitiveGoneException(Long.parseLong(id));
    377     }
    378 
    379     /**
    380      * handles the case of an error due to a delete request on an already deleted
    381      * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which
    382      * {@see OsmPrimitive} is causing the error.
    383      *
    384      * @param e the exception
    385      */
    386     protected void handleGoneForUnknownPrimitive(OsmApiException e) {
    387         String msg =  tr("<html>Uploading <strong>failed</strong> because a primitive you tried to<br>"
    388                 + "delete on the server is already deleted.<br>"
    389                 + "<br>"
    390                 + "The error message is:<br>"
    391                 + "{0}"
    392                 + "</html>",
    393                 e.getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
    394         );
    395         OptionPaneUtil.showMessageDialog(
    396                 Main.parent,
    397                 msg,
    398                 tr("Primitive already deleted"),
    399                 JOptionPane.ERROR_MESSAGE
    400         );
    401 
    402318    }
    403319
     
    418334        } else {
    419335            logger.warning(tr("Error header \"{0}\" does not match expected pattern \"{1}\"",e.getErrorHeader(), pattern));
    420             handleGoneForUnknownPrimitive(e);
     336            ExceptionDialogUtil.explainGoneForUnknownPrimitive(e);
    421337        }
    422338    }
     
    432348        //
    433349        if (e instanceof OsmApiInitializationException) {
    434             handleOsmApiInitializationException((OsmApiInitializationException)e);
     350            ExceptionDialogUtil.explainOsmApiInitializationException((OsmApiInitializationException)e);
    435351            return;
    436352        }
     
    448364            //
    449365            else if (ex.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) {
    450                 handlePreconditionFailed(ex);
     366                ExceptionDialogUtil.explainPreconditionFailed(ex);
    451367                return;
    452368            }
     
    478394        }
    479395
    480         // For any other exception just notify the user
    481         //
    482         String msg = e.getMessage();
    483         if (msg == null) {
    484             msg = e.toString();
    485         }
    486         e.printStackTrace();
    487         OptionPaneUtil.showMessageDialog(
    488                 Main.map,
    489                 msg,
    490                 tr("Upload to OSM API failed"),
    491                 JOptionPane.ERROR_MESSAGE
    492         );
    493     }
    494 
    495     /**
    496      * handles an exception caught during OSM API initialization
    497      *
    498      * @param e the exception
    499      */
    500     protected void handleOsmApiInitializationException(OsmApiInitializationException e) {
    501         OptionPaneUtil.showMessageDialog(
    502                 Main.parent,
    503                 tr(   "Failed to initialize communication with the OSM server {0}.\n"
    504                         + "Check the server URL in your preferences and your internet connection.",
    505                         Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api")
    506                 ),
    507                 tr("Error"),
    508                 JOptionPane.ERROR_MESSAGE
    509         );
    510         e.printStackTrace();
     396        ExceptionDialogUtil.explainException(e);
    511397    }
    512398
     
    634520        }
    635521    }
     522
     523
     524    class UploadDiffTask extends  PleaseWaitRunnable {
     525        private boolean uploadCancelled = false;
     526        private Exception lastException = null;
     527        private Collection <OsmPrimitive> toUpload;
     528        private OsmServerWriter writer;
     529
     530        public UploadDiffTask(Collection <OsmPrimitive> toUpload) {
     531            super(tr("Uploading"),false /* don't ignore exceptions */);
     532            this.toUpload = toUpload;
     533        }
     534
     535        @Override protected void realRun() throws SAXException, IOException {
     536            writer = new OsmServerWriter();
     537            try {
     538                writer.uploadOsm(getCurrentDataSet().version, toUpload, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
     539                getEditLayer().cleanData(writer.processed, !toUpload.isEmpty());
     540            } catch (Exception sxe) {
     541                if (uploadCancelled) {
     542                    System.out.println("Ignoring exception caught because upload is cancelled. Exception is: " + sxe.toString());
     543                    return;
     544                }
     545                lastException = sxe;
     546            }
     547        }
     548
     549        @Override protected void finish() {
     550            if (uploadCancelled)
     551                return;
     552            if (lastException != null) {
     553                handleFailedUpload(lastException);
     554            }
     555        }
     556
     557        @Override protected void cancel() {
     558            uploadCancelled = true;
     559            if (writer != null) {
     560                writer.disconnectActiveConnection();
     561            }
     562        }
     563    }
    636564}
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java

    r1879 r1885  
    4141    private Future<Task> task = null;
    4242    private DataSet downloadedData;
     43    private boolean canceled = false;
     44    private boolean failed = false;
    4345
    4446    private class Task extends PleaseWaitRunnable {
     
    4648        private DataSet dataSet;
    4749        private boolean newLayer;
    48         private boolean cancelled;
     50        private boolean canceled;
    4951        private Exception lastException;
    5052
     
    5961                dataSet = reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    6062            } catch(Exception e) {
    61                 if (cancelled) {
     63                if (canceled) {
    6264                    logger.warning(tr("Ignoring exception because download has been cancelled. Exception was: {0}" + e.toString()));
    6365                    return;
     
    102104
    103105        @Override protected void finish() {
    104             if (cancelled)
     106            if (canceled)
    105107                return;
    106108            if (lastException != null) {
    107109                ExceptionDialogUtil.explainException(lastException);
     110                DownloadOsmTask.this.setFailed(true);
    108111                return;
    109112            }
     
    135138
    136139        @Override protected void cancel() {
     140            this.canceled = true;
    137141            if (reader != null) {
    138142                reader.cancel();
    139143            }
     144            DownloadOsmTask.this.setCanceled(true);
    140145        }
    141146    }
     
    144149    private void rememberDownloadedData(DataSet ds) {
    145150        this.downloadedData = ds;
     151    }
     152
     153    public boolean isCanceled() {
     154        return canceled;
     155    }
     156
     157    public void setCanceled(boolean canceled) {
     158        this.canceled = canceled;
     159    }
     160
     161    public boolean isFailed() {
     162        return failed;
     163    }
     164
     165    public void setFailed(boolean failed) {
     166        this.failed = failed;
    146167    }
    147168
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java

    r1873 r1885  
    114114        }
    115115
     116        // FIXME: this is a hack. We assume that the user canceled the whole download if at least
     117        // one task was canceled or if it failed
     118        //
     119        for (DownloadTask task: osmTasks) {
     120            if (task instanceof DownloadOsmTask) {
     121                DownloadOsmTask osmTask = (DownloadOsmTask)task;
     122                if (osmTask.isCanceled() || osmTask.isFailed())
     123                    return;
     124            }
     125        }
    116126        Set<Long> myPrimitiveIds = Main.map.mapView.getEditLayer().data.getCompletePrimitiveIds();
    117127        Set<Long> downloadedIds = getDownloadedIds();
     
    233243            if(task instanceof DownloadOsmTask) {
    234244                DataSet ds = ((DownloadOsmTask)task).getDownloadedData();
    235                 ret.addAll(ds.getPrimitiveIds());
     245                if (ds != null) {
     246                    ret.addAll(ds.getPrimitiveIds());
     247                }
    236248            }
    237249        }
  • trunk/src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java

    r1879 r1885  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
     6import java.net.HttpURLConnection;
    67import java.net.MalformedURLException;
     8import java.net.SocketException;
    79import java.net.URL;
     10import java.net.UnknownHostException;
    811
    912import javax.swing.JOptionPane;
     
    1114import org.openstreetmap.josm.Main;
    1215import org.openstreetmap.josm.io.OsmApi;
     16import org.openstreetmap.josm.io.OsmApiException;
     17import org.openstreetmap.josm.io.OsmApiInitializationException;
    1318import org.openstreetmap.josm.io.OsmTransferException;
    1419
     
    2328     */
    2429    private ExceptionDialogUtil() {}
     30
     31    /**
     32     * handles an exception caught during OSM API initialization
     33     *
     34     * @param e the exception
     35     */
     36    public static void explainOsmApiInitializationException(OsmApiInitializationException e) {
     37        e.printStackTrace();
     38        OptionPaneUtil.showMessageDialog(
     39                Main.parent,
     40                tr(   "Failed to initialize communication with the OSM server {0}.\n"
     41                        + "Check the server URL in your preferences and your internet connection.",
     42                        Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api")
     43                ),
     44                tr("Error"),
     45                JOptionPane.ERROR_MESSAGE
     46        );
     47    }
     48
     49
     50    /**
     51     * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412
     52     *
     53     * @param e the exception
     54     */
     55    public static void explainPreconditionFailed(OsmApiException e) {
     56        e.printStackTrace();
     57        OptionPaneUtil.showMessageDialog(
     58                Main.parent,
     59                tr("<html>Uploading to the server <strong>failed</strong> because your current<br>"
     60                        +"dataset violates a precondition.<br>"
     61                        +"The error message is:<br>"
     62                        + "{0}"
     63                        + "</html>",
     64                        e.getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
     65                ),
     66                tr("Precondition violation"),
     67                JOptionPane.ERROR_MESSAGE
     68        );
     69    }
    2570
    2671
     
    73118                JOptionPane.ERROR_MESSAGE
    74119        );
    75 
     120    }
     121
     122    /**
     123     * Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
     124     * This is most likely happening when user tries to access the OSM API from whitin an
     125     * applet which wasn't loaded from the API server.
     126     *
     127     * @param e the exception
     128     */
     129
     130    public static void explainNestedSocketException(OsmTransferException e) {
     131        String apiUrl = OsmApi.getOsmApi().getBaseUrl();
     132        String message = tr("<html>Failed to open a connection to the remote server<br>"
     133                + "''{0}''.<br>"
     134                + "Please check your internet connection.</html>",
     135                apiUrl
     136        );
     137        e.printStackTrace();
     138        OptionPaneUtil.showMessageDialog(
     139                Main.parent,
     140                message,
     141                tr("Network exception"),
     142                JOptionPane.ERROR_MESSAGE
     143        );
     144    }
     145
     146    /**
     147     * Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
     148     * This is most likely happening when user tries to access the OSM API from whitin an
     149     * applet which wasn't loaded from the API server.
     150     *
     151     * @param e the exception
     152     */
     153
     154    public static void explainNestedUnkonwnHostException(OsmTransferException e) {
     155        String apiUrl = OsmApi.getOsmApi().getBaseUrl();
     156        String host = tr("unknown");
     157        try {
     158            host = new URL(apiUrl).getHost();
     159        } catch(MalformedURLException ex) {
     160            // shouldn't happen
     161        }
     162
     163        String message = tr("<html>Failed to open a connection to the remote server<br>"
     164                + "''{0}''.<br>"
     165                + "Host name ''{1}'' couldn''t be resolved. <br>"
     166                + "Please check the API URL in your preferences and your internet connection.</html>",
     167                apiUrl, host
     168        );
     169        e.printStackTrace();
     170        OptionPaneUtil.showMessageDialog(
     171                Main.parent,
     172                message,
     173                tr("Unknown host"),
     174                JOptionPane.ERROR_MESSAGE
     175        );
     176    }
     177
     178    protected static <T> T getNestedException(Exception e, Class<T> nested) {
     179        Throwable t = e;
     180        while (t != null && !(t.getClass().isAssignableFrom(nested))) {
     181            t = t.getCause();
     182        }
     183        return nested.cast(t);
    76184    }
    77185
     
    83191     * @return the first {@see SecurityException} in a chain of nested exceptions
    84192     */
    85     protected static SecurityException getSecurityChildException(Exception e) {
    86         Throwable t = e;
    87         while(t != null && ! (t instanceof SecurityException)) {
    88             t = t.getCause();
    89         }
    90         return (SecurityException)t;
    91     }
     193    protected static SecurityException getNestedSecurityException(Exception e) {
     194        return getNestedException(e, SecurityException.class);
     195    }
     196
     197
     198    /**
     199     * Replies the first {@see SocketException} in a chain of nested exceptions.
     200     * null, if no {@see SocketException} is in this chain.
     201     *
     202     * @param e the root exception
     203     * @return the first {@see SocketException} in a chain of nested exceptions
     204     */
     205    protected static SocketException getNestedSocketException(Exception e) {
     206        return getNestedException(e, SocketException.class);
     207    }
     208
     209    /**
     210     * Replies the first {@see UnknownHostException} in a chain of nested exceptions.
     211     * null, if no {@see UnknownHostException} is in this chain.
     212     *
     213     * @param e the root exception
     214     * @return the first {@see UnknownHostException} in a chain of nested exceptions
     215     */
     216    protected static UnknownHostException getNestedUnknownHostException(Exception e) {
     217        return getNestedException(e, UnknownHostException.class);
     218    }
     219
    92220
    93221    /**
     
    97225     */
    98226    public static void explainOsmTransferException(OsmTransferException e) {
    99         if (getSecurityChildException(e) != null) {
     227        if (getNestedSecurityException(e) != null) {
    100228            explainSecurityException(e);
    101229            return;
    102230        }
     231        if (getNestedSocketException(e) != null) {
     232            explainNestedSocketException(e);
     233            return;
     234        }
     235        if (getNestedUnknownHostException(e) != null) {
     236            explainNestedUnkonwnHostException(e);
     237            return;
     238        }
     239        if (e instanceof OsmApiInitializationException){
     240            explainOsmApiInitializationException((OsmApiInitializationException)e);
     241            return;
     242        }
     243        if (e instanceof OsmApiException) {
     244            OsmApiException oae = (OsmApiException)e;
     245            if (oae.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) {
     246                explainPreconditionFailed(oae);
     247                return;
     248            }
     249            if (oae.getResponseCode() == HttpURLConnection.HTTP_GONE) {
     250                explainGoneForUnknownPrimitive(oae);
     251                return;
     252            }
     253        }
     254
    103255        explainGeneric(e);
     256    }
     257
     258    /**
     259     * explains the case of an error due to a delete request on an already deleted
     260     * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which
     261     * {@see OsmPrimitive} is causing the error.
     262     *
     263     * @param e the exception
     264     */
     265    public static void explainGoneForUnknownPrimitive(OsmApiException e) {
     266        String msg =  tr("<html>Uploading <strong>failed</strong> because a primitive you tried to<br>"
     267                + "delete on the server is already deleted.<br>"
     268                + "<br>"
     269                + "The error message is:<br>"
     270                + "{0}"
     271                + "</html>",
     272                e.getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
     273        );
     274        OptionPaneUtil.showMessageDialog(
     275                Main.parent,
     276                msg,
     277                tr("Primitive already deleted"),
     278                JOptionPane.ERROR_MESSAGE
     279        );
     280
    104281    }
    105282
Note: See TracChangeset for help on using the changeset viewer.