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
024 package microsoft.exchange.webservices.data.core;
025
026 import java.io.ByteArrayOutputStream;
027 import java.io.Closeable;
028 import java.io.File;
029 import java.io.IOException;
030 import java.net.MalformedURLException;
031 import java.net.URI;
032 import java.net.URISyntaxException;
033 import java.security.GeneralSecurityException;
034 import java.text.DateFormat;
035 import java.text.SimpleDateFormat;
036 import java.util.Date;
037 import java.util.EnumSet;
038 import java.util.HashMap;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Random;
042 import java.util.TimeZone;
043
044 import javax.xml.stream.XMLStreamException;
045 import javax.xml.stream.XMLStreamWriter;
046
047 import microsoft.exchange.webservices.data.EWSConstants;
048 import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
049 import microsoft.exchange.webservices.data.core.enumeration.misc.TraceFlags;
050 import microsoft.exchange.webservices.data.core.exception.http.EWSHttpException;
051 import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
052 import microsoft.exchange.webservices.data.core.exception.service.remote.AccountIsLockedException;
053 import microsoft.exchange.webservices.data.core.request.HttpClientWebRequest;
054 import microsoft.exchange.webservices.data.core.request.HttpWebRequest;
055 import microsoft.exchange.webservices.data.credential.ExchangeCredentials;
056 import microsoft.exchange.webservices.data.misc.EwsTraceListener;
057 import microsoft.exchange.webservices.data.misc.ITraceListener;
058
059 import org.apache.commons.logging.Log;
060 import org.apache.commons.logging.LogFactory;
061 import org.apache.http.client.AuthenticationStrategy;
062 import org.apache.http.client.CookieStore;
063 import org.apache.http.client.protocol.HttpClientContext;
064 import org.apache.http.config.Registry;
065 import org.apache.http.config.RegistryBuilder;
066 import org.apache.http.conn.HttpClientConnectionManager;
067 import org.apache.http.conn.socket.ConnectionSocketFactory;
068 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
069 import org.apache.http.impl.client.BasicCookieStore;
070 import org.apache.http.impl.client.CloseableHttpClient;
071 import org.apache.http.impl.client.HttpClients;
072 import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
073 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
074
075 /**
076 * Represents an abstract binding to an Exchange Service.
077 */
078 public 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 }