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 String header = Utils.strip(errorHeader); 216 String body = Utils.strip(errorBody); 217 if ((header == null || header.isEmpty()) && (body == null || body.isEmpty())) { 218 sb.append(tr("The server replied an error with code {0}.", responseCode)); 219 } else { 220 if (header != null && !header.isEmpty()) { 221 sb.append(tr(header)); 222 } 223 if (body != null && !body.isEmpty() && !body.equals(header)) { 224 if (sb.length() > 0) { 225 sb.append(". "); 226 } 227 sb.append(tr(body)); 228 } 229 sb.append(' ').append(tr("(Code={0})", responseCode)); 230 } 231 return sb.toString(); 232 } 233 234 /** 235 * Sets the complete URL accessed when this error occurred. 236 * This is distinct from the one set with {@link #setUrl}, which is generally only the base URL of the server. 237 * @param url the complete URL accessed when this error occurred. 238 */ 239 public void setAccessedUrl(String url) { 240 this.accessedUrl = url; 241 } 242 243 /** 244 * Replies the complete URL accessed when this error occurred. 245 * This is distinct from the one returned by {@link #getUrl}, which is generally only the base URL of the server. 246 * @return the complete URL accessed when this error occurred. 247 */ 248 public String getAccessedUrl() { 249 return accessedUrl; 250 } 251 252 /** 253 * Sets the login used to connect to OSM API. 254 * @param login the login used to connect to OSM API 255 * @since 12992 256 */ 257 public void setLogin(String login) { 258 this.login = login; 259 } 260 261 /** 262 * Replies the login used to connect to OSM API. 263 * @return the login used to connect to OSM API, or {@code null} 264 * @since 12992 265 */ 266 public String getLogin() { 267 return login; 268 } 269 270 /** 271 * Sets the response content-type. 272 * @param contentType the response content-type. 273 * @since 13499 274 */ 275 public final void setContentType(String contentType) { 276 this.contentType = contentType; 277 } 278 279 /** 280 * Replies the response content-type. 281 * @return the response content-type 282 * @since 13499 283 */ 284 public final String getContentType() { 285 return contentType; 286 } 287 288 /** 289 * Determines if the exception has {@code text/html} as content type. 290 * @return {@code true} if the exception has {@code text/html} as content type. 291 * @since 14810 292 */ 293 public final boolean isHtml() { 294 return "text/html".equals(contentType); 295 } 296}