source: josm/trunk/src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java @ 5241

Revision 4540, 16.7 KB checked in by Don-vip, 7 months ago (diff)

see #6821 - Proper error dialog with HTTP 509 error code

  • Property svn:eol-style set to native
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.io.IOException;
8import java.lang.reflect.InvocationTargetException;
9import java.net.HttpURLConnection;
10import java.net.SocketException;
11import java.net.UnknownHostException;
12
13import javax.swing.JOptionPane;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.io.ChangesetClosedException;
17import org.openstreetmap.josm.io.IllegalDataException;
18import org.openstreetmap.josm.io.MissingOAuthAccessTokenException;
19import org.openstreetmap.josm.io.OsmApiException;
20import org.openstreetmap.josm.io.OsmApiInitializationException;
21import org.openstreetmap.josm.io.OsmTransferException;
22import org.openstreetmap.josm.tools.BugReportExceptionHandler;
23import org.openstreetmap.josm.tools.ExceptionUtil;
24
25/**
26 * This utility class provides static methods which explain various exceptions to the user.
27 *
28 */
29public class ExceptionDialogUtil {
30
31    /**
32     * just static utility functions. no constructor
33     */
34    private ExceptionDialogUtil() {
35    }
36
37    /**
38     * handles an exception caught during OSM API initialization
39     *
40     * @param e the exception
41     */
42    public static void explainOsmApiInitializationException(OsmApiInitializationException e) {
43        HelpAwareOptionPane.showOptionDialog(
44                Main.parent,
45                ExceptionUtil.explainOsmApiInitializationException(e),
46                tr("Error"),
47                JOptionPane.ERROR_MESSAGE,
48                ht("/ErrorMessages#OsmApiInitializationException")
49        );
50    }
51
52    /**
53     * handles a ChangesetClosedException
54     *
55     * @param e the exception
56     */
57    public static void explainChangesetClosedException(ChangesetClosedException e) {
58        HelpAwareOptionPane.showOptionDialog(
59                Main.parent,
60                ExceptionUtil.explainChangesetClosedException(e),
61                tr("Error"),
62                JOptionPane.ERROR_MESSAGE,
63                ht("/Action/Upload#ChangesetClosed")
64        );
65    }
66
67    /**
68     * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412
69     *
70     * @param e the exception
71     */
72    public static void explainPreconditionFailed(OsmApiException e) {
73        HelpAwareOptionPane.showOptionDialog(
74                Main.parent,
75                ExceptionUtil.explainPreconditionFailed(e),
76                tr("Precondition violation"),
77                JOptionPane.ERROR_MESSAGE,
78                ht("/ErrorMessages#OsmApiException")
79        );
80    }
81
82    /**
83     * Explains an exception with a generic message dialog
84     *
85     * @param e the exception
86     */
87    public static void explainGeneric(Exception e) {
88        e.printStackTrace();
89        BugReportExceptionHandler.handleException(e);
90    }
91
92    /**
93     * Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
94     * This is most likely happening when user tries to access the OSM API from within an
95     * applet which wasn't loaded from the API server.
96     *
97     * @param e the exception
98     */
99
100    public static void explainSecurityException(OsmTransferException e) {
101        HelpAwareOptionPane.showOptionDialog(
102                Main.parent,
103                ExceptionUtil.explainSecurityException(e),
104                tr("Security exception"),
105                JOptionPane.ERROR_MESSAGE,
106                ht("/ErrorMessages#SecurityException")
107        );
108    }
109
110    /**
111     * Explains a {@see SocketException} which has caused an {@see OsmTransferException}.
112     * This is most likely because there's not connection to the Internet or because
113     * the remote server is not reachable.
114     *
115     * @param e the exception
116     */
117
118    public static void explainNestedSocketException(OsmTransferException e) {
119        HelpAwareOptionPane.showOptionDialog(
120                Main.parent,
121                ExceptionUtil.explainNestedSocketException(e),
122                tr("Network exception"),
123                JOptionPane.ERROR_MESSAGE,
124                ht("/ErrorMessages#NestedSocketException")
125        );
126    }
127
128    /**
129     * Explains a {@see IOException} which has caused an {@see OsmTransferException}.
130     * This is most likely happening when the communication with the remote server is
131     * interrupted for any reason.
132     *
133     * @param e the exception
134     */
135
136    public static void explainNestedIOException(OsmTransferException e) {
137        HelpAwareOptionPane.showOptionDialog(
138                Main.parent,
139                ExceptionUtil.explainNestedIOException(e),
140                tr("IO Exception"),
141                JOptionPane.ERROR_MESSAGE,
142                ht("/ErrorMessages#NestedIOException")
143        );
144    }
145
146    /**
147     * Explains a {@see IllegalDataException} which has caused an {@see OsmTransferException}.
148     * This is most likely happening when JOSM tries to load data in in an unsupported format.
149     *
150     * @param e the exception
151     */
152
153    public static void explainNestedIllegalDataException(OsmTransferException e) {
154        HelpAwareOptionPane.showOptionDialog(
155                Main.parent,
156                ExceptionUtil.explainNestedIllegalDataException(e),
157                tr("Illegal Data"),
158                JOptionPane.ERROR_MESSAGE,
159                ht("/ErrorMessages#IllegalDataException")
160        );
161    }
162
163    /**
164     * Explains a {@see InvocationTargetException }
165     *
166     * @param e the exception
167     */
168
169    public static void explainNestedInvocationTargetException(Exception e) {
170        InvocationTargetException ex = getNestedException(e, InvocationTargetException.class);
171        if (ex != null) {
172            // Users should be able to submit a bug report for an invocation target exception
173            //
174            BugReportExceptionHandler.handleException(ex);
175            return;
176        }
177    }
178
179    /**
180     * Explains a {@see OsmApiException} which was thrown because of an internal server
181     * error in the OSM API server.
182     *
183     * @param e the exception
184     */
185
186    public static void explainInternalServerError(OsmTransferException e) {
187        HelpAwareOptionPane.showOptionDialog(
188                Main.parent,
189                ExceptionUtil.explainInternalServerError(e),
190                tr("Internal Server Error"),
191                JOptionPane.ERROR_MESSAGE,
192                ht("/ErrorMessages#InternalServerError")
193        );
194    }
195
196    /**
197     * Explains a {@see OsmApiException} which was thrown because of a bad
198     * request
199     *
200     * @param e the exception
201     */
202    public static void explainBadRequest(OsmApiException e) {
203        HelpAwareOptionPane.showOptionDialog(
204                Main.parent,
205                ExceptionUtil.explainBadRequest(e),
206                tr("Bad Request"),
207                JOptionPane.ERROR_MESSAGE,
208                ht("/ErrorMessages#BadRequest")
209        );
210    }
211
212    /**
213     * Explains a {@see OsmApiException} which was thrown because a resource wasn't found
214     * on the server
215     *
216     * @param e the exception
217     */
218    public static void explainNotFound(OsmApiException e) {
219        HelpAwareOptionPane.showOptionDialog(
220                Main.parent,
221                ExceptionUtil.explainNotFound(e),
222                tr("Not Found"),
223                JOptionPane.ERROR_MESSAGE,
224                ht("/ErrorMessages#NotFound")
225        );
226    }
227
228    /**
229     * Explains a {@see OsmApiException} which was thrown because of a conflict
230     *
231     * @param e the exception
232     */
233    public static void explainConflict(OsmApiException e) {
234        HelpAwareOptionPane.showOptionDialog(
235                Main.parent,
236                ExceptionUtil.explainConflict(e),
237                tr("Conflict"),
238                JOptionPane.ERROR_MESSAGE,
239                ht("/ErrorMessages#Conflict")
240        );
241    }
242
243    /**
244     * Explains a {@see OsmApiException} which was thrown because the authentication at
245     * the OSM server failed
246     *
247     * @param e the exception
248     */
249    public static void explainAuthenticationFailed(OsmApiException e) {
250        String authMethod = Main.pref.get("osm-server.auth-method", "basic");
251        String msg;
252        if (authMethod.equals("oauth")) {
253            msg = ExceptionUtil.explainFailedOAuthAuthentication(e);
254        } else {
255            msg = ExceptionUtil.explainFailedBasicAuthentication(e);
256        }
257
258        HelpAwareOptionPane.showOptionDialog(
259                Main.parent,
260                msg,
261                tr("Authentication Failed"),
262                JOptionPane.ERROR_MESSAGE,
263                ht("/ErrorMessages#AuthenticationFailed")
264        );
265    }
266
267    /**
268     * Explains a {@see OsmApiException} which was thrown because accessing a protected
269     * resource was forbidden.
270     *
271     * @param e the exception
272     */
273    public static void explainAuthorizationFailed(OsmApiException e) {
274        // Fixme: add special handling that calls ExceptionUtil.explainFailedOAuthAuthorisation(e)
275        HelpAwareOptionPane.showOptionDialog(
276                Main.parent,
277                ExceptionUtil.explainFailedAuthorisation(e),
278                tr("Authorisation Failed"),
279                JOptionPane.ERROR_MESSAGE,
280                ht("/ErrorMessages#AuthenticationFailed")
281        );
282    }
283
284    /**
285     * Explains a {@see OsmApiException} which was thrown because of a
286     * client timeout (HTTP 408)
287     *
288     * @param e the exception
289     */
290    public static void explainClientTimeout(OsmApiException e) {
291        HelpAwareOptionPane.showOptionDialog(
292                Main.parent,
293                ExceptionUtil.explainClientTimeout(e),
294                tr("Client Time Out"),
295                JOptionPane.ERROR_MESSAGE,
296                ht("/ErrorMessages#ClientTimeOut")
297        );
298    }
299
300    /**
301     * Explains a {@see OsmApiException} which was thrown because of a
302     * bandwidth limit (HTTP 509)
303     *
304     * @param e the exception
305     */
306    public static void explainBandwidthLimitExceeded(OsmApiException e) {
307        HelpAwareOptionPane.showOptionDialog(
308                Main.parent,
309                ExceptionUtil.explainBandwidthLimitExceeded(e),
310                tr("Bandwidth Limit Exceeded"),
311                JOptionPane.ERROR_MESSAGE,
312                ht("/ErrorMessages#BandwidthLimit")
313        );
314    }
315
316    /**
317     * Explains a {@see OsmApiException} with a generic error
318     * message.
319     *
320     * @param e the exception
321     */
322    public static void explainGenericHttpException(OsmApiException e) {
323        HelpAwareOptionPane.showOptionDialog(
324                Main.parent,
325                ExceptionUtil.explainClientTimeout(e),
326                tr("Communication with OSM server failed"),
327                JOptionPane.ERROR_MESSAGE,
328                ht("/ErrorMessages#GenericCommunicationError")
329        );
330    }
331
332    /**
333     * Explains a {@see OsmApiException} which was thrown because accessing a protected
334     * resource was forbidden.
335     *
336     * @param e the exception
337     */
338    public static void explainMissingOAuthAccessTokenException(MissingOAuthAccessTokenException e) {
339        HelpAwareOptionPane.showOptionDialog(
340                Main.parent,
341                ExceptionUtil.explainMissingOAuthAccessTokenException(e),
342                tr("Authentication failed"),
343                JOptionPane.ERROR_MESSAGE,
344                ht("/ErrorMessages#MissingOAuthAccessToken")
345        );
346    }
347
348    /**
349     * Explains a {@see UnknownHostException} which has caused an {@see OsmTransferException}.
350     * This is most likely happening when there is an error in the API URL or when
351     * local DNS services are not working.
352     *
353     * @param e the exception
354     */
355
356    public static void explainNestedUnkonwnHostException(OsmTransferException e) {
357        HelpAwareOptionPane.showOptionDialog(
358                Main.parent,
359                ExceptionUtil.explainNestedUnknownHostException(e),
360                tr("Unknown host"),
361                JOptionPane.ERROR_MESSAGE,
362                ht("/ErrorMessages#UnknownHost")
363        );
364    }
365
366    /**
367     * Replies the first nested exception of type <code>nestedClass</code> (including
368     * the root exception <code>e</code>) or null, if no such exception is found.
369     *
370     * @param <T>
371     * @param e the root exception
372     * @param nestedClass the type of the nested exception
373     * @return the first nested exception of type <code>nestedClass</code> (including
374     * the root exception <code>e</code>) or null, if no such exception is found.
375     */
376    protected static <T> T getNestedException(Exception e, Class<T> nestedClass) {
377        Throwable t = e;
378        while (t != null && !(nestedClass.isInstance(t))) {
379            t = t.getCause();
380        }
381        if (t == null)
382            return null;
383        else if (nestedClass.isInstance(t))
384            return nestedClass.cast(t);
385        return null;
386    }
387
388    /**
389     * Explains an {@see OsmTransferException} to the user.
390     *
391     * @param e the {@see OsmTransferException}
392     */
393    public static void explainOsmTransferException(OsmTransferException e) {
394        if (getNestedException(e, SecurityException.class) != null) {
395            explainSecurityException(e);
396            return;
397        }
398        if (getNestedException(e, SocketException.class) != null) {
399            explainNestedSocketException(e);
400            return;
401        }
402        if (getNestedException(e, UnknownHostException.class) != null) {
403            explainNestedUnkonwnHostException(e);
404            return;
405        }
406        if (getNestedException(e, IOException.class) != null) {
407            explainNestedIOException(e);
408            return;
409        }
410        if (getNestedException(e, IllegalDataException.class) != null) {
411            explainNestedIllegalDataException(e);
412            return;
413        }
414        if (e instanceof OsmApiInitializationException) {
415            explainOsmApiInitializationException((OsmApiInitializationException) e);
416            return;
417        }
418
419        if (e instanceof ChangesetClosedException) {
420            explainChangesetClosedException((ChangesetClosedException)e);
421            return;
422        }
423
424        if (e instanceof MissingOAuthAccessTokenException) {
425            explainMissingOAuthAccessTokenException((MissingOAuthAccessTokenException)e);
426            return;
427        }
428
429        if (e instanceof OsmApiException) {
430            OsmApiException oae = (OsmApiException) e;
431            switch(oae.getResponseCode()) {
432            case HttpURLConnection.HTTP_PRECON_FAILED:
433                explainPreconditionFailed(oae);
434                return;
435            case HttpURLConnection.HTTP_GONE:
436                explainGoneForUnknownPrimitive(oae);
437                return;
438            case HttpURLConnection.HTTP_INTERNAL_ERROR:
439                explainInternalServerError(oae);
440                return;
441            case HttpURLConnection.HTTP_BAD_REQUEST:
442                explainBadRequest(oae);
443                return;
444            case HttpURLConnection.HTTP_NOT_FOUND:
445                explainNotFound(oae);
446                return;
447            case HttpURLConnection.HTTP_CONFLICT:
448                explainConflict(oae);
449                return;
450            case HttpURLConnection.HTTP_UNAUTHORIZED:
451                explainAuthenticationFailed(oae);
452                return;
453            case HttpURLConnection.HTTP_FORBIDDEN:
454                explainAuthorizationFailed(oae);
455                return;
456            case HttpURLConnection.HTTP_CLIENT_TIMEOUT:
457                explainClientTimeout(oae);
458                return;
459            case 509:
460                explainBandwidthLimitExceeded(oae);
461                return;
462            default:
463                explainGenericHttpException(oae);
464                return;
465            }
466        }
467        explainGeneric(e);
468    }
469
470    /**
471     * explains the case of an error due to a delete request on an already deleted
472     * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which
473     * {@see OsmPrimitive} is causing the error.
474     *
475     * @param e the exception
476     */
477    public static void explainGoneForUnknownPrimitive(OsmApiException e) {
478        HelpAwareOptionPane.showOptionDialog(
479                Main.parent,
480                ExceptionUtil.explainGoneForUnknownPrimitive(e),
481                tr("Object deleted"),
482                JOptionPane.ERROR_MESSAGE,
483                ht("/ErrorMessages#GoneForUnknownPrimitive")
484        );
485    }
486
487    /**
488     * Explains an {@see Exception} to the user.
489     *
490     * @param e the {@see Exception}
491     */
492    public static void explainException(Exception e) {
493        if (getNestedException(e, InvocationTargetException.class) != null) {
494            explainNestedInvocationTargetException(e);
495            return;
496        }
497        if (e instanceof OsmTransferException) {
498            explainOsmTransferException((OsmTransferException) e);
499            return;
500        }
501        explainGeneric(e);
502    }
503}
Note: See TracBrowser for help on using the repository browser.