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

Last change on this file since 6070 was 6070, checked in by stoecker, 11 years ago

see #8853 remove tabs, trailing spaces, windows line ends, strange characters

  • Property svn:eol-style set to native
File size: 17.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.Main;
18import org.openstreetmap.josm.data.osm.OsmPrimitive;
19import org.openstreetmap.josm.io.ChangesetClosedException;
20import org.openstreetmap.josm.io.IllegalDataException;
21import org.openstreetmap.josm.io.MissingOAuthAccessTokenException;
22import org.openstreetmap.josm.io.OsmApiException;
23import org.openstreetmap.josm.io.OsmApiInitializationException;
24import org.openstreetmap.josm.io.OsmTransferException;
25import org.openstreetmap.josm.tools.BugReportExceptionHandler;
26import org.openstreetmap.josm.tools.ExceptionUtil;
27
28/**
29 * This utility class provides static methods which explain various exceptions to the user.
30 *
31 */
32public class ExceptionDialogUtil {
33
34 /**
35 * just static utility functions. no constructor
36 */
37 private ExceptionDialogUtil() {
38 }
39
40 /**
41 * handles an exception caught during OSM API initialization
42 *
43 * @param e the exception
44 */
45 public static void explainOsmApiInitializationException(OsmApiInitializationException e) {
46 HelpAwareOptionPane.showOptionDialog(
47 Main.parent,
48 ExceptionUtil.explainOsmApiInitializationException(e),
49 tr("Error"),
50 JOptionPane.ERROR_MESSAGE,
51 ht("/ErrorMessages#OsmApiInitializationException")
52 );
53 }
54
55 /**
56 * handles a ChangesetClosedException
57 *
58 * @param e the exception
59 */
60 public static void explainChangesetClosedException(ChangesetClosedException e) {
61 HelpAwareOptionPane.showOptionDialog(
62 Main.parent,
63 ExceptionUtil.explainChangesetClosedException(e),
64 tr("Error"),
65 JOptionPane.ERROR_MESSAGE,
66 ht("/Action/Upload#ChangesetClosed")
67 );
68 }
69
70 /**
71 * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412
72 *
73 * @param e the exception
74 */
75 public static void explainPreconditionFailed(OsmApiException e) {
76 HelpAwareOptionPane.showOptionDialog(
77 Main.parent,
78 ExceptionUtil.explainPreconditionFailed(e),
79 tr("Precondition violation"),
80 JOptionPane.ERROR_MESSAGE,
81 ht("/ErrorMessages#OsmApiException")
82 );
83 }
84
85 /**
86 * Explains an exception with a generic message dialog
87 *
88 * @param e the exception
89 */
90 public static void explainGeneric(Exception e) {
91 e.printStackTrace();
92 BugReportExceptionHandler.handleException(e);
93 }
94
95 /**
96 * Explains a {@link SecurityException} which has caused an {@link OsmTransferException}.
97 * This is most likely happening when user tries to access the OSM API from within an
98 * applet which wasn't loaded from the API server.
99 *
100 * @param e the exception
101 */
102
103 public static void explainSecurityException(OsmTransferException e) {
104 HelpAwareOptionPane.showOptionDialog(
105 Main.parent,
106 ExceptionUtil.explainSecurityException(e),
107 tr("Security exception"),
108 JOptionPane.ERROR_MESSAGE,
109 ht("/ErrorMessages#SecurityException")
110 );
111 }
112
113 /**
114 * Explains a {@link SocketException} which has caused an {@link OsmTransferException}.
115 * This is most likely because there's not connection to the Internet or because
116 * the remote server is not reachable.
117 *
118 * @param e the exception
119 */
120
121 public static void explainNestedSocketException(OsmTransferException e) {
122 HelpAwareOptionPane.showOptionDialog(
123 Main.parent,
124 ExceptionUtil.explainNestedSocketException(e),
125 tr("Network exception"),
126 JOptionPane.ERROR_MESSAGE,
127 ht("/ErrorMessages#NestedSocketException")
128 );
129 }
130
131 /**
132 * Explains a {@link IOException} which has caused an {@link OsmTransferException}.
133 * This is most likely happening when the communication with the remote server is
134 * interrupted for any reason.
135 *
136 * @param e the exception
137 */
138
139 public static void explainNestedIOException(OsmTransferException e) {
140 HelpAwareOptionPane.showOptionDialog(
141 Main.parent,
142 ExceptionUtil.explainNestedIOException(e),
143 tr("IO Exception"),
144 JOptionPane.ERROR_MESSAGE,
145 ht("/ErrorMessages#NestedIOException")
146 );
147 }
148
149 /**
150 * Explains a {@link IllegalDataException} which has caused an {@link OsmTransferException}.
151 * This is most likely happening when JOSM tries to load data in in an unsupported format.
152 *
153 * @param e the exception
154 */
155
156 public static void explainNestedIllegalDataException(OsmTransferException e) {
157 HelpAwareOptionPane.showOptionDialog(
158 Main.parent,
159 ExceptionUtil.explainNestedIllegalDataException(e),
160 tr("Illegal Data"),
161 JOptionPane.ERROR_MESSAGE,
162 ht("/ErrorMessages#IllegalDataException")
163 );
164 }
165
166 /**
167 * Explains a {@link InvocationTargetException }
168 *
169 * @param e the exception
170 */
171
172 public static void explainNestedInvocationTargetException(Exception e) {
173 InvocationTargetException ex = getNestedException(e, InvocationTargetException.class);
174 if (ex != null) {
175 // Users should be able to submit a bug report for an invocation target exception
176 //
177 BugReportExceptionHandler.handleException(ex);
178 return;
179 }
180 }
181
182 /**
183 * Explains a {@link OsmApiException} which was thrown because of an internal server
184 * error in the OSM API server.
185 *
186 * @param e the exception
187 */
188
189 public static void explainInternalServerError(OsmTransferException e) {
190 HelpAwareOptionPane.showOptionDialog(
191 Main.parent,
192 ExceptionUtil.explainInternalServerError(e),
193 tr("Internal Server Error"),
194 JOptionPane.ERROR_MESSAGE,
195 ht("/ErrorMessages#InternalServerError")
196 );
197 }
198
199 /**
200 * Explains a {@link OsmApiException} which was thrown because of a bad
201 * request
202 *
203 * @param e the exception
204 */
205 public static void explainBadRequest(OsmApiException e) {
206 HelpAwareOptionPane.showOptionDialog(
207 Main.parent,
208 ExceptionUtil.explainBadRequest(e),
209 tr("Bad Request"),
210 JOptionPane.ERROR_MESSAGE,
211 ht("/ErrorMessages#BadRequest")
212 );
213 }
214
215 /**
216 * Explains a {@link OsmApiException} which was thrown because a resource wasn't found
217 * on the server
218 *
219 * @param e the exception
220 */
221 public static void explainNotFound(OsmApiException e) {
222 HelpAwareOptionPane.showOptionDialog(
223 Main.parent,
224 ExceptionUtil.explainNotFound(e),
225 tr("Not Found"),
226 JOptionPane.ERROR_MESSAGE,
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 HelpAwareOptionPane.showOptionDialog(
238 Main.parent,
239 ExceptionUtil.explainConflict(e),
240 tr("Conflict"),
241 JOptionPane.ERROR_MESSAGE,
242 ht("/ErrorMessages#Conflict")
243 );
244 }
245
246 private static boolean isOAuth() {
247 return Main.pref.get("osm-server.auth-method", "basic").equals("oauth");
248 }
249
250 /**
251 * Explains a {@link OsmApiException} which was thrown because the authentication at
252 * the OSM server failed
253 *
254 * @param e the exception
255 */
256 public static void explainAuthenticationFailed(OsmApiException e) {
257 String msg;
258 if (isOAuth()) {
259 msg = ExceptionUtil.explainFailedOAuthAuthentication(e);
260 } else {
261 msg = ExceptionUtil.explainFailedBasicAuthentication(e);
262 }
263
264 HelpAwareOptionPane.showOptionDialog(
265 Main.parent,
266 msg,
267 tr("Authentication Failed"),
268 JOptionPane.ERROR_MESSAGE,
269 ht("/ErrorMessages#AuthenticationFailed")
270 );
271 }
272
273 /**
274 * Explains a {@link OsmApiException} which was thrown because accessing a protected
275 * resource was forbidden (HTTP 403).
276 *
277 * @param e the exception
278 */
279 public static void explainAuthorizationFailed(OsmApiException e) {
280
281 Matcher m;
282 String msg;
283 String url = e.getAccessedUrl();
284 Pattern p = Pattern.compile("http://.*/api/0.6/(node|way|relation)/(\\d+)/(\\d+)");
285
286 // Special case for individual access to redacted versions
287 // See http://wiki.openstreetmap.org/wiki/Open_Database_License/Changes_in_the_API
288 if (url != null && (m = p.matcher(url)).matches()) {
289 String type = m.group(1);
290 String id = m.group(2);
291 String version = m.group(3);
292 // {1} is the translation of "node", "way" or "relation"
293 msg = tr("Access to redacted version ''{0}'' of {1} {2} is forbidden.",
294 version, tr(type), id);
295 } else if (isOAuth()) {
296 msg = ExceptionUtil.explainFailedOAuthAuthorisation(e);
297 } else {
298 msg = ExceptionUtil.explainFailedAuthorisation(e);
299 }
300
301 HelpAwareOptionPane.showOptionDialog(
302 Main.parent,
303 msg,
304 tr("Authorisation Failed"),
305 JOptionPane.ERROR_MESSAGE,
306 ht("/ErrorMessages#AuthorizationFailed")
307 );
308 }
309
310 /**
311 * Explains a {@link OsmApiException} which was thrown because of a
312 * client timeout (HTTP 408)
313 *
314 * @param e the exception
315 */
316 public static void explainClientTimeout(OsmApiException e) {
317 HelpAwareOptionPane.showOptionDialog(
318 Main.parent,
319 ExceptionUtil.explainClientTimeout(e),
320 tr("Client Time Out"),
321 JOptionPane.ERROR_MESSAGE,
322 ht("/ErrorMessages#ClientTimeOut")
323 );
324 }
325
326 /**
327 * Explains a {@link OsmApiException} which was thrown because of a
328 * bandwidth limit (HTTP 509)
329 *
330 * @param e the exception
331 */
332 public static void explainBandwidthLimitExceeded(OsmApiException e) {
333 HelpAwareOptionPane.showOptionDialog(
334 Main.parent,
335 ExceptionUtil.explainBandwidthLimitExceeded(e),
336 tr("Bandwidth Limit Exceeded"),
337 JOptionPane.ERROR_MESSAGE,
338 ht("/ErrorMessages#BandwidthLimit")
339 );
340 }
341
342 /**
343 * Explains a {@link OsmApiException} with a generic error
344 * message.
345 *
346 * @param e the exception
347 */
348 public static void explainGenericHttpException(OsmApiException e) {
349 HelpAwareOptionPane.showOptionDialog(
350 Main.parent,
351 ExceptionUtil.explainClientTimeout(e),
352 tr("Communication with OSM server failed"),
353 JOptionPane.ERROR_MESSAGE,
354 ht("/ErrorMessages#GenericCommunicationError")
355 );
356 }
357
358 /**
359 * Explains a {@link OsmApiException} which was thrown because accessing a protected
360 * resource was forbidden.
361 *
362 * @param e the exception
363 */
364 public static void explainMissingOAuthAccessTokenException(MissingOAuthAccessTokenException e) {
365 HelpAwareOptionPane.showOptionDialog(
366 Main.parent,
367 ExceptionUtil.explainMissingOAuthAccessTokenException(e),
368 tr("Authentication failed"),
369 JOptionPane.ERROR_MESSAGE,
370 ht("/ErrorMessages#MissingOAuthAccessToken")
371 );
372 }
373
374 /**
375 * Explains a {@link UnknownHostException} which has caused an {@link OsmTransferException}.
376 * This is most likely happening when there is an error in the API URL or when
377 * local DNS services are not working.
378 *
379 * @param e the exception
380 */
381
382 public static void explainNestedUnkonwnHostException(OsmTransferException e) {
383 HelpAwareOptionPane.showOptionDialog(
384 Main.parent,
385 ExceptionUtil.explainNestedUnknownHostException(e),
386 tr("Unknown host"),
387 JOptionPane.ERROR_MESSAGE,
388 ht("/ErrorMessages#UnknownHost")
389 );
390 }
391
392 /**
393 * Replies the first nested exception of type <code>nestedClass</code> (including
394 * the root exception <code>e</code>) or null, if no such exception is found.
395 *
396 * @param <T>
397 * @param e the root exception
398 * @param nestedClass the type of the nested exception
399 * @return the first nested exception of type <code>nestedClass</code> (including
400 * the root exception <code>e</code>) or null, if no such exception is found.
401 */
402 protected static <T> T getNestedException(Exception e, Class<T> nestedClass) {
403 Throwable t = e;
404 while (t != null && !(nestedClass.isInstance(t))) {
405 t = t.getCause();
406 }
407 if (t == null)
408 return null;
409 else if (nestedClass.isInstance(t))
410 return nestedClass.cast(t);
411 return null;
412 }
413
414 /**
415 * Explains an {@link OsmTransferException} to the user.
416 *
417 * @param e the {@link OsmTransferException}
418 */
419 public static void explainOsmTransferException(OsmTransferException e) {
420 if (getNestedException(e, SecurityException.class) != null) {
421 explainSecurityException(e);
422 return;
423 }
424 if (getNestedException(e, SocketException.class) != null) {
425 explainNestedSocketException(e);
426 return;
427 }
428 if (getNestedException(e, UnknownHostException.class) != null) {
429 explainNestedUnkonwnHostException(e);
430 return;
431 }
432 if (getNestedException(e, IOException.class) != null) {
433 explainNestedIOException(e);
434 return;
435 }
436 if (getNestedException(e, IllegalDataException.class) != null) {
437 explainNestedIllegalDataException(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:
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 Main.parent,
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 (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.