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

Last change on this file since 14180 was 14153, checked in by Don-vip, 6 years ago

see #15229 - deprecate Main.parent and Main itself

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