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

Last change on this file since 17318 was 16217, checked in by GerdP, 4 years ago

see #18982: Improve log message, show content of panel instead of meaningless output of HtmlPanel.toString()

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