microsoft.exchange.webservices.data.autodiscover.request.AutodiscoverRequest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ews-java-api Show documentation
Show all versions of ews-java-api Show documentation
Exchange Web Services (EWS) Java API
/*
* The MIT License
* Copyright (c) 2012 Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package microsoft.exchange.webservices.data.autodiscover.request;
import microsoft.exchange.webservices.data.EWSConstants;
import microsoft.exchange.webservices.data.autodiscover.AutodiscoverService;
import microsoft.exchange.webservices.data.autodiscover.enumeration.AutodiscoverErrorCode;
import microsoft.exchange.webservices.data.autodiscover.exception.AutodiscoverResponseException;
import microsoft.exchange.webservices.data.autodiscover.response.AutodiscoverResponse;
import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
import microsoft.exchange.webservices.data.core.EwsUtilities;
import microsoft.exchange.webservices.data.core.EwsXmlReader;
import microsoft.exchange.webservices.data.core.ExchangeServerInfo;
import microsoft.exchange.webservices.data.core.XmlElementNames;
import microsoft.exchange.webservices.data.core.request.HttpWebRequest;
import microsoft.exchange.webservices.data.core.response.ServiceResponse;
import microsoft.exchange.webservices.data.core.enumeration.misc.TraceFlags;
import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
import microsoft.exchange.webservices.data.core.exception.http.EWSHttpException;
import microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRemoteException;
import microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRequestException;
import microsoft.exchange.webservices.data.core.exception.service.remote.ServiceResponseException;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlDeserializationException;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException;
import microsoft.exchange.webservices.data.misc.SoapFaultDetails;
import microsoft.exchange.webservices.data.security.XmlNodeType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
/**
* Represents the base class for all requested made to the Autodiscover service.
*/
public abstract class AutodiscoverRequest {
private static final Log LOG = LogFactory.getLog(AutodiscoverRequest.class);
/**
* The service.
*/
private AutodiscoverService service;
/**
* The url.
*/
private URI url;
/**
* Initializes a new instance of the AutodiscoverResponse class.
*
* @param service Autodiscover service associated with this request.
* @param url URL of Autodiscover service.
*/
protected AutodiscoverRequest(AutodiscoverService service, URI url) {
this.service = service;
this.url = url;
}
/**
* Determines whether response is a redirection.
*
* @param request the request
* @return True if redirection response.
* @throws EWSHttpException the EWS http exception
*/
public static boolean isRedirectionResponse(HttpWebRequest request)
throws EWSHttpException {
return ((request.getResponseCode() == 301)
|| (request.getResponseCode() == 302)
|| (request.getResponseCode() == 307) || (request
.getResponseCode() == 303));
}
/**
* Validates the request.
*
* @throws Exception the exception
*/
protected void validate() throws Exception {
this.getService().validate();
}
/**
* Executes this instance.
*
* @return the autodiscover response
* @throws Exception the exception
*/
protected AutodiscoverResponse internalExecute() throws Exception {
this.validate();
HttpWebRequest request = null;
try {
request = this.service.prepareHttpWebRequestForUrl(this.url);
this.service.traceHttpRequestHeaders(
TraceFlags.AutodiscoverRequestHttpHeaders, request);
boolean needSignature = this.getService().getCredentials() != null
&& this.getService().getCredentials().isNeedSignature();
boolean needTrace = this.getService().isTraceEnabledFor(
TraceFlags.AutodiscoverRequest);
OutputStream urlOutStream = request.getOutputStream();
// OutputStreamWriter out = new OutputStreamWriter(request
// .getOutputStream());
ByteArrayOutputStream memoryStream = new ByteArrayOutputStream();
EwsServiceXmlWriter writer = new EwsServiceXmlWriter(this
.getService(), memoryStream);
writer.setRequireWSSecurityUtilityNamespace(needSignature);
this.writeSoapRequest(this.url, writer);
if (needSignature) {
this.service.getCredentials().sign(memoryStream);
}
if (needTrace) {
memoryStream.flush();
this.service.traceXml(TraceFlags.AutodiscoverRequest,
memoryStream);
}
memoryStream.writeTo(urlOutStream);
urlOutStream.flush();
urlOutStream.close();
memoryStream.close();
// out.write(memoryStream.toString());
// out.close();
request.executeRequest();
request.getResponseCode();
if (AutodiscoverRequest.isRedirectionResponse(request)) {
AutodiscoverResponse response = this
.createRedirectionResponse(request);
if (response != null) {
return response;
} else {
throw new ServiceRemoteException("The service returned an invalid redirection response.");
}
}
memoryStream = new ByteArrayOutputStream();
InputStream serviceResponseStream = request.getInputStream();
while (true) {
int data = serviceResponseStream.read();
if (-1 == data) {
break;
} else {
memoryStream.write(data);
}
}
memoryStream.flush();
serviceResponseStream.close();
if (this.service.isTraceEnabled()) {
this.service.traceResponse(request, memoryStream);
}
ByteArrayInputStream memoryStreamIn = new ByteArrayInputStream(
memoryStream.toByteArray());
EwsXmlReader ewsXmlReader = new EwsXmlReader(memoryStreamIn);
// WCF may not generate an XML declaration.
ewsXmlReader.read();
if (ewsXmlReader.getNodeType().getNodeType() == XmlNodeType.START_DOCUMENT) {
ewsXmlReader.readStartElement(XmlNamespace.Soap,
XmlElementNames.SOAPEnvelopeElementName);
} else if ((ewsXmlReader.getNodeType().getNodeType() != XmlNodeType.START_ELEMENT)
|| (!ewsXmlReader.getLocalName().equals(
XmlElementNames.SOAPEnvelopeElementName))
|| (!ewsXmlReader.getNamespaceUri().equals(
EwsUtilities.getNamespaceUri(XmlNamespace.Soap)))) {
throw new ServiceXmlDeserializationException("The Autodiscover service response was invalid.");
}
this.readSoapHeaders(ewsXmlReader);
AutodiscoverResponse response = this.readSoapBody(ewsXmlReader);
ewsXmlReader.readEndElement(XmlNamespace.Soap,
XmlElementNames.SOAPEnvelopeElementName);
if (response.getErrorCode() == AutodiscoverErrorCode.NoError) {
return response;
} else {
throw new AutodiscoverResponseException(
response.getErrorCode(), response.getErrorMessage());
}
} catch (XMLStreamException ex) {
this.service.traceMessage(TraceFlags.AutodiscoverConfiguration,
String.format("XML parsing error: %s", ex.getMessage()));
// Wrap exception
throw new ServiceRequestException(String.format("The request failed. %s", ex.getMessage()), ex);
} catch (IOException ex) {
this.service.traceMessage(TraceFlags.AutodiscoverConfiguration,
String.format("I/O error: %s", ex.getMessage()));
// Wrap exception
throw new ServiceRequestException(String.format("The request failed. %s", ex.getMessage()), ex);
} catch (Exception ex) {
// HttpWebRequest httpWebResponse = (HttpWebRequest)ex;
if (null != request && request.getResponseCode() == 7) {
if (AutodiscoverRequest.isRedirectionResponse(request)) {
this.service
.processHttpResponseHeaders(
TraceFlags.AutodiscoverResponseHttpHeaders,
request);
AutodiscoverResponse response = this
.createRedirectionResponse(request);
if (response != null) {
return response;
}
} else {
this.processWebException(ex, request);
}
}
// Wrap exception if the above code block didn't throw
throw new ServiceRequestException(String.format("The request failed. %s", ex.getMessage()), ex);
} finally {
try {
if (request != null) {
request.close();
}
} catch (Exception e) {
// do nothing
}
}
}
/**
* Processes the web exception.
*
* @param exception WebException
* @param req HttpWebRequest
*/
private void processWebException(Exception exception, HttpWebRequest req) {
if (null != req) {
try {
if (500 == req.getResponseCode()) {
if (this.service
.isTraceEnabledFor(
TraceFlags.AutodiscoverRequest)) {
ByteArrayOutputStream memoryStream =
new ByteArrayOutputStream();
InputStream serviceResponseStream = AutodiscoverRequest
.getResponseStream(req);
while (true) {
int data = serviceResponseStream.read();
if (-1 == data) {
break;
} else {
memoryStream.write(data);
}
}
memoryStream.flush();
serviceResponseStream.close();
this.service.traceResponse(req, memoryStream);
ByteArrayInputStream memoryStreamIn =
new ByteArrayInputStream(
memoryStream.toByteArray());
EwsXmlReader reader = new EwsXmlReader(memoryStreamIn);
this.readSoapFault(reader);
memoryStream.close();
} else {
InputStream serviceResponseStream = AutodiscoverRequest
.getResponseStream(req);
EwsXmlReader reader = new EwsXmlReader(
serviceResponseStream);
SoapFaultDetails soapFaultDetails = this.readSoapFault(reader);
serviceResponseStream.close();
if (soapFaultDetails != null) {
throw new ServiceResponseException(
new ServiceResponse(soapFaultDetails));
}
}
} else {
this.service.processHttpErrorResponse(req, exception);
}
} catch (Exception e) {
LOG.error(e);
}
}
}
/**
* Create a redirection response.
*
* @param httpWebResponse the HTTP web response
* @return AutodiscoverResponse autodiscoverResponse object
* @throws XMLStreamException the XML stream exception
* @throws IOException signals that an I/O exception has occurred
* @throws EWSHttpException the EWS http exception
*/
private AutodiscoverResponse createRedirectionResponse(
HttpWebRequest httpWebResponse) throws XMLStreamException,
IOException, EWSHttpException {
String location = httpWebResponse.getResponseHeaderField("Location");
if (!(location == null || location.isEmpty())) {
try {
URI redirectionUri = new URI(location);
String scheme = redirectionUri.getScheme();
if (scheme.equalsIgnoreCase(EWSConstants.HTTP_SCHEME)
|| scheme.equalsIgnoreCase(EWSConstants.HTTPS_SCHEME)) {
AutodiscoverResponse response = this.createServiceResponse();
response.setErrorCode(AutodiscoverErrorCode.RedirectUrl);
response.setRedirectionUrl(redirectionUri);
return response;
}
this.service
.traceMessage(
TraceFlags.AutodiscoverConfiguration,
String
.format(
"Invalid redirection" +
" URL '%s' " +
"returned by Autodiscover " +
"service.",
redirectionUri.toString()));
} catch (URISyntaxException ex) {
this.service
.traceMessage(
TraceFlags.AutodiscoverConfiguration,
String
.format(
"Invalid redirection " +
"location '%s' " +
"returned by Autodiscover " +
"service.",
location));
}
} else {
this.service
.traceMessage(
TraceFlags.AutodiscoverConfiguration,
"Redirection response returned by Autodiscover " +
"service without redirection location.");
}
return null;
}
/**
* Reads the SOAP fault.
*
* @param reader The reader.
* @return SOAP fault details.
*/
private SoapFaultDetails readSoapFault(EwsXmlReader reader) {
SoapFaultDetails soapFaultDetails = null;
try {
reader.read();
if (reader.getNodeType().getNodeType() == XmlNodeType.START_DOCUMENT) {
reader.read();
}
if (!reader.isStartElement()
|| (!reader.getLocalName().equals(
XmlElementNames.SOAPEnvelopeElementName))) {
return null;
}
// Get the namespace URI from the envelope element and use it for
// the rest of the parsing.
// If it's not 1.1 or 1.2, we can't continue.
XmlNamespace soapNamespace = EwsUtilities
.getNamespaceFromUri(reader.getNamespaceUri());
if (soapNamespace == XmlNamespace.NotSpecified) {
return null;
}
reader.read();
// Skip SOAP header.
if (reader.isStartElement(soapNamespace,
XmlElementNames.SOAPHeaderElementName)) {
do {
reader.read();
} while (!reader.isEndElement(soapNamespace,
XmlElementNames.SOAPHeaderElementName));
// Queue up the next read
reader.read();
}
// Parse the fault element contained within the SOAP body.
if (reader.isStartElement(soapNamespace,
XmlElementNames.SOAPBodyElementName)) {
do {
reader.read();
// Parse Fault element
if (reader.isStartElement(soapNamespace,
XmlElementNames.SOAPFaultElementName)) {
soapFaultDetails = SoapFaultDetails.parse(reader,
soapNamespace);
}
} while (!reader.isEndElement(soapNamespace,
XmlElementNames.SOAPBodyElementName));
}
reader.readEndElement(soapNamespace,
XmlElementNames.SOAPEnvelopeElementName);
} catch (Exception e) {
// If response doesn't contain a valid SOAP fault, just ignore
// exception and
// return null for SOAP fault details.
LOG.error(e);
}
return soapFaultDetails;
}
/**
* Writes the autodiscover SOAP request.
*
* @param requestUrl request URL
* @param writer writer object
* @throws XMLStreamException the XML stream exception
* @throws ServiceXmlSerializationException the service xml serialization exception
*/
protected void writeSoapRequest(URI requestUrl,
EwsServiceXmlWriter writer) throws XMLStreamException, ServiceXmlSerializationException {
if (writer.isRequireWSSecurityUtilityNamespace()) {
writer.writeAttributeValue("xmlns",
EwsUtilities.WSSecurityUtilityNamespacePrefix,
EwsUtilities.WSSecurityUtilityNamespace);
}
writer.writeStartDocument();
writer.writeStartElement(XmlNamespace.Soap,
XmlElementNames.SOAPEnvelopeElementName);
writer.writeAttributeValue("xmlns", EwsUtilities
.getNamespacePrefix(XmlNamespace.Soap), EwsUtilities
.getNamespaceUri(XmlNamespace.Soap));
writer.writeAttributeValue("xmlns",
EwsUtilities.AutodiscoverSoapNamespacePrefix,
EwsUtilities.AutodiscoverSoapNamespace);
writer.writeAttributeValue("xmlns",
EwsUtilities.WSAddressingNamespacePrefix,
EwsUtilities.WSAddressingNamespace);
writer.writeAttributeValue("xmlns",
EwsUtilities.EwsXmlSchemaInstanceNamespacePrefix,
EwsUtilities.EwsXmlSchemaInstanceNamespace);
writer.writeStartElement(XmlNamespace.Soap,
XmlElementNames.SOAPHeaderElementName);
if (this.service.getCredentials() != null) {
this.service.getCredentials().emitExtraSoapHeaderNamespaceAliases(
writer.getInternalWriter());
}
writer.writeElementValue(XmlNamespace.Autodiscover,
XmlElementNames.RequestedServerVersion, this.service
.getRequestedServerVersion().toString());
writer.writeElementValue(XmlNamespace.WSAddressing,
XmlElementNames.Action, this.getWsAddressingActionName());
writer.writeElementValue(XmlNamespace.WSAddressing, XmlElementNames.To,
requestUrl.toString());
this.writeExtraCustomSoapHeadersToXml(writer);
if (this.service.getCredentials() != null) {
this.service.getCredentials().serializeWSSecurityHeaders(
writer.getInternalWriter());
}
this.service.doOnSerializeCustomSoapHeaders(writer.getInternalWriter());
writer.writeEndElement(); // soap:Header
writer.writeStartElement(XmlNamespace.Soap,
XmlElementNames.SOAPBodyElementName);
this.writeBodyToXml(writer);
writer.writeEndElement(); // soap:Body
writer.writeEndElement(); // soap:Envelope
writer.flush();
writer.dispose();
}
/**
* Write extra headers.
*
* @param writer the writer
* @throws ServiceXmlSerializationException the service xml serialization exception
* @throws XMLStreamException the XML stream exception
*/
protected void writeExtraCustomSoapHeadersToXml(EwsServiceXmlWriter writer)
throws XMLStreamException, ServiceXmlSerializationException {
// do nothing here.
// currently used only by GetUserSettingRequest to emit the BinarySecret header.
}
/**
* Writes XML body.
*
* @param writer the writer
* @throws ServiceXmlSerializationException the service xml serialization exception
* @throws XMLStreamException the XML stream exception
*/
protected void writeBodyToXml(EwsServiceXmlWriter writer)
throws ServiceXmlSerializationException, XMLStreamException {
writer.writeStartElement(XmlNamespace.Autodiscover, this
.getRequestXmlElementName());
this.writeAttributesToXml(writer);
this.writeElementsToXml(writer);
writer.writeEndElement(); // m:this.GetXmlElementName()
}
/**
* Gets the response stream (may be wrapped with GZip/Deflate stream to
* decompress content).
*
* @param request the request
* @return ResponseStream
* @throws EWSHttpException the EWS http exception
* @throws IOException signals that an I/O exception has occurred.
*/
protected static InputStream getResponseStream(HttpWebRequest request)
throws EWSHttpException, IOException {
String contentEncoding = "";
if (null != request.getContentEncoding()) {
contentEncoding = request.getContentEncoding().toLowerCase();
}
InputStream responseStream;
if (contentEncoding.contains("gzip")) {
responseStream = new GZIPInputStream(request.getInputStream());
} else if (contentEncoding.contains("deflate")) {
responseStream = new InflaterInputStream(request.getInputStream());
} else {
responseStream = request.getInputStream();
}
return responseStream;
}
/**
* Read SOAP header.
*
* @param reader EwsXmlReader.
* @throws Exception the exception
*/
protected void readSoapHeaders(EwsXmlReader reader) throws Exception {
reader.readStartElement(XmlNamespace.Soap,
XmlElementNames.SOAPHeaderElementName);
do {
reader.read();
this.readSoapHeader(reader);
} while (!reader.isEndElement(XmlNamespace.Soap,
XmlElementNames.SOAPHeaderElementName));
}
/**
* Reads a single SOAP header.
*
* @param reader EwsXmlReader
* @throws Exception on error
*/
protected void readSoapHeader(EwsXmlReader reader) throws Exception {
// Is this the ServerVersionInfo?
if (reader.isStartElement(XmlNamespace.Autodiscover,
XmlElementNames.ServerVersionInfo)) {
this.service.setServerInfo(this.readServerVersionInfo(reader));
}
}
/**
* Read ServerVersionInfo SOAP header.
*
* @param reader EwsXmlReader.
* @return ExchangeServerInfo ExchangeServerInfo object
* @throws Exception the exception
*/
private ExchangeServerInfo readServerVersionInfo(EwsXmlReader reader)
throws Exception {
ExchangeServerInfo serverInfo = new ExchangeServerInfo();
do {
reader.read();
if (reader.isStartElement()) {
if (reader.getLocalName().equals(XmlElementNames.MajorVersion)) {
serverInfo.setMajorVersion(reader
.readElementValue(Integer.class));
} else if (reader.getLocalName().equals(
XmlElementNames.MinorVersion)) {
serverInfo.setMinorVersion(reader
.readElementValue(Integer.class));
} else if (reader.getLocalName().equals(
XmlElementNames.MajorBuildNumber)) {
serverInfo.setMajorBuildNumber(reader
.readElementValue(Integer.class));
} else if (reader.getLocalName().equals(
XmlElementNames.MinorBuildNumber)) {
serverInfo.setMinorBuildNumber(reader
.readElementValue(Integer.class));
} else if (reader.getLocalName()
.equals(XmlElementNames.Version)) {
serverInfo.setVersionString(reader.readElementValue());
}
}
} while (!reader.isEndElement(XmlNamespace.Autodiscover,
XmlElementNames.ServerVersionInfo));
return serverInfo;
}
/**
* Read SOAP body.
*
* @param reader EwsXmlReader.
* @return AutodiscoverResponse AutodiscoverResponse object
* @throws Exception the exception
*/
protected AutodiscoverResponse readSoapBody(EwsXmlReader reader) throws Exception {
reader.readStartElement(XmlNamespace.Soap,
XmlElementNames.SOAPBodyElementName);
AutodiscoverResponse responses = this.loadFromXml(reader);
reader.readEndElement(XmlNamespace.Soap,
XmlElementNames.SOAPBodyElementName);
return responses;
}
/**
* Loads response from XML.
*
* @param reader The reader.
* @return AutodiscoverResponse object
* @throws Exception the exception
*/
protected AutodiscoverResponse loadFromXml(EwsXmlReader reader) throws Exception {
String elementName = this.getResponseXmlElementName();
reader.readStartElement(XmlNamespace.Autodiscover, elementName);
AutodiscoverResponse response = this.createServiceResponse();
response.loadFromXml(reader, elementName);
return response;
}
/**
* Gets the name of the request XML element.
*
* @return RequestXmlElementName gets XmlElementName.
*/
protected abstract String getRequestXmlElementName();
/**
* Gets the name of the response XML element.
*
* @return ResponseXmlElementName gets XmlElementName.
*/
protected abstract String getResponseXmlElementName();
/**
* Gets the WS-Addressing action name.
*
* @return WsAddressingActionName gets WsAddressingActionName.
*/
protected abstract String getWsAddressingActionName();
/**
* Creates the service response.
*
* @return AutodiscoverResponse AutodiscoverResponse object.
*/
protected abstract AutodiscoverResponse createServiceResponse();
/**
* Writes attribute to request XML.
*
* @param writer The writer.
* @throws ServiceXmlSerializationException the service xml serialization exception
*/
protected abstract void writeAttributesToXml(EwsServiceXmlWriter writer)
throws ServiceXmlSerializationException;
/**
* Writes elements to request XML.
*
* @param writer the writer
* @throws XMLStreamException the XML stream exception
* @throws ServiceXmlSerializationException the service xml serialization exception
*/
protected abstract void writeElementsToXml(EwsServiceXmlWriter writer)
throws XMLStreamException, ServiceXmlSerializationException;
/**
* Gets the Service.
*
* @return AutodiscoverService AutodiscoverService object.
*/
protected AutodiscoverService getService() {
return this.service;
}
/**
* Gets the URL.
*
* @return url URL Object.
*/
protected URI getUrl() {
return this.url;
}
}