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