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

Last change on this file since 2702 was 2512, checked in by stoecker, 14 years ago

i18n updated, fixed files to reduce problems when applying patches, fix #4017

File size: 15.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;
5
6import java.io.IOException;
7import java.net.HttpURLConnection;
8import java.net.MalformedURLException;
9import java.net.SocketException;
10import java.net.URL;
11import java.net.UnknownHostException;
12import java.text.DateFormat;
13import java.text.ParseException;
14import java.text.SimpleDateFormat;
15import java.util.Date;
16import java.util.Locale;
17import java.util.regex.Matcher;
18import java.util.regex.Pattern;
19
20import org.openstreetmap.josm.Main;
21import org.openstreetmap.josm.io.ChangesetClosedException;
22import org.openstreetmap.josm.io.OsmApi;
23import org.openstreetmap.josm.io.OsmApiException;
24import org.openstreetmap.josm.io.OsmApiInitializationException;
25import org.openstreetmap.josm.io.OsmTransferException;
26
27public class ExceptionUtil {
28 private ExceptionUtil() {
29 }
30
31 /**
32 * handles an exception caught during OSM API initialization
33 *
34 * @param e the exception
35 */
36 public static String explainOsmApiInitializationException(OsmApiInitializationException e) {
37 e.printStackTrace();
38 String msg = tr(
39 "<html>Failed to initialize communication with the OSM server {0}.<br>"
40 + "Check the server URL in your preferences and your internet connection.</html>", Main.pref.get(
41 "osm-server.url", "http://api.openstreetmap.org/api"));
42 return msg;
43 }
44
45 /**
46 * Explains a precondition exception when a child relation could not be deleted because
47 * it is still referred to by an undeleted parent relation.
48 *
49 * @param e the exception
50 * @param childRelation the child relation
51 * @param parentRelation the parent relation
52 * @return
53 */
54 public static String explainDeletedRelationStillInUse(OsmApiException e, long childRelation, long parentRelation) {
55 String msg = tr(
56 "<html><strong>Failed</strong> to delete <strong>relation {0}</strong>."
57 + " It is still referred to by relation {1}.<br>"
58 + "Please load relation {1}, remove the reference to relation {0}, and upload again.</html>",
59 childRelation,parentRelation
60 );
61 return msg;
62 }
63
64 /**
65 * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412
66 *
67 * @param e the exception
68 */
69 public static String explainPreconditionFailed(OsmApiException e) {
70 e.printStackTrace();
71 String msg = e.getErrorHeader();
72 if (msg != null) {
73 String pattern = "Precondition failed: The relation (\\d+) is used in relation (\\d+)\\.";
74 Pattern p = Pattern.compile(pattern);
75 Matcher m = p.matcher(msg);
76 if (m.matches()) {
77 long childRelation = Long.parseLong(m.group(1));
78 long parentRelation = Long.parseLong(m.group(2));
79 return explainDeletedRelationStillInUse(e, childRelation, parentRelation);
80 }
81 }
82 msg = tr(
83 "<html>Uploading to the server <strong>failed</strong> because your current<br>"
84 + "dataset violates a precondition.<br>" + "The error message is:<br>" + "{0}" + "</html>", e
85 .getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"));
86 return msg;
87 }
88
89 /**
90 * Explains an error due to a 409 conflict
91 *
92 * @param e the exception
93 */
94 public static String explainConflict(OsmApiException e) {
95 e.printStackTrace();
96 String msg = e.getErrorHeader();
97 if (msg != null) {
98 String pattern = "The changeset (\\d+) was closed at (.*)";
99 Pattern p = Pattern.compile(pattern);
100 Matcher m = p.matcher(msg);
101 if (m.matches()) {
102 long changesetId = Long.parseLong(m.group(1));
103 // Example: Tue Oct 15 10:00:00 UTC 2009. Always parsed with english locale, regardless
104 // of the current locale in JOSM
105 DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
106 Date closeDate = null;
107 try {
108 closeDate = formatter.parse(m.group(2));
109 } catch(ParseException ex) {
110 System.err.println(tr("Failed to parse date ''{0}'' replied by server.", m.group(2)));
111 ex.printStackTrace();
112 }
113 if (closeDate == null) {
114 msg = tr(
115 "<html>Closing of changeset <strong>{0}</strong> failed <br>because it has already been closed.</html>",
116 changesetId
117 );
118 } else {
119 SimpleDateFormat dateFormat = new SimpleDateFormat();
120 msg = tr(
121 "<html>Closing of changeset <strong>{0}</strong> failed<br>"
122 +" because it has already been closed on {1}.</html>",
123 changesetId,
124 dateFormat.format(closeDate)
125 );
126 }
127 return msg;
128 }
129 msg = tr(
130 "<html>The server reported that it has detected a conflict.<br>" +
131 "Error message (untranslated):<br>{0}</html>",
132 msg
133 );
134 }
135 msg = tr(
136 "<html>The server reported that it has detected a conflict.</html>"
137 );
138 return msg;
139 }
140
141 /**
142 * Explains an exception thrown during upload because the changeset which data is
143 * uploaded to is already closed.
144 *
145 * @param e the exception
146 */
147 public static String explainChangesetClosedException(ChangesetClosedException e) {
148 String msg;
149 SimpleDateFormat dateFormat = new SimpleDateFormat();
150 msg = tr(
151 "<html>Failed to upload to changeset <strong>{0}</strong><br>"
152 +"because it has already been closed on {1}.</html>",
153 e.getChangesetId(),
154 dateFormat.format(e.getClosedOn())
155 );
156 e.printStackTrace();
157 return msg;
158 }
159
160 /**
161 * Explains an exception with a generic message dialog
162 *
163 * @param e the exception
164 */
165 public static String explainGeneric(Exception e) {
166 String msg = e.getMessage();
167 if (msg == null || msg.trim().equals("")) {
168 msg = e.toString();
169 }
170 e.printStackTrace();
171 return msg;
172 }
173
174 /**
175 * Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
176 * This is most likely happening when user tries to access the OSM API from within an
177 * applet which wasn't loaded from the API server.
178 *
179 * @param e the exception
180 */
181
182 public static String explainSecurityException(OsmTransferException e) {
183 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
184 String host = tr("unknown");
185 try {
186 host = new URL(apiUrl).getHost();
187 } catch (MalformedURLException ex) {
188 // shouldn't happen
189 }
190
191 String message = tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''<br>"
192 + "for security reasons. This is most likely because you are running<br>"
193 + "in an applet and because you didn''t load your applet from ''{1}''.</html>", apiUrl, host);
194 return message;
195 }
196
197 /**
198 * Explains a {@see SocketException} which has caused an {@see OsmTransferException}.
199 * This is most likely because there's not connection to the Internet or because
200 * the remote server is not reachable.
201 *
202 * @param e the exception
203 */
204
205 public static String explainNestedSocketException(OsmTransferException e) {
206 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
207 String message = tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''.<br>"
208 + "Please check your internet connection.</html>", apiUrl);
209 e.printStackTrace();
210 return message;
211 }
212
213 /**
214 * Explains a {@see IOException} which has caused an {@see OsmTransferException}.
215 * This is most likely happening when the communication with the remote server is
216 * interrupted for any reason.
217 *
218 * @param e the exception
219 */
220
221 public static String explainNestedIOException(OsmTransferException e) {
222 IOException ioe = getNestedException(e, IOException.class);
223 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
224 String message = tr("<html>Failed to upload data to or download data from<br>" + "''{0}''<br>"
225 + "due to a problem with transferring data.<br>" + "Details(untranslated): {1}</html>", apiUrl, ioe
226 .getMessage());
227 e.printStackTrace();
228 return message;
229 }
230
231 /**
232 * Explains a {@see OsmApiException} which was thrown because of an internal server
233 * error in the OSM API server..
234 *
235 * @param e the exception
236 */
237
238 public static String explainInternalServerError(OsmTransferException e) {
239 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
240 String message = tr("<html>The OSM server<br>" + "''{0}''<br>" + "reported an internal server error.<br>"
241 + "This is most likely a temporary problem. Please try again later.</html>", apiUrl);
242 e.printStackTrace();
243 return message;
244 }
245
246 /**
247 * Explains a {@see OsmApiException} which was thrown because of a bad
248 * request
249 *
250 * @param e the exception
251 */
252 public static String explainBadRequest(OsmApiException e) {
253 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
254 String message = tr("The OSM server ''{0}'' reported a bad request.<br>", apiUrl);
255 if (e.getErrorHeader() != null && e.getErrorHeader().startsWith("The maximum bbox")) {
256 message += "<br>"
257 + tr("The area you tried to download is too big or your request was too large."
258 + "<br>Either request a smaller area or use an export file provided by the OSM community.");
259 } else if (e.getErrorHeader() != null) {
260 message += tr("<br>Error message(untranslated): {0}", e.getErrorHeader());
261 }
262 message = "<html>" + message + "</html>";
263 e.printStackTrace();
264 return message;
265 }
266
267 /**
268 * Explains a {@see OsmApiException} which was thrown because a resource wasn't found.
269 *
270 * @param e the exception
271 */
272 public static String explainNotFound(OsmApiException e) {
273 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
274 String message = tr("The OSM server ''{0}'' doesn''t know about an object<br>"
275 + "you tried to read, update, or delete. Either the respective object<br>"
276 + "doesn''t exist on the server or you''re using an invalid URL to access<br>"
277 + "it. Please carefully check the servers address ''{0}'' for typos."
278 , apiUrl);
279 message = "<html>" + message + "</html>";
280 e.printStackTrace();
281 return message;
282 }
283
284 /**
285 * Explains a {@see UnknownHostException} which has caused an {@see OsmTransferException}.
286 * This is most likely happening when there is an error in the API URL or when
287 * local DNS services are not working.
288 *
289 * @param e the exception
290 */
291
292 public static String explainNestedUnkonwnHostException(OsmTransferException e) {
293 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
294 String host = tr("unknown");
295 try {
296 host = new URL(apiUrl).getHost();
297 } catch (MalformedURLException ex) {
298 // shouldn't happen
299 }
300
301 String message = tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''.<br>"
302 + "Host name ''{1}'' couldn''t be resolved. <br>"
303 + "Please check the API URL in your preferences and your internet connection.</html>", apiUrl, host);
304 e.printStackTrace();
305 return message;
306 }
307
308 /**
309 * Replies the first nested exception of type <code>nestedClass</code> (including
310 * the root exception <code>e</code>) or null, if no such exception is found.
311 *
312 * @param <T>
313 * @param e the root exception
314 * @param nestedClass the type of the nested exception
315 * @return the first nested exception of type <code>nestedClass</code> (including
316 * the root exception <code>e</code>) or null, if no such exception is found.
317 */
318 protected static <T> T getNestedException(Exception e, Class<T> nestedClass) {
319 Throwable t = e;
320 while (t != null && !(nestedClass.isInstance(t))) {
321 t = t.getCause();
322 }
323 if (t == null)
324 return null;
325 else if (nestedClass.isInstance(t))
326 return nestedClass.cast(t);
327 return null;
328 }
329
330 /**
331 * Explains an {@see OsmTransferException} to the user.
332 *
333 * @param e the {@see OsmTransferException}
334 */
335 public static String explainOsmTransferException(OsmTransferException e) {
336 if (getNestedException(e, SecurityException.class) != null)
337 return explainSecurityException(e);
338 if (getNestedException(e, SocketException.class) != null)
339 return explainNestedSocketException(e);
340 if (getNestedException(e, UnknownHostException.class) != null)
341 return explainNestedUnkonwnHostException(e);
342 if (getNestedException(e, IOException.class) != null)
343 return explainNestedIOException(e);
344 if (e instanceof OsmApiInitializationException)
345 return explainOsmApiInitializationException((OsmApiInitializationException) e);
346
347 if (e instanceof ChangesetClosedException)
348 return explainChangesetClosedException((ChangesetClosedException)e);
349
350 if (e instanceof OsmApiException) {
351 OsmApiException oae = (OsmApiException) e;
352 if (oae.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED)
353 return explainPreconditionFailed(oae);
354 if (oae.getResponseCode() == HttpURLConnection.HTTP_GONE)
355 return explainGoneForUnknownPrimitive(oae);
356 if (oae.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR)
357 return explainInternalServerError(oae);
358 if (oae.getResponseCode() == HttpURLConnection.HTTP_BAD_REQUEST)
359 return explainBadRequest(oae);
360 }
361 return explainGeneric(e);
362 }
363
364 /**
365 * explains the case of an error due to a delete request on an already deleted
366 * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which
367 * {@see OsmPrimitive} is causing the error.
368 *
369 * @param e the exception
370 */
371 public static String explainGoneForUnknownPrimitive(OsmApiException e) {
372 String msg = tr(
373 "<html>The server reports that an object is deleted.<br>"
374 + "<strong>Uploading failed</strong> if you tried to update or delete this object.<br> "
375 + "<strong>Downloading failed</strong> if you tried to download this object.<br>"
376 + "<br>"
377 + "The error message is:<br>" + "{0}"
378 + "</html>", e.getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"));
379 return msg;
380
381 }
382
383 /**
384 * Explains an {@see Exception} to the user.
385 *
386 * @param e the {@see Exception}
387 */
388 public static String explainException(Exception e) {
389 String msg = "";
390 if (e instanceof OsmTransferException) {
391 msg = explainOsmTransferException((OsmTransferException) e);
392 } else {
393 msg = explainGeneric(e);
394 }
395 e.printStackTrace();
396 return msg;
397 }
398}
Note: See TracBrowser for help on using the repository browser.