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

Last change on this file since 4552 was 4540, checked in by Don-vip, 13 years ago

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

  • Property svn:eol-style set to native
File size: 16.7 KB
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.