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

Last change on this file since 7022 was 7005, checked in by Don-vip, 10 years ago

see #8465 - use diamond operator where applicable

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