// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import javax.swing.JOptionPane;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.io.OsmApi;
import org.openstreetmap.josm.io.OsmApiException;
import org.openstreetmap.josm.io.OsmApiInitializationException;
import org.openstreetmap.josm.io.OsmTransferException;
/**
* This utility class provides static methods which explain various exceptions to the user.
*
*/
public class ExceptionDialogUtil {
/**
* just static utility functions. no constructor
*/
private ExceptionDialogUtil() {}
/**
* handles an exception caught during OSM API initialization
*
* @param e the exception
*/
public static void explainOsmApiInitializationException(OsmApiInitializationException e) {
e.printStackTrace();
OptionPaneUtil.showMessageDialog(
Main.parent,
tr( "Failed to initialize communication with the OSM server {0}.\n"
+ "Check the server URL in your preferences and your internet connection.",
Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api")
),
tr("Error"),
JOptionPane.ERROR_MESSAGE
);
}
/**
* Explains an upload error due to a violated precondition, i.e. a HTTP return code 412
*
* @param e the exception
*/
public static void explainPreconditionFailed(OsmApiException e) {
e.printStackTrace();
OptionPaneUtil.showMessageDialog(
Main.parent,
tr("Uploading to the server failed because your current
"
+"dataset violates a precondition.
"
+"The error message is:
"
+ "{0}"
+ "",
e.getMessage().replace("&", "&").replace("<", "<").replace(">", ">")
),
tr("Precondition violation"),
JOptionPane.ERROR_MESSAGE
);
}
/**
* Explains an exception with a generic message dialog
*
* @param e the exception
*/
public static void explainGeneric(Exception e) {
String msg = e.getMessage();
if (msg == null) {
msg = e.toString();
}
e.printStackTrace();
OptionPaneUtil.showMessageDialog(
Main.parent,
msg,
tr("Error"),
JOptionPane.ERROR_MESSAGE
);
}
/**
* Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
* This is most likely happening when user tries to access the OSM API from whitin an
* applet which wasn't loaded from the API server.
*
* @param e the exception
*/
public static void explainSecurityException(OsmTransferException e) {
String apiUrl = OsmApi.getOsmApi().getBaseUrl();
String host = tr("unknown");
try {
host = new URL(apiUrl).getHost();
} catch(MalformedURLException ex) {
// shouldn't happen
}
String message = tr("Failed to open a connection to the remote server
"
+ "''{0}''
"
+ "for security reasons. This is most likely because you are running
"
+ "in an applet and because you didn''t load your applet from ''{1}''.",
apiUrl, host
);
OptionPaneUtil.showMessageDialog(
Main.parent,
message,
tr("Security exception"),
JOptionPane.ERROR_MESSAGE
);
}
/**
* Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
* This is most likely happening when user tries to access the OSM API from whitin an
* applet which wasn't loaded from the API server.
*
* @param e the exception
*/
public static void explainNestedSocketException(OsmTransferException e) {
String apiUrl = OsmApi.getOsmApi().getBaseUrl();
String message = tr("Failed to open a connection to the remote server
"
+ "''{0}''.
"
+ "Please check your internet connection.",
apiUrl
);
e.printStackTrace();
OptionPaneUtil.showMessageDialog(
Main.parent,
message,
tr("Network exception"),
JOptionPane.ERROR_MESSAGE
);
}
/**
* Explains a {@see SecurityException} which has caused an {@see OsmTransferException}.
* This is most likely happening when user tries to access the OSM API from whitin an
* applet which wasn't loaded from the API server.
*
* @param e the exception
*/
public static void explainNestedUnkonwnHostException(OsmTransferException e) {
String apiUrl = OsmApi.getOsmApi().getBaseUrl();
String host = tr("unknown");
try {
host = new URL(apiUrl).getHost();
} catch(MalformedURLException ex) {
// shouldn't happen
}
String message = tr("Failed to open a connection to the remote server
"
+ "''{0}''.
"
+ "Host name ''{1}'' couldn''t be resolved.
"
+ "Please check the API URL in your preferences and your internet connection.",
apiUrl, host
);
e.printStackTrace();
OptionPaneUtil.showMessageDialog(
Main.parent,
message,
tr("Unknown host"),
JOptionPane.ERROR_MESSAGE
);
}
protected static T getNestedException(Exception e, Class nested) {
Throwable t = e;
while (t != null && !(t.getClass().isAssignableFrom(nested))) {
t = t.getCause();
}
return nested.cast(t);
}
/**
* Replies the first {@see SecurityException} in a chain of nested exceptions.
* null, if no {@see SecurityException} is in this chain.
*
* @param e the root exception
* @return the first {@see SecurityException} in a chain of nested exceptions
*/
protected static SecurityException getNestedSecurityException(Exception e) {
return getNestedException(e, SecurityException.class);
}
/**
* Replies the first {@see SocketException} in a chain of nested exceptions.
* null, if no {@see SocketException} is in this chain.
*
* @param e the root exception
* @return the first {@see SocketException} in a chain of nested exceptions
*/
protected static SocketException getNestedSocketException(Exception e) {
return getNestedException(e, SocketException.class);
}
/**
* Replies the first {@see UnknownHostException} in a chain of nested exceptions.
* null, if no {@see UnknownHostException} is in this chain.
*
* @param e the root exception
* @return the first {@see UnknownHostException} in a chain of nested exceptions
*/
protected static UnknownHostException getNestedUnknownHostException(Exception e) {
return getNestedException(e, UnknownHostException.class);
}
/**
* Explains an {@see OsmTransferException} to the user.
*
* @param e the {@see OsmTransferException}
*/
public static void explainOsmTransferException(OsmTransferException e) {
if (getNestedSecurityException(e) != null) {
explainSecurityException(e);
return;
}
if (getNestedSocketException(e) != null) {
explainNestedSocketException(e);
return;
}
if (getNestedUnknownHostException(e) != null) {
explainNestedUnkonwnHostException(e);
return;
}
if (e instanceof OsmApiInitializationException){
explainOsmApiInitializationException((OsmApiInitializationException)e);
return;
}
if (e instanceof OsmApiException) {
OsmApiException oae = (OsmApiException)e;
if (oae.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) {
explainPreconditionFailed(oae);
return;
}
if (oae.getResponseCode() == HttpURLConnection.HTTP_GONE) {
explainGoneForUnknownPrimitive(oae);
return;
}
}
explainGeneric(e);
}
/**
* explains the case of an error due to a delete request on an already deleted
* {@see OsmPrimitive}, i.e. a HTTP response code 410, where we don't know which
* {@see OsmPrimitive} is causing the error.
*
* @param e the exception
*/
public static void explainGoneForUnknownPrimitive(OsmApiException e) {
String msg = tr("Uploading failed because a primitive you tried to
"
+ "delete on the server is already deleted.
"
+ "
"
+ "The error message is:
"
+ "{0}"
+ "",
e.getMessage().replace("&", "&").replace("<", "<").replace(">", ">")
);
OptionPaneUtil.showMessageDialog(
Main.parent,
msg,
tr("Primitive already deleted"),
JOptionPane.ERROR_MESSAGE
);
}
/**
* Explains an {@see Exception} to the user.
*
* @param e the {@see Exception}
*/
public static void explainException(Exception e) {
if (e instanceof OsmTransferException) {
explainOsmTransferException((OsmTransferException)e);
return;
}
explainGeneric(e);
}
}