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.core.request; 025 026import microsoft.exchange.webservices.data.core.EwsServiceXmlReader; 027import microsoft.exchange.webservices.data.core.EwsUtilities; 028import microsoft.exchange.webservices.data.core.ExchangeService; 029import microsoft.exchange.webservices.data.core.XmlElementNames; 030import microsoft.exchange.webservices.data.core.enumeration.service.error.ServiceErrorHandling; 031import microsoft.exchange.webservices.data.core.response.ServiceResponse; 032import microsoft.exchange.webservices.data.core.response.ServiceResponseCollection; 033import microsoft.exchange.webservices.data.core.enumeration.service.ServiceResult; 034import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace; 035import microsoft.exchange.webservices.data.core.exception.service.remote.ServiceResponseException; 036import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlDeserializationException; 037import microsoft.exchange.webservices.data.misc.IAsyncResult; 038 039/** 040 * Represents a service request that can have multiple response. 041 * 042 * @param <TResponse> The type of the response. 043 */ 044public abstract class MultiResponseServiceRequest<TResponse extends ServiceResponse> 045 extends SimpleServiceRequestBase<ServiceResponseCollection<TResponse>> { 046 047 /** 048 * The error handling mode. 049 */ 050 private ServiceErrorHandling errorHandlingMode; 051 052 /** 053 * {@inheritDoc} 054 */ 055 @Override 056 protected ServiceResponseCollection<TResponse> parseResponse(EwsServiceXmlReader reader) 057 throws Exception { 058 ServiceResponseCollection<TResponse> serviceResponses = 059 new ServiceResponseCollection<TResponse>(); 060 061 reader.readStartElement(XmlNamespace.Messages, 062 XmlElementNames.ResponseMessages); 063 064 for (int i = 0; i < this.getExpectedResponseMessageCount(); i++) { 065 // Read ahead to see if we've reached the end of the response 066 // messages early. 067 reader.read(); 068 if (reader.isEndElement(XmlNamespace.Messages, 069 XmlElementNames.ResponseMessages)) { 070 break; 071 } 072 073 TResponse response = this.createServiceResponse( 074 reader.getService(), i); 075 076 response.loadFromXml(reader, this 077 .getResponseMessageXmlElementName()); 078 079 // Add the response to the list after it has been deserialized 080 // because the response list updates an overall result as individual 081 // response are added 082 // to it. 083 serviceResponses.add(response); 084 } 085 // Bug E14:131334 -- if there's a general error in batch processing, 086 // the server will return a single response message containing the error 087 // (for example, if the SavedItemFolderId is bogus in a batch CreateItem 088 // call). In this case, throw a ServiceResponsException. Otherwise this 089 // is an unexpected server error. 090 if (serviceResponses.getCount() < this 091 .getExpectedResponseMessageCount()) { 092 if ((serviceResponses.getCount() == 1) && 093 (serviceResponses.getResponseAtIndex(0).getResult() == 094 ServiceResult.Error)) { 095 throw new ServiceResponseException(serviceResponses 096 .getResponseAtIndex(0)); 097 } else { 098 throw new ServiceXmlDeserializationException(String.format( 099 "The service was expected to return %s response of type '%d', but %d response were received.", this 100 .getResponseMessageXmlElementName(), this 101 .getExpectedResponseMessageCount(), 102 serviceResponses.getCount())); 103 } 104 } 105 106 reader.readEndElementIfNecessary(XmlNamespace.Messages, 107 XmlElementNames.ResponseMessages); 108 109 return serviceResponses; 110 } 111 112 /** 113 * Creates the service response. 114 * 115 * @param service The service. 116 * @param responseIndex Index of the response. 117 * @return Service response. 118 * @throws Exception the exception 119 */ 120 protected abstract TResponse createServiceResponse(ExchangeService service, 121 int responseIndex) throws Exception; 122 123 /** 124 * Gets the name of the response message XML element. 125 * 126 * @return XML element name 127 */ 128 protected abstract String getResponseMessageXmlElementName(); 129 130 /** 131 * Gets the expected response message count. 132 * 133 * @return Number of expected response messages. 134 */ 135 protected abstract int getExpectedResponseMessageCount(); 136 137 /** 138 * Initializes a new instance. 139 * 140 * @param service The service. 141 * @param errorHandlingMode Indicates how errors should be handled. 142 * @throws Exception 143 */ 144 protected MultiResponseServiceRequest(ExchangeService service, 145 ServiceErrorHandling errorHandlingMode) 146 throws Exception { 147 super(service); 148 this.errorHandlingMode = errorHandlingMode; 149 } 150 151 /** 152 * Executes this request. 153 * 154 * @return Service response collection. 155 * @throws Exception the exception 156 */ 157 public ServiceResponseCollection<TResponse> execute() throws Exception { 158 ServiceResponseCollection<TResponse> serviceResponses = internalExecute(); 159 160 if (this.errorHandlingMode == ServiceErrorHandling.ThrowOnError) { 161 EwsUtilities.ewsAssert(serviceResponses.getCount() == 1, "MultiResponseServiceRequest.Execute", 162 "ServiceErrorHandling.ThrowOnError " + "error handling " + 163 "is only valid for singleton request"); 164 165 serviceResponses.getResponseAtIndex(0).throwIfNecessary(); 166 } 167 168 return serviceResponses; 169 } 170 171 /** 172 * Ends executing this async request. 173 * 174 * @param asyncResult The async result 175 * @return Service response collection. 176 * @throws Exception on error 177 */ 178 public ServiceResponseCollection<TResponse> endExecute(IAsyncResult asyncResult) throws Exception { 179 ServiceResponseCollection<TResponse> serviceResponses = endInternalExecute(asyncResult); 180 181 if (this.errorHandlingMode == ServiceErrorHandling.ThrowOnError) { 182 EwsUtilities.ewsAssert(serviceResponses.getCount() == 1, "MultiResponseServiceRequest.Execute", 183 "ServiceErrorHandling.ThrowOnError error handling is only valid for singleton request"); 184 185 serviceResponses.getResponseAtIndex(0).throwIfNecessary(); 186 } 187 188 return serviceResponses; 189 } 190 191 /** 192 * Gets a value indicating how errors should be handled. 193 * 194 * @return A value indicating how errors should be handled. 195 */ 196 protected ServiceErrorHandling getErrorHandlingMode() { 197 return this.errorHandlingMode; 198 } 199 200}