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; 025 026import microsoft.exchange.webservices.data.*; 027import microsoft.exchange.webservices.data.core.enumeration.misc.*; 028import microsoft.exchange.webservices.data.core.exception.http.*; 029import microsoft.exchange.webservices.data.core.exception.service.local.*; 030import microsoft.exchange.webservices.data.core.exception.service.remote.*; 031import microsoft.exchange.webservices.data.core.request.*; 032import microsoft.exchange.webservices.data.credential.*; 033import microsoft.exchange.webservices.data.misc.*; 034import org.apache.commons.io.*; 035import org.apache.commons.logging.*; 036import org.apache.http.client.CookieStore; 037import org.apache.http.client.*; 038import org.apache.http.client.protocol.*; 039import org.apache.http.config.*; 040import org.apache.http.conn.*; 041import org.apache.http.conn.socket.*; 042import org.apache.http.impl.client.*; 043import org.apache.http.impl.conn.*; 044 045import javax.xml.stream.*; 046import java.io.*; 047import java.net.*; 048import java.security.*; 049import java.text.*; 050import java.util.*; 051 052/** 053 * Represents an abstract binding to an Exchange Service. 054 */ 055public abstract class ExchangeServiceBase implements Closeable { 056 057 private static final Log LOG = LogFactory.getLog(ExchangeService.class); 058 059 /** 060 * The credential. 061 */ 062 private ExchangeCredentials credentials; 063 064 /** 065 * The use default credential. 066 */ 067 private boolean useDefaultCredentials; 068 069 /** 070 * The binary secret. 071 */ 072 private static byte[] binarySecret; 073 074 /** 075 * The timeout. 076 */ 077 private int timeout = 100000; 078 079 /** 080 * The trace enabled. 081 */ 082 private boolean traceEnabled; 083 084 /** 085 * The trace flags. 086 */ 087 private EnumSet<TraceFlags> traceFlags = EnumSet.allOf(TraceFlags.class); 088 089 /** 090 * The trace listener. 091 */ 092 private ITraceListener traceListener = new EwsTraceListener(); 093 094 /** 095 * The pre authenticate. 096 */ 097 private boolean preAuthenticate; 098 099 /** 100 * The user agent. 101 */ 102 private String userAgent = ExchangeServiceBase.defaultUserAgent; 103 104 /** 105 * The accept gzip encoding. 106 */ 107 private boolean acceptGzipEncoding = true; 108 109 /** 110 * The requested server version. 111 */ 112 private ExchangeVersion requestedServerVersion = ExchangeVersion.Exchange2010_SP2; 113 114 /** 115 * The server info. 116 */ 117 private ExchangeServerInfo serverInfo; 118 119 private Map<String, String> httpHeaders = new HashMap<String, String>(); 120 121 private Map<String, String> httpResponseHeaders = new HashMap<String, String>(); 122 123 private WebProxy webProxy; 124 125 protected CloseableHttpClient httpClient; 126 127 protected boolean externalHttpClient = false; 128 129 protected HttpClientContext httpContext; 130 131 protected CloseableHttpClient httpPoolingClient; 132 133 protected boolean externalHttpPoolingClient = false; 134 135 private int maximumPoolingConnections = 10; 136 137 private boolean useGlobalCookieStore = false; 138 139// protected HttpClientWebRequest request = null; 140 141 // protected static HttpStatusCode AccountIsLocked = (HttpStatusCode)456; 142 143 /** 144 * Default UserAgent. 145 */ 146 private static String defaultUserAgent = "ExchangeServicesClient/" + EwsUtilities.getBuildVersion(); 147 148 private ServiceRequestTraceListener serviceRequestTraceListener; 149 150 /** 151 * Initializes a new instance. 152 * 153 * This constructor performs the initialization of the HTTP connection manager, so it should be called by 154 * every other constructor. 155 */ 156 protected ExchangeServiceBase() { 157 this((CloseableHttpClient) null, null); 158 } 159 160 protected ExchangeServiceBase(CloseableHttpClient httpClient, CloseableHttpClient httpPoolingClient) { 161 setUseDefaultCredentials(true); 162 if (httpClient != null) { 163 externalHttpClient = true; 164 this.httpClient = httpClient; 165 } else { 166 initializeHttpClient(); 167 } 168 if (httpPoolingClient != null) { 169 externalHttpPoolingClient = true; 170 this.httpPoolingClient = httpPoolingClient; 171 } 172 } 173 174 protected ExchangeServiceBase(ExchangeVersion requestedServerVersion) { 175 this(); 176 this.requestedServerVersion = requestedServerVersion; 177 } 178 179 protected ExchangeServiceBase(ExchangeVersion requestedServerVersion, CloseableHttpClient httpClient, 180 CloseableHttpClient httpPoolingClient) { 181 this(httpClient, httpPoolingClient); 182 this.requestedServerVersion = requestedServerVersion; 183 } 184 185 protected ExchangeServiceBase(ExchangeServiceBase service, ExchangeVersion requestedServerVersion) { 186 this(requestedServerVersion, service.httpClient, service.httpPoolingClient); 187 this.externalHttpClient = service.externalHttpClient; 188 this.externalHttpPoolingClient = service.externalHttpPoolingClient; 189 this.useDefaultCredentials = service.getUseDefaultCredentials(); 190 this.credentials = service.getCredentials(); 191 this.traceEnabled = service.isTraceEnabled(); 192 this.traceListener = service.getTraceListener(); 193 this.traceFlags = service.getTraceFlags(); 194 this.timeout = service.getTimeout(); 195 this.preAuthenticate = service.isPreAuthenticate(); 196 this.userAgent = service.getUserAgent(); 197 this.acceptGzipEncoding = service.getAcceptGzipEncoding(); 198 this.httpHeaders = service.getHttpHeaders(); 199 } 200 201 protected void initializeHttpClient() { 202 Registry<ConnectionSocketFactory> registry = createConnectionSocketFactoryRegistry(); 203 HttpClientConnectionManager httpConnectionManager = new BasicHttpClientConnectionManager(registry); 204 AuthenticationStrategy authStrategy = new CookieProcessingTargetAuthenticationStrategy(); 205 206 httpClient = HttpClients.custom() 207 .setConnectionManager(httpConnectionManager) 208 .setTargetAuthenticationStrategy(authStrategy) 209 .build(); 210 } 211 212 protected void initializeHttpPoolingClient() { 213 Registry<ConnectionSocketFactory> registry = createConnectionSocketFactoryRegistry(); 214 PoolingHttpClientConnectionManager httpConnectionManager = new PoolingHttpClientConnectionManager(registry); 215 httpConnectionManager.setMaxTotal(maximumPoolingConnections); 216 httpConnectionManager.setDefaultMaxPerRoute(maximumPoolingConnections); 217 AuthenticationStrategy authStrategy = new CookieProcessingTargetAuthenticationStrategy(); 218 219 httpPoolingClient = HttpClients.custom() 220 .setConnectionManager(httpConnectionManager) 221 .setTargetAuthenticationStrategy(authStrategy) 222 .build(); 223 } 224 225 /** 226 * Sets the maximum number of connections for the pooling connection manager which is used for 227 * subscriptions. 228 * <p> 229 * Default is 10. 230 * </p> 231 * 232 * @param maximumPoolingConnections Maximum number of pooling connections 233 */ 234 public void setMaximumPoolingConnections(int maximumPoolingConnections) { 235 if (maximumPoolingConnections < 1) 236 throw new IllegalArgumentException("maximumPoolingConnections must be 1 or greater"); 237 this.maximumPoolingConnections = maximumPoolingConnections; 238 } 239 240 /** 241 * Create registry with configured {@link ConnectionSocketFactory} instances. 242 * Override this method to change how to work with different schemas. 243 * 244 * @return registry object 245 */ 246 protected Registry<ConnectionSocketFactory> createConnectionSocketFactoryRegistry() { 247 try { 248 return RegistryBuilder.<ConnectionSocketFactory>create() 249 .register(EWSConstants.HTTP_SCHEME, new PlainConnectionSocketFactory()) 250 .register(EWSConstants.HTTPS_SCHEME, EwsSSLProtocolSocketFactory.build(null)) 251 .build(); 252 } catch (GeneralSecurityException e) { 253 throw new RuntimeException( 254 "Could not initialize ConnectionSocketFactory instances for HttpClientConnectionManager", e 255 ); 256 } 257 } 258 259 /** 260 * (Re)initializes the HttpContext object. This removes any existing state (mainly cookies). Use an own 261 * cookie store, instead of the httpClient's global store, so cookies get reset on reinitialization 262 */ 263 private void initializeHttpContext() { 264 httpContext = HttpClientContext.create(); 265 if (!useGlobalCookieStore) { 266 CookieStore cookieStore = new BasicCookieStore(); 267 httpContext.setCookieStore(cookieStore); 268 } 269 } 270 271 @Override 272 public void close() { 273 if (!externalHttpClient) { 274 IOUtils.closeQuietly(httpClient); 275 } 276 if (!externalHttpPoolingClient) { 277 IOUtils.closeQuietly(httpPoolingClient); 278 } 279 } 280 281 // Event handlers 282 283 /** 284 * Calls the custom SOAP header serialisation event handlers, if defined. 285 * 286 * @param writer The XmlWriter to which to write the custom SOAP headers. 287 */ 288 public void doOnSerializeCustomSoapHeaders(XMLStreamWriter writer) { 289 EwsUtilities 290 .ewsAssert(writer != null, "ExchangeService.DoOnSerializeCustomSoapHeaders", "writer is null"); 291 292 if (null != getOnSerializeCustomSoapHeaders() && 293 !getOnSerializeCustomSoapHeaders().isEmpty()) { 294 for (ICustomXmlSerialization customSerialization : getOnSerializeCustomSoapHeaders()) { 295 customSerialization.CustomXmlSerialization(writer); 296 } 297 } 298 } 299 300 // Utilities 301 302 /** 303 * Creates an HttpWebRequest instance and initialises it with the 304 * appropriate parameters, based on the configuration of this service 305 * object. 306 * 307 * @param url The URL that the HttpWebRequest should target. 308 * @param acceptGzipEncoding If true, ask server for GZip compressed content. 309 * @param allowAutoRedirect If true, redirection response will be automatically followed. 310 * @return An initialised instance of HttpWebRequest. 311 * @throws ServiceLocalException the service local exception 312 * @throws java.net.URISyntaxException the uRI syntax exception 313 */ 314 protected HttpWebRequest prepareHttpWebRequestForUrl(URI url, boolean acceptGzipEncoding, 315 boolean allowAutoRedirect) throws ServiceLocalException, URISyntaxException { 316 // Verify that the protocol is something that we can handle 317 String scheme = url.getScheme(); 318 if (!scheme.equalsIgnoreCase(EWSConstants.HTTP_SCHEME) 319 && !scheme.equalsIgnoreCase(EWSConstants.HTTPS_SCHEME)) { 320 String strErr = String.format("Protocol %s isn't supported for service request.", scheme); 321 throw new ServiceLocalException(strErr); 322 } 323 324 if (httpContext == null) { 325 initializeHttpContext(); 326 } 327 328 HttpClientWebRequest request = new HttpClientWebRequest(httpClient, httpContext); 329 prepareHttpWebRequestForUrl(url, acceptGzipEncoding, allowAutoRedirect, request); 330 331 return request; 332 } 333 334 /** 335 * Creates an HttpWebRequest instance from a pooling connection manager and initialises it with 336 * the appropriate parameters, based on the configuration of this service object. 337 * <p> 338 * This is used for subscriptions. 339 * </p> 340 * 341 * @param url The URL that the HttpWebRequest should target. 342 * @param acceptGzipEncoding If true, ask server for GZip compressed content. 343 * @param allowAutoRedirect If true, redirection response will be automatically followed. 344 * @return An initialised instance of HttpWebRequest. 345 * @throws ServiceLocalException the service local exception 346 * @throws java.net.URISyntaxException the uRI syntax exception 347 */ 348 protected HttpWebRequest prepareHttpPoolingWebRequestForUrl(URI url, boolean acceptGzipEncoding, 349 boolean allowAutoRedirect) throws ServiceLocalException, URISyntaxException { 350 // Verify that the protocol is something that we can handle 351 String scheme = url.getScheme(); 352 if (!scheme.equalsIgnoreCase(EWSConstants.HTTP_SCHEME) 353 && !scheme.equalsIgnoreCase(EWSConstants.HTTPS_SCHEME)) { 354 String strErr = String.format("Protocol %s isn't supported for service request.", scheme); 355 throw new ServiceLocalException(strErr); 356 } 357 358 if (httpPoolingClient == null) { 359 initializeHttpPoolingClient(); 360 } 361 362 if (httpContext == null) { 363 initializeHttpContext(); 364 } 365 366 HttpClientWebRequest request = new HttpClientWebRequest(httpPoolingClient, httpContext); 367 prepareHttpWebRequestForUrl(url, acceptGzipEncoding, allowAutoRedirect, request); 368 369 return request; 370 } 371 372 private void prepareHttpWebRequestForUrl(URI url, boolean acceptGzipEncoding, boolean allowAutoRedirect, 373 HttpClientWebRequest request) throws ServiceLocalException, URISyntaxException { 374 try { 375 request.setUrl(url.toURL()); 376 } catch (MalformedURLException e) { 377 String strErr = String.format("Incorrect format : %s", url); 378 throw new ServiceLocalException(strErr); 379 } 380 381 request.setPreAuthenticate(preAuthenticate); 382 request.setTimeout(timeout); 383 request.setContentType("text/xml; charset=utf-8"); 384 request.setAccept("text/xml"); 385 request.setUserAgent(userAgent); 386 request.setAllowAutoRedirect(allowAutoRedirect); 387 request.setAcceptGzipEncoding(acceptGzipEncoding); 388 request.setHeaders(getHttpHeaders()); 389 request.setProxy(getWebProxy()); 390 prepareCredentials(request); 391 392 request.prepareConnection(); 393 394 httpResponseHeaders.clear(); 395 } 396 397 protected void prepareCredentials(HttpWebRequest request) throws ServiceLocalException, URISyntaxException { 398 request.setUseDefaultCredentials(useDefaultCredentials); 399 if (!useDefaultCredentials) { 400 if (credentials == null) { 401 throw new ServiceLocalException("Credentials are required to make a service request."); 402 } 403 404 // Make sure that credential have been authenticated if required 405 credentials.preAuthenticate(); 406 407 // Apply credential to the request 408 credentials.prepareWebRequest(request); 409 } 410 } 411 412 /** 413 * This method doesn't handle 500 ISE errors. This is handled by the caller since 414 * 500 ISE typically indicates that a SOAP fault has occurred and the handling of 415 * a SOAP fault is currently service specific. 416 * 417 * @param httpWebResponse HTTP web response 418 * @param webException web exception 419 * @param responseHeadersTraceFlag trace flag for response headers 420 * @param responseTraceFlag trace flag for respone 421 * @throws Exception on error 422 */ 423 protected void internalProcessHttpErrorResponse(HttpWebRequest httpWebResponse, Exception webException, 424 TraceFlags responseHeadersTraceFlag, TraceFlags responseTraceFlag) throws Exception { 425 EwsUtilities.ewsAssert(500 != httpWebResponse.getResponseCode(), 426 "ExchangeServiceBase.InternalProcessHttpErrorResponse", 427 "InternalProcessHttpErrorResponse does not handle 500 ISE errors, the caller is supposed to handle this."); 428 429 this.processHttpResponseHeaders(responseHeadersTraceFlag, httpWebResponse); 430 431 // E14:321785 -- Deal with new HTTP error code indicating that account is locked. 432 // The "unlock" URL is returned as the status description in the response. 433 if (httpWebResponse.getResponseCode() == 456) { 434 String location = httpWebResponse.getResponseContentType(); 435 436 URI accountUnlockUrl = null; 437 if (checkURIPath(location)) { 438 accountUnlockUrl = new URI(location); 439 } 440 441 final String message = String.format("This account is locked. Visit %s to unlock it.", accountUnlockUrl); 442 this.traceMessage(responseTraceFlag, message); 443 throw new AccountIsLockedException(message, accountUnlockUrl, webException); 444 } 445 } 446 447 /** 448 * @param location file path 449 * @return false if location is null,true if this abstract pathname is absolute 450 */ 451 public static boolean checkURIPath(String location) { 452 if (location == null) { 453 return false; 454 } 455 final File file = new File(location); 456 return file.isAbsolute(); 457 } 458 459 /** 460 * @param httpWebResponse HTTP web response 461 * @param webException web exception 462 * @throws Exception on error 463 */ 464 protected abstract void processHttpErrorResponse(HttpWebRequest httpWebResponse, Exception webException) 465 throws Exception; 466 467 /** 468 * Determines whether tracing is enabled for specified trace flag(s). 469 * 470 * @param traceFlags The trace flags. 471 * @return True if tracing is enabled for specified trace flag(s). 472 */ 473 public boolean isTraceEnabledFor(TraceFlags traceFlags) { 474 return this.isTraceEnabled() && this.traceFlags.contains(traceFlags); 475 } 476 477 /** 478 * Logs the specified string to the TraceListener if tracing is enabled. 479 * 480 * @param traceType kind of trace entry 481 * @param logEntry the entry to log 482 * @throws XMLStreamException the XML stream exception 483 * @throws IOException signals that an I/O exception has occurred 484 */ 485 public void traceMessage(TraceFlags traceType, String logEntry) throws XMLStreamException, IOException { 486 if (this.isTraceEnabledFor(traceType)) { 487 String traceTypeStr = traceType.toString(); 488 String logMessage = EwsUtilities.formatLogMessage(traceTypeStr, logEntry); 489 this.traceListener.trace(traceTypeStr, logMessage); 490 } 491 } 492 493 /** 494 * Logs the specified XML to the TraceListener if tracing is enabled. 495 * 496 * @param traceType Kind of trace entry. 497 * @param stream The stream containing XML. 498 */ 499 public void traceXml(TraceFlags traceType, ByteArrayOutputStream stream) { 500 if (this.isTraceEnabledFor(traceType)) { 501 String traceTypeStr = traceType.toString(); 502 String logMessage = EwsUtilities.formatLogMessageWithXmlContent(traceTypeStr, stream); 503 this.traceListener.trace(traceTypeStr, logMessage); 504 } 505 } 506 507 /** 508 * Traces the HTTP request headers. 509 * 510 * @param traceType Kind of trace entry. 511 * @param request The request 512 * @throws EWSHttpException EWS http exception 513 * @throws URISyntaxException URI syntax error 514 * @throws IOException signals that an I/O exception has occurred 515 * @throws XMLStreamException the XML stream exception 516 */ 517 public void traceHttpRequestHeaders(TraceFlags traceType, HttpWebRequest request) 518 throws URISyntaxException, EWSHttpException, XMLStreamException, IOException { 519 if (this.isTraceEnabledFor(traceType)) { 520 String traceTypeStr = traceType.toString(); 521 String headersAsString = EwsUtilities.formatHttpRequestHeaders(request); 522 String logMessage = EwsUtilities.formatLogMessage(traceTypeStr, headersAsString); 523 this.traceListener.trace(traceTypeStr, logMessage); 524 } 525 } 526 527 /** 528 * Traces the HTTP response headers. 529 * 530 * @param traceType kind of trace entry 531 * @param request the HttpRequest object 532 * @throws XMLStreamException the XML stream exception 533 * @throws IOException signals that an I/O exception has occurred 534 * @throws EWSHttpException the EWS http exception 535 */ 536 private void traceHttpResponseHeaders(TraceFlags traceType, HttpWebRequest request) 537 throws XMLStreamException, IOException, EWSHttpException { 538 if (this.isTraceEnabledFor(traceType)) { 539 String traceTypeStr = traceType.toString(); 540 String headersAsString = EwsUtilities.formatHttpResponseHeaders(request); 541 String logMessage = EwsUtilities.formatLogMessage(traceTypeStr, headersAsString); 542 this.traceListener.trace(traceTypeStr, logMessage); 543 } 544 } 545 546 /** 547 * Converts the date time to universal date time string. 548 * 549 * @param dt the date 550 * @return String representation of DateTime in yyyy-MM-ddTHH:mm:ssZ format. 551 */ 552 public String convertDateTimeToUniversalDateTimeString(Date dt) { 553 String utcPattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; 554 DateFormat utcFormatter = new SimpleDateFormat(utcPattern); 555 utcFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); 556 return utcFormatter.format(dt); 557 } 558 559 /** 560 * Sets the user agent to a custom value 561 * 562 * @param userAgent User agent string to set on the service 563 */ 564 protected void setCustomUserAgent(String userAgent) { 565 this.userAgent = userAgent; 566 } 567 568 /** 569 * Validates this instance. 570 * 571 * @throws ServiceLocalException the service local exception 572 */ 573 public void validate() throws ServiceLocalException { 574 } 575 576 /** 577 * Gets a value indicating whether tracing is enabled. 578 * 579 * @return True is tracing is enabled 580 */ 581 public boolean isTraceEnabled() { 582 return this.traceEnabled; 583 } 584 585 /** 586 * Sets a value indicating whether tracing is enabled. 587 * 588 * @param traceEnabled true to enable tracing 589 */ 590 public void setTraceEnabled(boolean traceEnabled) { 591 this.traceEnabled = traceEnabled; 592 if (this.traceEnabled && (this.traceListener == null)) { 593 this.traceListener = new EwsTraceListener(); 594 } 595 } 596 597 /** 598 * Gets the trace flags. 599 * 600 * @return Set of trace flags. 601 */ 602 public EnumSet<TraceFlags> getTraceFlags() { 603 return traceFlags; 604 } 605 606 /** 607 * Sets the trace flags. 608 * 609 * @param traceFlags A set of trace flags 610 */ 611 public void setTraceFlags(EnumSet<TraceFlags> traceFlags) { 612 this.traceFlags = traceFlags; 613 } 614 615 /** 616 * Gets the trace listener. 617 * 618 * @return The trace listener. 619 */ 620 public ITraceListener getTraceListener() { 621 return traceListener; 622 } 623 624 /** 625 * Sets the trace listener. 626 * 627 * @param traceListener the trace listener. 628 */ 629 public void setTraceListener(ITraceListener traceListener) { 630 this.traceListener = traceListener; 631 this.traceEnabled = (traceListener != null); 632 } 633 634 public void setServiceRequestTracer(ServiceRequestTraceListener serviceRequestTraceListener) { 635 this.serviceRequestTraceListener = serviceRequestTraceListener; 636 } 637 638 /** 639 * Gets the credential used to authenticate with the Exchange Web Services. 640 * 641 * @return credential 642 */ 643 public ExchangeCredentials getCredentials() { 644 return this.credentials; 645 } 646 647 /** 648 * Sets the credential used to authenticate with the Exchange Web Services. 649 * Setting the Credentials property automatically sets the 650 * UseDefaultCredentials to false. 651 * 652 * @param credentials Exchange credential. 653 */ 654 public void setCredentials(ExchangeCredentials credentials) { 655 this.credentials = credentials; 656 this.useDefaultCredentials = false; 657 658 // Reset the httpContext, to remove any existing authentication cookies from subsequent request 659 httpContext = null; 660 } 661 662 /** 663 * Gets a value indicating whether the credential of the user currently 664 * logged into Windows should be used to authenticate with the Exchange Web 665 * Services. 666 * 667 * @return true if credential of the user currently logged in are used 668 */ 669 public boolean getUseDefaultCredentials() { 670 return this.useDefaultCredentials; 671 } 672 673 /** 674 * Sets a value indicating whether the credential of the user currently 675 * logged into Windows should be used to authenticate with the Exchange Web 676 * Services. Setting UseDefaultCredentials to true automatically sets the 677 * Credentials property to null. 678 * 679 * @param value the new use default credential 680 */ 681 public void setUseDefaultCredentials(boolean value) { 682 this.useDefaultCredentials = value; 683 if (value) { 684 this.credentials = null; 685 } 686 687 // Reset the httpContext, to remove any existing authentication cookies from subsequent request 688 httpContext = null; 689 } 690 691 /** 692 * Gets the timeout used when sending HTTP request and when receiving HTTP 693 * response, in milliseconds. 694 * 695 * @return timeout in milliseconds 696 */ 697 public int getTimeout() { 698 return timeout; 699 } 700 701 /** 702 * Sets the timeout used when sending HTTP request and when receiving HTTP 703 * respones, in milliseconds. Defaults to 100000. 704 * 705 * @param timeout timeout in milliseconds 706 */ 707 public void setTimeout(int timeout) { 708 if (timeout < 1) { 709 throw new IllegalArgumentException("Timeout must be greater than zero."); 710 } 711 this.timeout = timeout; 712 } 713 714 /** 715 * Gets a value that indicates whether HTTP pre-authentication should be 716 * performed. 717 * 718 * @return true indicates pre-authentication is set 719 */ 720 public boolean isPreAuthenticate() { 721 return preAuthenticate; 722 } 723 724 /** 725 * Sets a value that indicates whether HTTP pre-authentication should be 726 * performed. 727 * 728 * @param preAuthenticate true to enable pre-authentication 729 */ 730 public void setPreAuthenticate(boolean preAuthenticate) { 731 this.preAuthenticate = preAuthenticate; 732 } 733 734 /** 735 * Gets a value indicating whether GZip compression encoding should be 736 * accepted. This value will tell the server that the client is able to 737 * handle GZip compression encoding. The server will only send Gzip 738 * compressed content if it has been configured to do so. 739 * 740 * @return true if compression is used 741 */ 742 public boolean getAcceptGzipEncoding() { 743 return acceptGzipEncoding; 744 } 745 746 /** 747 * Gets a value indicating whether GZip compression encoding should 748 * be accepted. This value will tell the server that the client is able to 749 * handle GZip compression encoding. The server will only send Gzip 750 * compressed content if it has been configured to do so. 751 * 752 * @param acceptGzipEncoding true to enable compression 753 */ 754 public void setAcceptGzipEncoding(boolean acceptGzipEncoding) { 755 this.acceptGzipEncoding = acceptGzipEncoding; 756 } 757 758 /** 759 * Gets the requested server version. 760 * 761 * @return The requested server version. 762 */ 763 public ExchangeVersion getRequestedServerVersion() { 764 return this.requestedServerVersion; 765 } 766 767 /** 768 * Gets the user agent. 769 * 770 * @return The user agent. 771 */ 772 public String getUserAgent() { 773 return this.userAgent; 774 } 775 776 /** 777 * Sets the user agent. 778 * 779 * @param userAgent The user agent 780 */ 781 public void setUserAgent(String userAgent) { 782 this.userAgent = userAgent + " (" + ExchangeServiceBase.defaultUserAgent + ")"; 783 } 784 785 /** 786 * Gets information associated with the server that processed the last 787 * request. Will be null if no request have been processed. 788 * 789 * @return the server info 790 */ 791 public ExchangeServerInfo getServerInfo() { 792 return serverInfo; 793 } 794 795 /** 796 * Sets information associated with the server that processed the last 797 * request. 798 * 799 * @param serverInfo Server Information 800 */ 801 public void setServerInfo(ExchangeServerInfo serverInfo) { 802 this.serverInfo = serverInfo; 803 } 804 805 /** 806 * Gets the web proxy that should be used when sending request to EWS. 807 * 808 * @return Proxy 809 * the Proxy Information 810 */ 811 public WebProxy getWebProxy() { 812 return this.webProxy; 813 } 814 815 /** 816 * Sets the web proxy that should be used when sending request to EWS. 817 * Set this property to null to use the default web proxy. 818 * 819 * @param value the Proxy Information 820 */ 821 public void setWebProxy(WebProxy value) { 822 this.webProxy = value; 823 } 824 825 public boolean isUseGlobalCookieStore() { 826 return useGlobalCookieStore; 827 } 828 829 public void setUseGlobalCookieStore(boolean useGlobalCookieStore) { 830 this.useGlobalCookieStore = useGlobalCookieStore; 831 } 832 833 /** 834 * Gets a collection of HTTP headers that will be sent with each request to 835 * EWS. 836 * 837 * @return httpHeaders 838 */ 839 public Map<String, String> getHttpHeaders() { 840 return this.httpHeaders; 841 } 842 843 // Events 844 845 /** 846 * Provides an event that applications can implement to emit custom SOAP 847 * headers in request that are sent to Exchange. 848 */ 849 private List<ICustomXmlSerialization> OnSerializeCustomSoapHeaders; 850 851 /** 852 * Gets the on serialize custom soap headers. 853 * 854 * @return the on serialize custom soap headers 855 */ 856 public List<ICustomXmlSerialization> getOnSerializeCustomSoapHeaders() { 857 return OnSerializeCustomSoapHeaders; 858 } 859 860 /** 861 * Sets the on serialize custom soap headers. 862 * 863 * @param onSerializeCustomSoapHeaders the new on serialize custom soap headers 864 */ 865 public void setOnSerializeCustomSoapHeaders(List<ICustomXmlSerialization> onSerializeCustomSoapHeaders) { 866 OnSerializeCustomSoapHeaders = onSerializeCustomSoapHeaders; 867 } 868 869 /** 870 * Traces the HTTP response headers. 871 * 872 * @param traceType kind of trace entry 873 * @param request The request 874 * @throws EWSHttpException EWS http exception 875 * @throws IOException signals that an I/O exception has occurred 876 * @throws XMLStreamException the XML stream exception 877 */ 878 public void processHttpResponseHeaders(TraceFlags traceType, HttpWebRequest request) 879 throws XMLStreamException, IOException, EWSHttpException { 880 this.traceHttpResponseHeaders(traceType, request); 881 this.saveHttpResponseHeaders(request.getResponseHeaders()); 882 } 883 884 /** 885 * Save the HTTP response headers. 886 * 887 * @param headers The response headers 888 */ 889 private void saveHttpResponseHeaders(Map<String, String> headers) { 890 this.httpResponseHeaders.clear(); 891 892 for (String key : headers.keySet()) { 893 this.httpResponseHeaders.put(key, headers.get(key)); 894 } 895 } 896 897 /** 898 * Gets a collection of HTTP headers from the last response. 899 * @return HTTP response headers 900 */ 901 public Map<String, String> getHttpResponseHeaders() { 902 return this.httpResponseHeaders; 903 } 904 905 /** 906 * Gets the session key. 907 * @return session key 908 */ 909 public static byte[] getSessionKey() { 910 // this has to be computed only once. 911 synchronized (ExchangeServiceBase.class) { 912 if (ExchangeServiceBase.binarySecret == null) { 913 Random randomNumberGenerator = new Random(); 914 ExchangeServiceBase.binarySecret = new byte[256 / 8]; 915 randomNumberGenerator.nextBytes(binarySecret); 916 } 917 918 return ExchangeServiceBase.binarySecret; 919 } 920 } 921 922 public int getMaximumPoolingConnections() { 923 return maximumPoolingConnections; 924 } 925 926 public <T> void traceServiceRequestStart(ServiceRequestBase<T> serviceRequest, HttpWebRequest request) { 927 if (serviceRequestTraceListener == null) { 928 return; 929 } 930 serviceRequestTraceListener.requestStart(serviceRequest, request); 931 } 932 933 public <T> void traceServiceRequestError(ServiceRequestBase<T> serviceRequest, HttpWebRequest request, Exception e) { 934 if (serviceRequestTraceListener == null) { 935 return; 936 } 937 serviceRequestTraceListener.requestError(serviceRequest, request, e); 938 } 939 940 public <T> void traceServiceRequestSuccess(ServiceRequestBase<T> serviceRequest, HttpWebRequest request) { 941 if (serviceRequestTraceListener == null) { 942 return; 943 } 944 serviceRequestTraceListener.requestFinish(serviceRequest, request); 945 } 946}