/**
   * * 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;
  }
  /**
   * * Processes the web exception.
   *
   * @param exception WebException
   * @param req HttpWebRequest
   */
  private void processWebException(Exception exception, HttpWebRequest req) {
    SoapFaultDetails soapFaultDetails = null;
    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);
            // soapFaultDetails = this.readSoapFault(reader);
            this.readSoapFault(reader);
            memoryStream.close();
          } else {
            InputStream serviceResponseStream = AutodiscoverRequest.getResponseStream(req);
            EwsXmlReader reader = new EwsXmlReader(serviceResponseStream);
            soapFaultDetails = this.readSoapFault(reader);
            serviceResponseStream.close();

            if (soapFaultDetails != null) {
              throw new ServiceResponseException(new ServiceResponse(soapFaultDetails));
            }
          }
        } else {
          this.service.processHttpErrorResponse(req, exception);
        }
      } catch (Exception e) {
        // do nothing
        e.printStackTrace();
      }
    }
  }
  /**
   * * 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);
        if (redirectionUri.getScheme().toLowerCase().equals("http")
            || redirectionUri.getScheme().toLowerCase().equals("https")) {
          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;
  }
  /**
   * * Executes this instance.
   *
   * @return the autodiscover response
   * @throws ServiceLocalException the service local exception
   * @throws Exception the exception
   */
  protected AutodiscoverResponse internalExecute() throws ServiceLocalException, Exception {
    this.validate();
    HttpWebRequest request = null;
    try {
      request = this.service.prepareHttpWebRequestForUrl(this.url);
      this.service.traceHttpRequestHeaders(TraceFlags.AutodiscoverRequestHttpHeaders, request);

      OutputStream urlOutStream = request.getOutputStream();
      // OutputStreamWriter out = new OutputStreamWriter(request
      // .getOutputStream());

      ByteArrayOutputStream memoryStream = new ByteArrayOutputStream();
      this.writeSoapRequest(this.url, memoryStream);

      if (this.service.isTraceEnabledFor(TraceFlags.AutodiscoverRequest)) {
        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(Strings.InvalidRedirectionResponseReturned);
        }
      }

      /*
       * BufferedReader in = new BufferedReader(new
       * InputStreamReader(request.getInputStream()));
       *
       * String decodedString;
       *
       * while ((decodedString = in.readLine()) != null) {
       * System.out.println(decodedString); } in.close();
       */

      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(Strings.InvalidAutodiscoverServiceResponse);
      }

      this.readSoapHeader(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(Strings.ServiceRequestFailed, 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(Strings.ServiceRequestFailed, ex.getMessage()), ex);
    } catch (Exception ex) {
      // HttpWebRequest httpWebResponse = (HttpWebRequest)ex;

      if (null != request && request.getResponseCode() == 7) {
        if (AutodiscoverRequest.isRedirectionResponse(request)) {
          this.service.traceHttpResponseHeaders(
              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(Strings.ServiceRequestFailed, ex.getMessage()), ex);
    } finally {
      try {
        request.close();
      } catch (Exception e2) {
        request = null;
      }
    }
  }
 /**
  * * Determines whether response is a redirection.
  *
  * @param request the request
  * @return True if redirection response.
  * @throws EWSHttpException the eWS http exception
  */
 protected static boolean isRedirectionResponse(HttpWebRequest request) throws EWSHttpException {
   return ((request.getResponseCode() == 301)
       || (request.getResponseCode() == 302)
       || (request.getResponseCode() == 307)
       || (request.getResponseCode() == 303));
 }