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
024 package microsoft.exchange.webservices.data.misc;
025
026 import microsoft.exchange.webservices.data.core.EwsUtilities;
027 import microsoft.exchange.webservices.data.core.EwsXmlReader;
028 import microsoft.exchange.webservices.data.core.XmlAttributeNames;
029 import microsoft.exchange.webservices.data.core.XmlElementNames;
030 import microsoft.exchange.webservices.data.core.enumeration.misc.error.ServiceError;
031 import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
032 import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlDeserializationException;
033 import microsoft.exchange.webservices.data.security.XmlNodeType;
034 import org.apache.commons.logging.Log;
035 import org.apache.commons.logging.LogFactory;
036
037 import java.util.HashMap;
038 import java.util.Map;
039
040 /**
041 * Represents SoapFault details.
042 */
043 public 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 }