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

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

fix #8201 - Error handling or redacted items

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