source: josm/trunk/src/org/openstreetmap/josm/tools/ExceptionUtil.java@ 6340

Last change on this file since 6340 was 6248, checked in by Don-vip, 11 years ago

Rework console output:

  • new log level "error"
  • Replace nearly all calls to system.out and system.err to Main.(error|warn|info|debug)
  • Remove some unnecessary debug output
  • Some messages are modified (removal of "Info", "Warning", "Error" from the message itself -> notable i18n impact but limited to console error messages not seen by the majority of users, so that's ok)
  • Property svn:eol-style set to native
File size: 30.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.io.IOException;
8import java.net.HttpURLConnection;
9import java.net.MalformedURLException;
10import java.net.SocketException;
11import java.net.URL;
12import java.net.UnknownHostException;
13import java.text.DateFormat;
14import java.text.ParseException;
15import java.text.SimpleDateFormat;
16import java.util.Collection;
17import java.util.Date;
18import java.util.Locale;
19import java.util.TreeSet;
20import java.util.regex.Matcher;
21import java.util.regex.Pattern;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.data.osm.Node;
25import org.openstreetmap.josm.data.osm.OsmPrimitive;
26import org.openstreetmap.josm.data.osm.Relation;
27import org.openstreetmap.josm.data.osm.Way;
28import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder;
29import org.openstreetmap.josm.io.ChangesetClosedException;
30import org.openstreetmap.josm.io.IllegalDataException;
31import org.openstreetmap.josm.io.MissingOAuthAccessTokenException;
32import org.openstreetmap.josm.io.OsmApi;
33import org.openstreetmap.josm.io.OsmApiException;
34import org.openstreetmap.josm.io.OsmApiInitializationException;
35import org.openstreetmap.josm.io.OsmTransferException;
36import org.openstreetmap.josm.io.auth.CredentialsManager;
37
38@SuppressWarnings("CallToThreadDumpStack")
39public class ExceptionUtil {
40 private ExceptionUtil() {
41 }
42
43 /**
44 * handles an exception caught during OSM API initialization
45 *
46 * @param e the exception
47 */
48 public static String explainOsmApiInitializationException(OsmApiInitializationException e) {
49 e.printStackTrace();
50 String msg = tr(
51 "<html>Failed to initialize communication with the OSM server {0}.<br>"
52 + "Check the server URL in your preferences and your internet connection.", Main.pref.get(
53 "osm-server.url", OsmApi.DEFAULT_API_URL));
54 return msg;
55 }
56
57
58 /**
59 * Creates the error message
60 *
61 * @param e the exception
62 */
63 public static String explainMissingOAuthAccessTokenException(MissingOAuthAccessTokenException e) {
64 e.printStackTrace();
65 String msg = tr(
66 "<html>Failed to authenticate at the OSM server ''{0}''.<br>"
67 + "You are using OAuth to authenticate but currently there is no<br>"
68 + "OAuth Access Token configured.<br>"
69 + "Please open the Preferences Dialog and generate or enter an Access Token."
70 + "</html>",
71 Main.pref.get("osm-server.url", OsmApi.DEFAULT_API_URL)
72 );
73 return msg;
74 }
75
76 public static Pair<OsmPrimitive, Collection<OsmPrimitive>> parsePreconditionFailed(String msg) {
77 final String ids = "(\\d+(?:,\\d+)*)";
78 final Collection<OsmPrimitive> refs = new TreeSet<OsmPrimitive>(); // error message can contain several times the same way
79 Matcher m;
80 m = Pattern.compile(".*Node (\\d+) is still used by relations " + ids + ".*").matcher(msg);
81 if (m.matches()) {
82 OsmPrimitive n = new Node(Long.parseLong(m.group(1)));
83 for (String s : m.group(2).split(",")) {
84 refs.add(new Relation(Long.parseLong(s)));
85 }
86 return Pair.create(n, refs);
87 }
88 m = Pattern.compile(".*Node (\\d+) is still used by ways " + ids + ".*").matcher(msg);
89 if (m.matches()) {
90 OsmPrimitive n = new Node(Long.parseLong(m.group(1)));
91 for (String s : m.group(2).split(",")) {
92 refs.add(new Way(Long.parseLong(s)));
93 }
94 return Pair.create(n, refs);
95 }
96 m = Pattern.compile(".*The relation (\\d+) is used in relations? " + ids + ".*").matcher(msg);
97 if (m.matches()) {
98 OsmPrimitive n = new Relation(Long.parseLong(m.group(1)));
99 for (String s : m.group(2).split(",")) {
100 refs.add(new Relation(Long.parseLong(s)));
101 }
102 return Pair.create(n, refs);
103 }
104 m = Pattern.compile(".*Way (\\d+) is still used by relations " + ids + ".*").matcher(msg);
105 if (m.matches()) {
106 OsmPrimitive n = new Way(Long.parseLong(m.group(1)));
107 for (String s : m.group(2).split(",")) {
108 refs.add(new Relation(Long.parseLong(s)));
109 }
110 return Pair.create(n, refs);
111 }
112 m = Pattern.compile(".*Way (\\d+) requires the nodes with id in " + ids + ".*").matcher(msg); // ... ", which either do not exist, or are not visible"
113 if (m.matches()) {
114 OsmPrimitive n = new Way(Long.parseLong(m.group(1)));
115 for (String s : m.group(2).split(",")) {
116 refs.add(new Node(Long.parseLong(s)));
117 }
118 return Pair.create(n, refs);
119 }
120 return null;
121 }
122
123 /**
124 * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412
125 *
126 * @param e the exception
127 */
128 public static String explainPreconditionFailed(OsmApiException e) {
129 e.printStackTrace();
130 Pair<OsmPrimitive, Collection<OsmPrimitive>> conflict = parsePreconditionFailed(e.getErrorHeader());
131 if (conflict != null) {
132 OsmPrimitive firstRefs = conflict.b.iterator().next();
133 String objId = Long.toString(conflict.a.getId());
134 Collection<Long> refIds= Utils.transform(conflict.b, new Utils.Function<OsmPrimitive, Long>() {
135
136 @Override
137 public Long apply(OsmPrimitive x) {
138 return x.getId();
139 }
140 });
141 String refIdsString = refIds.size() == 1 ? refIds.iterator().next().toString() : refIds.toString();
142 if (conflict.a instanceof Node) {
143 if (firstRefs instanceof Node) {
144 return "<html>" + trn(
145 "<strong>Failed</strong> to delete <strong>node {0}</strong>."
146 + " It is still referred to by node {1}.<br>"
147 + "Please load the node, remove the reference to the node, and upload again.",
148 "<strong>Failed</strong> to delete <strong>node {0}</strong>."
149 + " It is still referred to by nodes {1}.<br>"
150 + "Please load the nodes, remove the reference to the node, and upload again.",
151 conflict.b.size(), objId, refIdsString) + "</html>";
152 } else if (firstRefs instanceof Way) {
153 return "<html>" + trn(
154 "<strong>Failed</strong> to delete <strong>node {0}</strong>."
155 + " It is still referred to by way {1}.<br>"
156 + "Please load the way, remove the reference to the node, and upload again.",
157 "<strong>Failed</strong> to delete <strong>node {0}</strong>."
158 + " It is still referred to by ways {1}.<br>"
159 + "Please load the ways, remove the reference to the node, and upload again.",
160 conflict.b.size(), objId, refIdsString) + "</html>";
161 } else if (firstRefs instanceof Relation) {
162 return "<html>" + trn(
163 "<strong>Failed</strong> to delete <strong>node {0}</strong>."
164 + " It is still referred to by relation {1}.<br>"
165 + "Please load the relation, remove the reference to the node, and upload again.",
166 "<strong>Failed</strong> to delete <strong>node {0}</strong>."
167 + " It is still referred to by relations {1}.<br>"
168 + "Please load the relations, remove the reference to the node, and upload again.",
169 conflict.b.size(), objId, refIdsString) + "</html>";
170 } else {
171 throw new IllegalStateException();
172 }
173 } else if (conflict.a instanceof Way) {
174 if (firstRefs instanceof Node) {
175 return "<html>" + trn(
176 "<strong>Failed</strong> to delete <strong>way {0}</strong>."
177 + " It is still referred to by node {1}.<br>"
178 + "Please load the node, remove the reference to the way, and upload again.",
179 "<strong>Failed</strong> to delete <strong>way {0}</strong>."
180 + " It is still referred to by nodes {1}.<br>"
181 + "Please load the nodes, remove the reference to the way, and upload again.",
182 conflict.b.size(), objId, refIdsString) + "</html>";
183 } else if (firstRefs instanceof Way) {
184 return "<html>" + trn(
185 "<strong>Failed</strong> to delete <strong>way {0}</strong>."
186 + " It is still referred to by way {1}.<br>"
187 + "Please load the way, remove the reference to the way, and upload again.",
188 "<strong>Failed</strong> to delete <strong>way {0}</strong>."
189 + " It is still referred to by ways {1}.<br>"
190 + "Please load the ways, remove the reference to the way, and upload again.",
191 conflict.b.size(), objId, refIdsString) + "</html>";
192 } else if (firstRefs instanceof Relation) {
193 return "<html>" + trn(
194 "<strong>Failed</strong> to delete <strong>way {0}</strong>."
195 + " It is still referred to by relation {1}.<br>"
196 + "Please load the relation, remove the reference to the way, and upload again.",
197 "<strong>Failed</strong> to delete <strong>way {0}</strong>."
198 + " It is still referred to by relations {1}.<br>"
199 + "Please load the relations, remove the reference to the way, and upload again.",
200 conflict.b.size(), objId, refIdsString) + "</html>";
201 } else {
202 throw new IllegalStateException();
203 }
204 } else if (conflict.a instanceof Relation) {
205 if (firstRefs instanceof Node) {
206 return "<html>" + trn(
207 "<strong>Failed</strong> to delete <strong>relation {0}</strong>."
208 + " It is still referred to by node {1}.<br>"
209 + "Please load the node, remove the reference to the relation, and upload again.",
210 "<strong>Failed</strong> to delete <strong>relation {0}</strong>."
211 + " It is still referred to by nodes {1}.<br>"
212 + "Please load the nodes, remove the reference to the relation, and upload again.",
213 conflict.b.size(), objId, refIdsString) + "</html>";
214 } else if (firstRefs instanceof Way) {
215 return "<html>" + trn(
216 "<strong>Failed</strong> to delete <strong>relation {0}</strong>."
217 + " It is still referred to by way {1}.<br>"
218 + "Please load the way, remove the reference to the relation, and upload again.",
219 "<strong>Failed</strong> to delete <strong>relation {0}</strong>."
220 + " It is still referred to by ways {1}.<br>"
221 + "Please load the ways, remove the reference to the relation, and upload again.",
222 conflict.b.size(), objId, refIdsString) + "</html>";
223 } else if (firstRefs instanceof Relation) {
224 return "<html>" + trn(
225 "<strong>Failed</strong> to delete <strong>relation {0}</strong>."
226 + " It is still referred to by relation {1}.<br>"
227 + "Please load the relation, remove the reference to the relation, and upload again.",
228 "<strong>Failed</strong> to delete <strong>relation {0}</strong>."
229 + " It is still referred to by relations {1}.<br>"
230 + "Please load the relations, remove the reference to the relation, and upload again.",
231 conflict.b.size(), objId, refIdsString) + "</html>";
232 } else {
233 throw new IllegalStateException();
234 }
235 } else {
236 throw new IllegalStateException();
237 }
238 } else {
239 return tr(
240 "<html>Uploading to the server <strong>failed</strong> because your current<br>"
241 + "dataset violates a precondition.<br>" + "The error message is:<br>" + "{0}" + "</html>",
242 escapeReservedCharactersHTML(e.getMessage()));
243 }
244 }
245
246 public static String explainFailedBasicAuthentication(OsmApiException e) {
247 e.printStackTrace();
248 return tr("<html>"
249 + "Authentication at the OSM server with the username ''{0}'' failed.<br>"
250 + "Please check the username and the password in the JOSM preferences."
251 + "</html>",
252 CredentialsManager.getInstance().getUsername()
253 );
254 }
255
256 public static String explainFailedOAuthAuthentication(OsmApiException e) {
257 e.printStackTrace();
258 return tr("<html>"
259 + "Authentication at the OSM server with the OAuth token ''{0}'' failed.<br>"
260 + "Please launch the preferences dialog and retrieve another OAuth token."
261 + "</html>",
262 OAuthAccessTokenHolder.getInstance().getAccessTokenKey()
263 );
264 }
265
266 public static String explainFailedAuthorisation(OsmApiException e) {
267 e.printStackTrace();
268 String header = e.getErrorHeader();
269 String body = e.getErrorBody();
270 String msg = null;
271 if (header != null) {
272 if (body != null && !header.equals(body)) {
273 msg = header + " (" + body + ")";
274 } else {
275 msg = header;
276 }
277 } else {
278 msg = body;
279 }
280
281 if (msg != null && !msg.isEmpty()) {
282 return tr("<html>"
283 + "Authorisation at the OSM server failed.<br>"
284 + "The server reported the following error:<br>"
285 + "''{0}''"
286 + "</html>",
287 msg
288 );
289 } else {
290 return tr("<html>"
291 + "Authorisation at the OSM server failed.<br>"
292 + "</html>"
293 );
294 }
295 }
296
297 public static String explainFailedOAuthAuthorisation(OsmApiException e) {
298 e.printStackTrace();
299 return tr("<html>"
300 + "Authorisation at the OSM server with the OAuth token ''{0}'' failed.<br>"
301 + "The token is not authorised to access the protected resource<br>"
302 + "''{1}''.<br>"
303 + "Please launch the preferences dialog and retrieve another OAuth token."
304 + "</html>",
305 OAuthAccessTokenHolder.getInstance().getAccessTokenKey(),
306 e.getAccessedUrl() == null ? tr("unknown") : e.getAccessedUrl()
307 );
308 }
309
310 /**
311 * Explains an OSM API exception because of a client timeout (HTTP 408).
312 *
313 * @param e the exception
314 * @return the message
315 */
316 public static String explainClientTimeout(OsmApiException e) {
317 e.printStackTrace();
318 return tr("<html>"
319 + "Communication with the OSM server ''{0}'' timed out. Please retry later."
320 + "</html>",
321 OsmApi.getOsmApi().getBaseUrl()
322 );
323 }
324
325 /**
326 * Replies a generic error message for an OSM API exception
327 *
328 * @param e the exception
329 * @return the message
330 */
331 public static String explainGenericOsmApiException(OsmApiException e) {
332 e.printStackTrace();
333 String errMsg = e.getErrorHeader();
334 if (errMsg == null) {
335 errMsg = e.getErrorBody();
336 }
337 if (errMsg == null) {
338 errMsg = tr("no error message available");
339 }
340 return tr("<html>"
341 + "Communication with the OSM server ''{0}''failed. The server replied<br>"
342 + "the following error code and the following error message:<br>"
343 + "<strong>Error code:<strong> {1}<br>"
344 + "<strong>Error message (untranslated)</strong>: {2}"
345 + "</html>",
346 OsmApi.getOsmApi().getBaseUrl(),
347 e.getResponseCode(),
348 errMsg
349 );
350 }
351
352 /**
353 * Explains an error due to a 409 conflict
354 *
355 * @param e the exception
356 */
357 public static String explainConflict(OsmApiException e) {
358 e.printStackTrace();
359 String msg = e.getErrorHeader();
360 if (msg != null) {
361 String pattern = "The changeset (\\d+) was closed at (.*)";
362 Pattern p = Pattern.compile(pattern);
363 Matcher m = p.matcher(msg);
364 if (m.matches()) {
365 long changesetId = Long.parseLong(m.group(1));
366 // Example: "2010-09-07 14:39:41 UTC". Always parsed with US locale, regardless
367 // of the current locale in JOSM
368 DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z", Locale.US);
369 Date closeDate = null;
370 try {
371 closeDate = formatter.parse(m.group(2));
372 } catch (ParseException ex) {
373 Main.error(tr("Failed to parse date ''{0}'' replied by server.", m.group(2)));
374 ex.printStackTrace();
375 }
376 if (closeDate == null) {
377 msg = tr(
378 "<html>Closing of changeset <strong>{0}</strong> failed <br>because it has already been closed.",
379 changesetId
380 );
381 } else {
382 SimpleDateFormat dateFormat = new SimpleDateFormat();
383 msg = tr(
384 "<html>Closing of changeset <strong>{0}</strong> failed<br>"
385 +" because it has already been closed on {1}.",
386 changesetId,
387 dateFormat.format(closeDate)
388 );
389 }
390 return msg;
391 }
392 msg = tr(
393 "<html>The server reported that it has detected a conflict.<br>" +
394 "Error message (untranslated):<br>{0}</html>",
395 msg
396 );
397 } else {
398 msg = tr(
399 "<html>The server reported that it has detected a conflict.");
400 }
401 return msg;
402 }
403
404 /**
405 * Explains an exception thrown during upload because the changeset which data is
406 * uploaded to is already closed.
407 *
408 * @param e the exception
409 */
410 public static String explainChangesetClosedException(ChangesetClosedException e) {
411 String msg;
412 SimpleDateFormat dateFormat = new SimpleDateFormat();
413 msg = tr(
414 "<html>Failed to upload to changeset <strong>{0}</strong><br>"
415 +"because it has already been closed on {1}.",
416 e.getChangesetId(),
417 e.getClosedOn() == null ? "?" : dateFormat.format(e.getClosedOn())
418 );
419 e.printStackTrace();
420 return msg;
421 }
422
423 /**
424 * Explains an exception with a generic message dialog
425 *
426 * @param e the exception
427 */
428 public static String explainGeneric(Exception e) {
429 String msg = e.getMessage();
430 if (msg == null || msg.trim().isEmpty()) {
431 msg = e.toString();
432 }
433 e.printStackTrace();
434 return escapeReservedCharactersHTML(msg);
435 }
436
437 /**
438 * Explains a {@link SecurityException} which has caused an {@link OsmTransferException}.
439 * This is most likely happening when user tries to access the OSM API from within an
440 * applet which wasn't loaded from the API server.
441 *
442 * @param e the exception
443 */
444
445 public static String explainSecurityException(OsmTransferException e) {
446 String apiUrl = e.getUrl();
447 String host = tr("unknown");
448 try {
449 host = new URL(apiUrl).getHost();
450 } catch (MalformedURLException ex) {
451 // shouldn't happen
452 }
453
454 String message = tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''<br>"
455 + "for security reasons. This is most likely because you are running<br>"
456 + "in an applet and because you did not load your applet from ''{1}''.", apiUrl, host);
457 return message;
458 }
459
460 /**
461 * Explains a {@link SocketException} which has caused an {@link OsmTransferException}.
462 * This is most likely because there's not connection to the Internet or because
463 * the remote server is not reachable.
464 *
465 * @param e the exception
466 */
467
468 public static String explainNestedSocketException(OsmTransferException e) {
469 String apiUrl = e.getUrl();
470 String message = tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''.<br>"
471 + "Please check your internet connection.", apiUrl);
472 e.printStackTrace();
473 return message;
474 }
475
476 /**
477 * Explains a {@link IOException} which has caused an {@link OsmTransferException}.
478 * This is most likely happening when the communication with the remote server is
479 * interrupted for any reason.
480 *
481 * @param e the exception
482 */
483
484 public static String explainNestedIOException(OsmTransferException e) {
485 IOException ioe = getNestedException(e, IOException.class);
486 String apiUrl = e.getUrl();
487 String message = tr("<html>Failed to upload data to or download data from<br>" + "''{0}''<br>"
488 + "due to a problem with transferring data.<br>"
489 + "Details (untranslated): {1}</html>", apiUrl, ioe
490 .getMessage());
491 e.printStackTrace();
492 return message;
493 }
494
495 /**
496 * Explains a {@link IllegalDataException} which has caused an {@link OsmTransferException}.
497 * This is most likely happening when JOSM tries to load data in in an unsupported format.
498 *
499 * @param e the exception
500 */
501 public static String explainNestedIllegalDataException(OsmTransferException e) {
502 IllegalDataException ide = getNestedException(e, IllegalDataException.class);
503 String message = tr("<html>Failed to download data. "
504 + "Its format is either unsupported, ill-formed, and/or inconsistent.<br>"
505 + "<br>Details (untranslated): {0}</html>", ide.getMessage());
506 e.printStackTrace();
507 return message;
508 }
509
510 /**
511 * Explains a {@link OsmApiException} which was thrown because of an internal server
512 * error in the OSM API server..
513 *
514 * @param e the exception
515 */
516
517 public static String explainInternalServerError(OsmTransferException e) {
518 String apiUrl = e.getUrl();
519 String message = tr("<html>The OSM server<br>" + "''{0}''<br>" + "reported an internal server error.<br>"
520 + "This is most likely a temporary problem. Please try again later.", apiUrl);
521 e.printStackTrace();
522 return message;
523 }
524
525 /**
526 * Explains a {@link OsmApiException} which was thrown because of a bad
527 * request
528 *
529 * @param e the exception
530 */
531 public static String explainBadRequest(OsmApiException e) {
532 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
533 String message = tr("The OSM server ''{0}'' reported a bad request.<br>", apiUrl);
534 if (e.getErrorHeader() != null &&
535 (e.getErrorHeader().startsWith("The maximum bbox") ||
536 e.getErrorHeader().startsWith("You requested too many nodes"))) {
537 message += "<br>"
538 + tr("The area you tried to download is too big or your request was too large."
539 + "<br>Either request a smaller area or use an export file provided by the OSM community.");
540 } else if (e.getErrorHeader() != null) {
541 message += tr("<br>Error message(untranslated): {0}", e.getErrorHeader());
542 }
543 message = "<html>" + message + "</html>";
544 e.printStackTrace();
545 return message;
546 }
547
548 /**
549 * Explains a {@link OsmApiException} which was thrown because of
550 * bandwidth limit exceeded (HTTP error 509)
551 *
552 * @param e the exception
553 */
554 public static String explainBandwidthLimitExceeded(OsmApiException e) {
555 // TODO: Write a proper error message
556 String message = explainGenericOsmApiException(e);
557 e.printStackTrace();
558 return message;
559 }
560
561
562 /**
563 * Explains a {@link OsmApiException} which was thrown because a resource wasn't found.
564 *
565 * @param e the exception
566 */
567 public static String explainNotFound(OsmApiException e) {
568 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
569 String message = tr("The OSM server ''{0}'' does not know about an object<br>"
570 + "you tried to read, update, or delete. Either the respective object<br>"
571 + "does not exist on the server or you are using an invalid URL to access<br>"
572 + "it. Please carefully check the server''s address ''{0}'' for typos."
573 , apiUrl);
574 message = "<html>" + message + "</html>";
575 e.printStackTrace();
576 return message;
577 }
578
579 /**
580 * Explains a {@link UnknownHostException} which has caused an {@link OsmTransferException}.
581 * This is most likely happening when there is an error in the API URL or when
582 * local DNS services are not working.
583 *
584 * @param e the exception
585 */
586
587 public static String explainNestedUnknownHostException(OsmTransferException e) {
588 String apiUrl = e.getUrl();
589 String host = tr("unknown");
590 try {
591 host = new URL(apiUrl).getHost();
592 } catch (MalformedURLException ex) {
593 // shouldn't happen
594 }
595
596 String message = tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''.<br>"
597 + "Host name ''{1}'' could not be resolved. <br>"
598 + "Please check the API URL in your preferences and your internet connection.", apiUrl, host);
599 e.printStackTrace();
600 return message;
601 }
602
603 /**
604 * Replies the first nested exception of type <code>nestedClass</code> (including
605 * the root exception <code>e</code>) or null, if no such exception is found.
606 *
607 * @param <T>
608 * @param e the root exception
609 * @param nestedClass the type of the nested exception
610 * @return the first nested exception of type <code>nestedClass</code> (including
611 * the root exception <code>e</code>) or null, if no such exception is found.
612 */
613 protected static <T> T getNestedException(Exception e, Class<T> nestedClass) {
614 Throwable t = e;
615 while (t != null && !(nestedClass.isInstance(t))) {
616 t = t.getCause();
617 }
618 if (t == null)
619 return null;
620 else if (nestedClass.isInstance(t))
621 return nestedClass.cast(t);
622 return null;
623 }
624
625 /**
626 * Explains an {@link OsmTransferException} to the user.
627 *
628 * @param e the {@link OsmTransferException}
629 */
630 public static String explainOsmTransferException(OsmTransferException e) {
631 if (getNestedException(e, SecurityException.class) != null)
632 return explainSecurityException(e);
633 if (getNestedException(e, SocketException.class) != null)
634 return explainNestedSocketException(e);
635 if (getNestedException(e, UnknownHostException.class) != null)
636 return explainNestedUnknownHostException(e);
637 if (getNestedException(e, IOException.class) != null)
638 return explainNestedIOException(e);
639 if (e instanceof OsmApiInitializationException)
640 return explainOsmApiInitializationException((OsmApiInitializationException) e);
641
642 if (e instanceof ChangesetClosedException)
643 return explainChangesetClosedException((ChangesetClosedException)e);
644
645 if (e instanceof OsmApiException) {
646 OsmApiException oae = (OsmApiException) e;
647 if (oae.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED)
648 return explainPreconditionFailed(oae);
649 if (oae.getResponseCode() == HttpURLConnection.HTTP_GONE)
650 return explainGoneForUnknownPrimitive(oae);
651 if (oae.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR)
652 return explainInternalServerError(oae);
653 if (oae.getResponseCode() == HttpURLConnection.HTTP_BAD_REQUEST)
654 return explainBadRequest(oae);
655 if (oae.getResponseCode() == 509)
656 return explainBandwidthLimitExceeded(oae);
657 }
658 return explainGeneric(e);
659 }
660
661 /**
662 * explains the case of an error due to a delete request on an already deleted
663 * {@link OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which
664 * {@link OsmPrimitive} is causing the error.
665 *
666 * @param e the exception
667 */
668 public static String explainGoneForUnknownPrimitive(OsmApiException e) {
669 String msg = tr(
670 "<html>The server reports that an object is deleted.<br>"
671 + "<strong>Uploading failed</strong> if you tried to update or delete this object.<br> "
672 + "<strong>Downloading failed</strong> if you tried to download this object.<br>"
673 + "<br>"
674 + "The error message is:<br>" + "{0}"
675 + "</html>", escapeReservedCharactersHTML(e.getMessage()));
676 return msg;
677
678 }
679
680 /**
681 * Explains an {@link Exception} to the user.
682 *
683 * @param e the {@link Exception}
684 */
685 public static String explainException(Exception e) {
686 String msg = "";
687 if (e instanceof OsmTransferException) {
688 msg = explainOsmTransferException((OsmTransferException) e);
689 } else {
690 msg = explainGeneric(e);
691 }
692 e.printStackTrace();
693 return msg;
694 }
695
696 /**
697 * Replaces some HTML reserved characters (<, > and &) by their equivalent entity (&lt;, &gt; and &amp;);
698 * @param s The unescaped string
699 * @return The escaped string
700 */
701 public static String escapeReservedCharactersHTML(String s) {
702 return s == null ? "" : s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
703 }
704}
Note: See TracBrowser for help on using the repository browser.