001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003import static org.openstreetmap.josm.tools.I18n.tr; 004 005import org.openstreetmap.josm.tools.Logging; 006import org.openstreetmap.josm.tools.Utils; 007 008/** 009 * Exception thrown when a communication error occurs when accessing the <a href="http://wiki.openstreetmap.org/wiki/API_v0.6">OSM API</a>. 010 * @see OsmApi 011 */ 012public class OsmApiException extends OsmTransferException { 013 014 private int responseCode; 015 private String contentType; 016 private String errorHeader; 017 private String errorBody; 018 private String accessedUrl; 019 private String login; 020 021 /** 022 * Constructs an {@code OsmApiException} with the specified response code, error header and error body 023 * @param responseCode The HTTP response code replied by the OSM server. 024 * See {@link java.net.HttpURLConnection HttpURLConnection} for predefined HTTP response code values 025 * @param errorHeader The error header, as transmitted in the {@code Error} field of the HTTP response header 026 * @param errorBody The error body, as transmitted in the HTTP response body 027 * @param accessedUrl The complete URL accessed when this error occurred 028 * @param login the login used to connect to OSM API (can be null) 029 * @param contentType the response content-type 030 * @since 13499 031 */ 032 public OsmApiException(int responseCode, String errorHeader, String errorBody, String accessedUrl, String login, String contentType) { 033 this.responseCode = responseCode; 034 this.errorHeader = errorHeader; 035 this.errorBody = Utils.strip(errorBody); 036 this.accessedUrl = accessedUrl; 037 this.login = login; 038 this.contentType = contentType; 039 checkHtmlBody(); 040 } 041 042 /** 043 * Constructs an {@code OsmApiException} with the specified response code, error header and error body 044 * @param responseCode The HTTP response code replied by the OSM server. 045 * See {@link java.net.HttpURLConnection HttpURLConnection} for predefined HTTP response code values 046 * @param errorHeader The error header, as transmitted in the {@code Error} field of the HTTP response header 047 * @param errorBody The error body, as transmitted in the HTTP response body 048 * @param accessedUrl The complete URL accessed when this error occurred 049 * @param login the login used to connect to OSM API (can be null) 050 * @since 12992 051 */ 052 public OsmApiException(int responseCode, String errorHeader, String errorBody, String accessedUrl, String login) { 053 this(responseCode, errorHeader, errorBody, accessedUrl, login, null); 054 } 055 056 /** 057 * Constructs an {@code OsmApiException} with the specified response code, error header and error body 058 * @param responseCode The HTTP response code replied by the OSM server. 059 * See {@link java.net.HttpURLConnection HttpURLConnection} for predefined HTTP response code values 060 * @param errorHeader The error header, as transmitted in the {@code Error} field of the HTTP response header 061 * @param errorBody The error body, as transmitted in the HTTP response body 062 * @param accessedUrl The complete URL accessed when this error occurred 063 * @since 5584 064 */ 065 public OsmApiException(int responseCode, String errorHeader, String errorBody, String accessedUrl) { 066 this(responseCode, errorHeader, errorBody, accessedUrl, null); 067 } 068 069 /** 070 * Constructs an {@code OsmApiException} with the specified response code, error header and error body 071 * @param responseCode The HTTP response code replied by the OSM server. 072 * See {@link java.net.HttpURLConnection HttpURLConnection} for predefined HTTP response code values 073 * @param errorHeader The error header, as transmitted in the {@code Error} field of the HTTP response header 074 * @param errorBody The error body, as transmitted in the HTTP response body 075 */ 076 public OsmApiException(int responseCode, String errorHeader, String errorBody) { 077 this(responseCode, errorHeader, errorBody, null); 078 } 079 080 /** 081 * Constructs an {@code OsmApiException} with the specified detail message. 082 * The cause is not initialized, and may subsequently be initialized by a call to {@link #initCause}. 083 * 084 * @param message The detail message (which is saved for later retrieval by the {@link #getMessage} method) 085 */ 086 public OsmApiException(String message) { 087 super(message); 088 } 089 090 /** 091 * Constructs an {@code OsmApiException} with the specified cause and a detail message of 092 * <code>(cause==null ? null : cause.toString())</code> 093 * (which typically contains the class and detail message of <code>cause</code>). 094 * 095 * @param cause the cause (which is saved for later retrieval by the {@link #getCause} method). 096 * A <code>null</code> value is permitted, and indicates that the cause is nonexistent or unknown. 097 */ 098 public OsmApiException(Throwable cause) { 099 super(cause); 100 } 101 102 /** 103 * Constructs an {@code OsmApiException} with the specified detail message and cause. 104 * 105 * <p> Note that the detail message associated with {@code cause} is <i>not</i> automatically incorporated 106 * into this exception's detail message. 107 * 108 * @param message The detail message (which is saved for later retrieval by the {@link #getMessage} method) 109 * @param cause The cause (which is saved for later retrieval by the {@link #getCause} method). 110 * A null value is permitted, and indicates that the cause is nonexistent or unknown. 111 * 112 */ 113 public OsmApiException(String message, Throwable cause) { 114 super(message, cause); 115 } 116 117 private void checkHtmlBody() { 118 if (errorBody != null && errorBody.matches("^<.*>.*<.*>$")) { 119 setContentType("text/html"); 120 if (!errorBody.contains("<html>")) { 121 errorBody = "<html>" + errorBody + "</html>"; 122 } 123 } 124 } 125 126 /** 127 * Replies the HTTP response code. 128 * @return The HTTP response code replied by the OSM server. Refer to 129 * <a href="http://wiki.openstreetmap.org/wiki/API_v0.6">OSM API</a> to see the list of response codes returned by the API for each call. 130 */ 131 public int getResponseCode() { 132 return responseCode; 133 } 134 135 /** 136 * Sets the HTTP response code. 137 * @param responseCode The HTTP response code replied by the OSM server. 138 * See {@link java.net.HttpURLConnection HttpURLConnection} for predefined HTTP response code values 139 */ 140 public void setResponseCode(int responseCode) { 141 this.responseCode = responseCode; 142 } 143 144 /** 145 * Replies the error header. 146 * @return the error header, as transmitted in the {@code Error} field of the HTTP response header 147 */ 148 public String getErrorHeader() { 149 return errorHeader; 150 } 151 152 /** 153 * Sets the error header. 154 * @param errorHeader the error header, as transmitted in the {@code Error} field of the HTTP response header 155 */ 156 public void setErrorHeader(String errorHeader) { 157 this.errorHeader = errorHeader; 158 } 159 160 /** 161 * Replies the error body. 162 * @return The error body, as transmitted in the HTTP response body 163 */ 164 public String getErrorBody() { 165 return errorBody; 166 } 167 168 /** 169 * Sets the error body. 170 * @param errorBody The error body, as transmitted in the HTTP response body 171 */ 172 public void setErrorBody(String errorBody) { 173 this.errorBody = errorBody; 174 } 175 176 @Override 177 public String getMessage() { 178 StringBuilder sb = new StringBuilder(); 179 sb.append("ResponseCode=") 180 .append(responseCode); 181 String eh = ""; 182 try { 183 if (errorHeader != null) 184 eh = tr(errorHeader.trim()); 185 if (!eh.isEmpty()) { 186 sb.append(", Error Header=<") 187 .append(eh) 188 .append('>'); 189 } 190 } catch (IllegalArgumentException e) { 191 // Ignored 192 Logging.trace(e); 193 } 194 try { 195 String eb = errorBody != null ? tr(errorBody.trim()) : ""; 196 if (!eb.isEmpty() && !eb.equals(eh)) { 197 sb.append(", Error Body=<") 198 .append(eb) 199 .append('>'); 200 } 201 } catch (IllegalArgumentException e) { 202 // Ignored 203 Logging.trace(e); 204 } 205 return sb.toString(); 206 } 207 208 /** 209 * Replies a message suitable to be displayed in a message dialog 210 * 211 * @return a message which is suitable to be displayed in a message dialog 212 */ 213 public String getDisplayMessage() { 214 StringBuilder sb = new StringBuilder(); 215 if (errorHeader != null) { 216 sb.append(tr(errorHeader)); 217 sb.append(tr("(Code={0})", responseCode)); 218 } else if (errorBody != null && !errorBody.trim().isEmpty()) { 219 errorBody = errorBody.trim(); 220 sb.append(tr(errorBody)); 221 sb.append(tr("(Code={0})", responseCode)); 222 } else { 223 sb.append(tr("The server replied an error with code {0}.", responseCode)); 224 } 225 return sb.toString(); 226 } 227 228 /** 229 * Sets the complete URL accessed when this error occurred. 230 * This is distinct from the one set with {@link #setUrl}, which is generally only the base URL of the server. 231 * @param url the complete URL accessed when this error occurred. 232 */ 233 public void setAccessedUrl(String url) { 234 this.accessedUrl = url; 235 } 236 237 /** 238 * Replies the complete URL accessed when this error occurred. 239 * This is distinct from the one returned by {@link #getUrl}, which is generally only the base URL of the server. 240 * @return the complete URL accessed when this error occurred. 241 */ 242 public String getAccessedUrl() { 243 return accessedUrl; 244 } 245 246 /** 247 * Sets the login used to connect to OSM API. 248 * @param login the login used to connect to OSM API 249 * @since 12992 250 */ 251 public void setLogin(String login) { 252 this.login = login; 253 } 254 255 /** 256 * Replies the login used to connect to OSM API. 257 * @return the login used to connect to OSM API, or {@code null} 258 * @since 12992 259 */ 260 public String getLogin() { 261 return login; 262 } 263 264 /** 265 * Sets the response content-type. 266 * @param contentType the response content-type. 267 * @since 13499 268 */ 269 public final void setContentType(String contentType) { 270 this.contentType = contentType; 271 } 272 273 /** 274 * Replies the response content-type. 275 * @return the response content-type 276 * @since 13499 277 */ 278 public final String getContentType() { 279 return contentType; 280 } 281 282 /** 283 * Determines if the exception has {@code text/html} as content type. 284 * @return {@code true} if the exception has {@code text/html} as content type. 285 * @since xxx 286 */ 287 public final boolean isHtml() { 288 return "text/html".equals(contentType); 289 } 290}