001/* 002 * The MIT License 003 * Copyright (c) 2012 Microsoft Corporation 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining a copy 006 * of this software and associated documentation files (the "Software"), to deal 007 * in the Software without restriction, including without limitation the rights 008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 009 * copies of the Software, and to permit persons to whom the Software is 010 * furnished to do so, subject to the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be included in 013 * all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 021 * THE SOFTWARE. 022 */ 023 024package microsoft.exchange.webservices.data.misc; 025 026import microsoft.exchange.webservices.data.core.EwsUtilities; 027import microsoft.exchange.webservices.data.core.EwsXmlReader; 028import microsoft.exchange.webservices.data.core.XmlAttributeNames; 029import microsoft.exchange.webservices.data.core.XmlElementNames; 030import microsoft.exchange.webservices.data.core.enumeration.misc.error.ServiceError; 031import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace; 032import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlDeserializationException; 033import microsoft.exchange.webservices.data.security.XmlNodeType; 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036 037import java.util.HashMap; 038import java.util.Map; 039 040/** 041 * Represents SoapFault details. 042 */ 043public class SoapFaultDetails { 044 045 private static final Log LOG = LogFactory.getLog(SoapFaultDetails.class); 046 047 /** 048 * The fault code. 049 */ 050 private String faultCode; 051 052 /** 053 * The fault string. 054 */ 055 private String faultString; 056 057 /** 058 * The fault actor. 059 */ 060 private String faultActor; 061 062 /** 063 * The response code. 064 */ 065 private ServiceError responseCode = ServiceError.ErrorInternalServerError; 066 067 /** 068 * The message. 069 */ 070 private String message; 071 072 /** 073 * The error code. 074 */ 075 private ServiceError errorCode = ServiceError.NoError; 076 077 /** 078 * The exception type. 079 */ 080 private String exceptionType; 081 082 /** 083 * The line number. 084 */ 085 private int lineNumber; 086 087 /** 088 * The position within line. 089 */ 090 private int positionWithinLine; 091 092 /** 093 * Dictionary of key/value pairs from the MessageXml node in the fault. 094 * Usually empty but there are a few cases where SOAP faults may include 095 * MessageXml details (e.g. CASOverBudgetException includes BackoffTime 096 * value). 097 */ 098 private Map<String, String> errorDetails = new HashMap<String, String>(); 099 100 /** 101 * Parses the. 102 * 103 * @param reader the reader 104 * @param soapNamespace the soap namespace 105 * @return the soap fault details 106 * @throws Exception the exception 107 */ 108 public static SoapFaultDetails parse(EwsXmlReader reader, XmlNamespace soapNamespace) throws Exception { 109 SoapFaultDetails soapFaultDetails = new SoapFaultDetails(); 110 111 do { 112 reader.read(); 113 if (reader.getNodeType().equals( 114 new XmlNodeType(XmlNodeType.START_ELEMENT))) { 115 String localName = reader.getLocalName(); 116 if (localName.equals(XmlElementNames.SOAPFaultCodeElementName)) { 117 soapFaultDetails.setFaultCode(reader.readElementValue()); 118 } else if (localName 119 .equals(XmlElementNames.SOAPFaultStringElementName)) { 120 soapFaultDetails.setFaultString(reader.readElementValue()); 121 } else if (localName 122 .equals(XmlElementNames.SOAPFaultActorElementName)) { 123 soapFaultDetails.setFaultActor(reader.readElementValue()); 124 } else if (localName 125 .equals(XmlElementNames.SOAPDetailElementName)) { 126 soapFaultDetails.parseDetailNode(reader); 127 } 128 } 129 } while (!reader.isEndElement(soapNamespace, 130 XmlElementNames.SOAPFaultElementName)); 131 132 return soapFaultDetails; 133 } 134 135 /** 136 * Parses the detail node. 137 * 138 * @param reader the reader 139 * @throws Exception the exception 140 */ 141 private void parseDetailNode(EwsXmlReader reader) throws Exception { 142 do { 143 reader.read(); 144 if (reader.getNodeType().equals( 145 new XmlNodeType(XmlNodeType.START_ELEMENT))) { 146 String localName = reader.getLocalName(); 147 if (localName 148 .equals(XmlElementNames.EwsResponseCodeElementName)) { 149 try { 150 this.setResponseCode(reader 151 .readElementValue(ServiceError.class)); 152 } catch (Exception e) { 153 LOG.error(e); 154 155 // ServiceError couldn't be mapped to enum value, treat 156 // as an ISE 157 this 158 .setResponseCode(ServiceError. 159 ErrorInternalServerError); 160 } 161 162 } else if (localName 163 .equals(XmlElementNames.EwsMessageElementName)) { 164 this.setMessage(reader.readElementValue()); 165 } else if (localName.equals(XmlElementNames.EwsLineElementName)) { 166 this.setLineNumber(reader.readElementValue(Integer.class)); 167 } else if (localName 168 .equals(XmlElementNames.EwsPositionElementName)) { 169 this.setPositionWithinLine(reader 170 .readElementValue(Integer.class)); 171 } else if (localName 172 .equals(XmlElementNames.EwsErrorCodeElementName)) { 173 try { 174 this.setErrorCode(reader 175 .readElementValue(ServiceError.class)); 176 } catch (Exception e) { 177 LOG.error(e); 178 179 // ServiceError couldn't be mapped to enum value, treat 180 // as an ISE 181 this 182 .setErrorCode(ServiceError. 183 ErrorInternalServerError); 184 } 185 186 } else if (localName 187 .equals(XmlElementNames.EwsExceptionTypeElementName)) { 188 try { 189 this.setExceptionType(reader.readElementValue()); 190 } catch (Exception e) { 191 LOG.error(e); 192 this.setExceptionType(null); 193 } 194 } else if (localName.equals(XmlElementNames.MessageXml)) { 195 this.parseMessageXml(reader); 196 } 197 } 198 } while (!reader.isEndElement(XmlNamespace.NotSpecified, 199 XmlElementNames.SOAPDetailElementName)); 200 } 201 202 /** 203 * Parses the message xml. 204 * 205 * @param reader the reader 206 * @throws Exception the exception 207 * @throws ServiceXmlDeserializationException the service xml deserialization exception 208 */ 209 private void parseMessageXml(EwsXmlReader reader) throws Exception, ServiceXmlDeserializationException, Exception { 210 // E14:172881: E12 and E14 return the MessageXml element in different 211 // namespaces (types namespace for E12, errors namespace in E14). To 212 // avoid this problem, the parser will match the namespace from the 213 // start and end elements. 214 XmlNamespace elementNS = EwsUtilities.getNamespaceFromUri(reader.getNamespaceUri()); 215 216 if (!reader.isEmptyElement()) { 217 do { 218 reader.read(); 219 220 if (reader.isStartElement() && !reader.isEmptyElement()) { 221 String localName = reader.getLocalName(); 222 if (localName.equals(XmlElementNames.Value)) { 223 this.errorDetails.put(reader 224 .readAttributeValue(XmlAttributeNames.Name), 225 reader.readElementValue()); 226 } 227 } 228 } while (!reader 229 .isEndElement(elementNS, XmlElementNames.MessageXml)); 230 } else { 231 reader.read(); 232 } 233 234 } 235 236 /** 237 * Gets the fault code. 238 * 239 * @return the fault code 240 */ 241 protected String getFaultCode() { 242 return faultCode; 243 } 244 245 /** 246 * Sets the fault code. 247 * 248 * @param faultCode the new fault code 249 */ 250 protected void setFaultCode(String faultCode) { 251 this.faultCode = faultCode; 252 } 253 254 /** 255 * Gets the fault string. 256 * 257 * @return the fault string 258 */ 259 public String getFaultString() { 260 return faultString; 261 } 262 263 /** 264 * Sets the fault string. 265 * 266 * @param faultString the new fault string 267 */ 268 protected void setFaultString(String faultString) { 269 this.faultString = faultString; 270 } 271 272 /** 273 * Gets the fault actor. 274 * 275 * @return the fault actor 276 */ 277 protected String getFaultActor() { 278 return faultActor; 279 } 280 281 /** 282 * Sets the fault actor. 283 * 284 * @param faultActor the new fault actor 285 */ 286 protected void setFaultActor(String faultActor) { 287 this.faultActor = faultActor; 288 } 289 290 /** 291 * Gets the response code. 292 * 293 * @return the response code 294 */ 295 public ServiceError getResponseCode() { 296 return responseCode; 297 } 298 299 /** 300 * Sets the response code. 301 * 302 * @param responseCode the new response code 303 */ 304 protected void setResponseCode(ServiceError responseCode) { 305 this.responseCode = responseCode; 306 } 307 308 /** 309 * Gets the message. 310 * 311 * @return the message 312 */ 313 protected String getMessage() { 314 return message; 315 } 316 317 /** 318 * Sets the message. 319 * 320 * @param message the new message 321 */ 322 protected void setMessage(String message) { 323 this.message = message; 324 } 325 326 /** 327 * Gets the error code. 328 * 329 * @return the error code 330 */ 331 protected ServiceError getErrorCode() { 332 return errorCode; 333 } 334 335 /** 336 * Sets the error code. 337 * 338 * @param errorCode the new error code 339 */ 340 protected void setErrorCode(ServiceError errorCode) { 341 this.errorCode = errorCode; 342 } 343 344 /** 345 * Gets the exception type. 346 * 347 * @return the exception type 348 */ 349 protected String getExceptionType() { 350 return exceptionType; 351 } 352 353 /** 354 * Sets the exception type. 355 * 356 * @param exceptionType the new exception type 357 */ 358 protected void setExceptionType(String exceptionType) { 359 this.exceptionType = exceptionType; 360 } 361 362 /** 363 * Gets the line number. 364 * 365 * @return the line number 366 */ 367 protected int getLineNumber() { 368 return lineNumber; 369 } 370 371 /** 372 * Sets the line number. 373 * 374 * @param lineNumber the new line number 375 */ 376 protected void setLineNumber(int lineNumber) { 377 this.lineNumber = lineNumber; 378 } 379 380 /** 381 * Gets the position within line. 382 * 383 * @return the position within line 384 */ 385 protected int getPositionWithinLine() { 386 return positionWithinLine; 387 } 388 389 /** 390 * Sets the position within line. 391 * 392 * @param positionWithinLine the new position within line 393 */ 394 protected void setPositionWithinLine(int positionWithinLine) { 395 this.positionWithinLine = positionWithinLine; 396 } 397 398 /** 399 * Gets the error details. 400 * 401 * @return the error details 402 */ 403 public Map<String, String> getErrorDetails() { 404 return errorDetails; 405 } 406 407 /** 408 * Sets the error details. 409 * 410 * @param errorDetails the error details 411 */ 412 protected void setErrorDetails(Map<String, String> errorDetails) { 413 this.errorDetails = errorDetails; 414 } 415}