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

Last change on this file since 2035 was 2035, checked in by Gubaer, 15 years ago

Improved user feedback in case of timed retries after InternalServerErrors
Improved user feedback in case of problems with closing changesets

File size: 12.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
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;
12
13import javax.swing.JOptionPane;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.io.OsmApi;
17import org.openstreetmap.josm.io.OsmApiException;
18import org.openstreetmap.josm.io.OsmApiInitializationException;
19import org.openstreetmap.josm.io.OsmChangesetCloseException;
20import org.openstreetmap.josm.io.OsmTransferException;
21
22/**
23 * This utility class provides static methods which explain various exceptions to the user.
24 *
25 */
26public class ExceptionDialogUtil {
27
28 /**
29 * just static utility functions. no constructor
30 */
31 private ExceptionDialogUtil() {}
32
33 /**
34 * handles an exception caught during OSM API initialization
35 *
36 * @param e the exception
37 */
38 public static void explainOsmApiInitializationException(OsmApiInitializationException e) {
39 e.printStackTrace();
40 JOptionPane.showMessageDialog(
41 Main.parent,
42 tr( "<html>Failed to initialize communication with the OSM server {0}.<br>"
43 + "Check the server URL in your preferences and your internet connection.</html>",
44 Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api")
45 ),
46 tr("Error"),
47 JOptionPane.ERROR_MESSAGE
48 );
49 }
50
51 /**
52 * handles an exception caught during OSM API initialization
53 *
54 * @param e the exception
55 */
56 public static void explainOsmChangesetCloseException(OsmChangesetCloseException e) {
57 e.printStackTrace();
58 String changsetId = e.getChangeset() == null ? tr("unknown") : Long.toString(e.getChangeset().getId());
59 JOptionPane.showMessageDialog(
60 Main.parent,
61 tr( "<html>Failed to close changeset ''{0}'' on the OSM server ''{1}''.<br>"
62 + "The changeset will automatically be closed by the server after a timeout.</html>",
63 changsetId,
64 Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api")
65 ),
66 tr("Error"),
67 JOptionPane.ERROR_MESSAGE
68 );
69 }
70
71
72 /**
73 * Explains an upload error due to a violated precondition, i.e. a HTTP return code 412
74 *
75 * @param e the exception
76 */
77 public static void explainPreconditionFailed(OsmApiException e) {
78 e.printStackTrace();
79 JOptionPane.showMessageDialog(
80 Main.parent,
81 tr("<html>Uploading to the server <strong>failed</strong> because your current<br>"
82 +"dataset violates a precondition.<br>"
83 +"The error message is:<br>"
84 + "{0}"
85 + "</html>",
86 e.getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
87 ),
88 tr("Precondition violation"),
89 JOptionPane.ERROR_MESSAGE
90 );
91 }
92
93
94 /**
95 * Explains an exception with a generic message dialog
96 *
97 * @param e the exception
98 */
99 public static void explainGeneric(Exception e) {
100 String msg = e.getMessage();
101 if (msg == null || msg.trim().equals("")) {
102 msg = e.toString();
103 }
104 e.printStackTrace();
105 JOptionPane.showMessageDialog(
106 Main.parent,
107 msg,
108 tr("Error"),
109 JOptionPane.ERROR_MESSAGE
110 );
111 }
112
113 /**
114 * Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
115 * This is most likely happening when user tries to access the OSM API from within an
116 * applet which wasn't loaded from the API server.
117 *
118 * @param e the exception
119 */
120
121 public static void explainSecurityException(OsmTransferException e) {
122 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
123 String host = tr("unknown");
124 try {
125 host = new URL(apiUrl).getHost();
126 } catch(MalformedURLException ex) {
127 // shouldn't happen
128 }
129
130 String message = tr("<html>Failed to open a connection to the remote server<br>"
131 + "''{0}''<br>"
132 + "for security reasons. This is most likely because you are running<br>"
133 + "in an applet and because you didn''t load your applet from ''{1}''.</html>",
134 apiUrl, host
135 );
136 JOptionPane.showMessageDialog(
137 Main.parent,
138 message,
139 tr("Security exception"),
140 JOptionPane.ERROR_MESSAGE
141 );
142 }
143
144 /**
145 * Explains a {@see SocketException} which has caused an {@see OsmTransferException}.
146 * This is most likely because there's not connection to the Internet or because
147 * the remote server is not reachable.
148 *
149 * @param e the exception
150 */
151
152 public static void explainNestedSocketException(OsmTransferException e) {
153 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
154 String message = tr("<html>Failed to open a connection to the remote server<br>"
155 + "''{0}''.<br>"
156 + "Please check your internet connection.</html>",
157 apiUrl
158 );
159 e.printStackTrace();
160 JOptionPane.showMessageDialog(
161 Main.parent,
162 message,
163 tr("Network exception"),
164 JOptionPane.ERROR_MESSAGE
165 );
166 }
167
168 /**
169 * Explains a {@see IOException} which has caused an {@see OsmTransferException}.
170 * This is most likely happening when the communication with the remote server is
171 * interrupted for any reason.
172 *
173 * @param e the exception
174 */
175
176 public static void explainNestedIOException(OsmTransferException e) {
177 IOException ioe = getNestedException(e, IOException.class);
178 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
179 String message = tr("<html>Failed to upload data to or download data from<br>"
180 + "''{0}''<br>"
181 + "due to a problem with transferring data.<br>"
182 + "Details(untranslated): {1}</html>",
183 apiUrl, ioe.getMessage()
184 );
185 e.printStackTrace();
186 JOptionPane.showMessageDialog(
187 Main.parent,
188 message,
189 tr("IO Exception"),
190 JOptionPane.ERROR_MESSAGE
191 );
192 }
193
194 /**
195 * Explains a {@see OsmApiException} which was thrown because of an internal server
196 * error in the OSM API server..
197 *
198 * @param e the exception
199 */
200
201 public static void explainInternalServerError(OsmTransferException e) {
202 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
203 String message = tr("<html>The OSM server<br>"
204 + "''{0}''<br>"
205 + "reported an internal server error.<br>"
206 + "This is most likely a temporary problem. Please try again later.</html>",
207 apiUrl
208 );
209 e.printStackTrace();
210 JOptionPane.showMessageDialog(
211 Main.parent,
212 message,
213 tr("Internal Server Error"),
214 JOptionPane.ERROR_MESSAGE
215 );
216 }
217
218 /**
219 * Explains a {@see UnknownHostException} which has caused an {@see OsmTransferException}.
220 * This is most likely happening when there is an error in the API URL or when
221 * local DNS services are not working.
222 *
223 * @param e the exception
224 */
225
226 public static void explainNestedUnkonwnHostException(OsmTransferException e) {
227 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
228 String host = tr("unknown");
229 try {
230 host = new URL(apiUrl).getHost();
231 } catch(MalformedURLException ex) {
232 // shouldn't happen
233 }
234
235 String message = tr("<html>Failed to open a connection to the remote server<br>"
236 + "''{0}''.<br>"
237 + "Host name ''{1}'' couldn''t be resolved. <br>"
238 + "Please check the API URL in your preferences and your internet connection.</html>",
239 apiUrl, host
240 );
241 e.printStackTrace();
242 JOptionPane.showMessageDialog(
243 Main.parent,
244 message,
245 tr("Unknown host"),
246 JOptionPane.ERROR_MESSAGE
247 );
248 }
249
250 /**
251 * Replies the first nested exception of type <code>nestedClass</code> (including
252 * the root exception <code>e</code>) or null, if no such exception is found.
253 *
254 * @param <T>
255 * @param e the root exception
256 * @param nestedClass the type of the nested exception
257 * @return the first nested exception of type <code>nestedClass</code> (including
258 * the root exception <code>e</code>) or null, if no such exception is found.
259 */
260 protected static <T> T getNestedException(Exception e, Class<T> nestedClass) {
261 Throwable t = e;
262 while (t != null && !(nestedClass.isInstance(t))) {
263 t = t.getCause();
264 }
265 if (t== null)
266 return null;
267 else if (nestedClass.isInstance(t))
268 return nestedClass.cast(t);
269 return null;
270 }
271
272 /**
273 * Explains an {@see OsmTransferException} to the user.
274 *
275 * @param e the {@see OsmTransferException}
276 */
277 public static void explainOsmTransferException(OsmTransferException e) {
278 if (getNestedException(e, SecurityException.class) != null) {
279 explainSecurityException(e);
280 return;
281 }
282 if (getNestedException(e, SocketException.class) != null) {
283 explainNestedSocketException(e);
284 return;
285 }
286 if (getNestedException(e, UnknownHostException.class) != null) {
287 explainNestedUnkonwnHostException(e);
288 return;
289 }
290 if (getNestedException(e, IOException.class) != null) {
291 explainNestedIOException(e);
292 return;
293 }
294 if (e instanceof OsmApiInitializationException){
295 explainOsmApiInitializationException((OsmApiInitializationException)e);
296 return;
297 }
298 if (e instanceof OsmChangesetCloseException){
299 explainOsmChangesetCloseException((OsmChangesetCloseException)e);
300 return;
301 }
302
303 if (e instanceof OsmApiException) {
304 OsmApiException oae = (OsmApiException)e;
305 if (oae.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) {
306 explainPreconditionFailed(oae);
307 return;
308 }
309 if (oae.getResponseCode() == HttpURLConnection.HTTP_GONE) {
310 explainGoneForUnknownPrimitive(oae);
311 return;
312 }
313 if (oae.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
314 explainInternalServerError(oae);
315 return;
316 }
317 }
318 explainGeneric(e);
319 }
320
321 /**
322 * explains the case of an error due to a delete request on an already deleted
323 * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which
324 * {@see OsmPrimitive} is causing the error.
325 *
326 * @param e the exception
327 */
328 public static void explainGoneForUnknownPrimitive(OsmApiException e) {
329 String msg = tr("<html>Uploading <strong>failed</strong> because a primitive you tried to<br>"
330 + "delete on the server is already deleted.<br>"
331 + "<br>"
332 + "The error message is:<br>"
333 + "{0}"
334 + "</html>",
335 e.getMessage().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
336 );
337 JOptionPane.showMessageDialog(
338 Main.parent,
339 msg,
340 tr("Primitive already deleted"),
341 JOptionPane.ERROR_MESSAGE
342 );
343
344 }
345
346 /**
347 * Explains an {@see Exception} to the user.
348 *
349 * @param e the {@see Exception}
350 */
351 public static void explainException(Exception e) {
352 if (e instanceof OsmTransferException) {
353 explainOsmTransferException((OsmTransferException)e);
354 return;
355 }
356 explainGeneric(e);
357 }
358}
Note: See TracBrowser for help on using the repository browser.