All Downloads are FREE. Search and download functionalities are using the official Maven repository.

microsoft.exchange.webservices.data.AutodiscoverDnsClient Maven / Gradle / Ivy

Go to download

The source came from http://archive.msdn.microsoft.com/ewsjavaapi Support for Maven has been added.

The newest version!
/**************************************************************************
 * copyright file="AutodiscoverDnsClient.java" company="Microsoft"
 *     Copyright (c) Microsoft Corporation.  All rights reserved.
 * 
 * Defines the AutodiscoverDnsClient.java.
 **************************************************************************/
package microsoft.exchange.webservices.data;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.xml.stream.XMLStreamException;

/**
 * Class that reads AutoDiscover configuration information from DNS.
 */
class AutodiscoverDnsClient {

	/**
	 * SRV DNS prefix to lookup.
	 */
	private static final String AutoDiscoverSrvPrefix = "_autodiscover._tcp.";

	/**
	 * We are only interested in records that use SSL.
	 */
	private static final int SslPort = 443;

	/**
	 * Random selector in the case of ties.
	 */
	private static Random RandomTieBreakerSelector = new Random();

	/**
	 * AutodiscoverService using this DNS reader.
	 */
	private AutodiscoverService service;

	/**
	 * Initializes a new instance of the class.
	 * 
	 * @param service
	 *            the service
	 */
	protected AutodiscoverDnsClient(AutodiscoverService service) {
		this.service = service;
	}

	/**
	 * Finds the Autodiscover host from DNS SRV records.
	 * 
	 * @param domain
	 *            the domain
	 * @return Autodiscover hostname (will be null if lookup failed).
	 * @throws XMLStreamException
	 *             the xML stream exception
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	protected String findAutodiscoverHostFromSrv(String domain)
			throws XMLStreamException, IOException {
		String domainToMatch = AutoDiscoverSrvPrefix + domain;

		DnsSrvRecord dnsSrvRecord = this
				.findBestMatchingSrvRecord(domainToMatch);

		if ((dnsSrvRecord == null) || dnsSrvRecord.getNameTarget() == null ||
				 dnsSrvRecord.getNameTarget().isEmpty()) {
			this.service.traceMessage(TraceFlags.AutodiscoverConfiguration,
					"No appropriate SRV record was found.");
			return null;
		} else {
			this.service.traceMessage(TraceFlags.AutodiscoverConfiguration,
					String.format(
							"DNS query for SRV record for domain %s found %s",
							domain, dnsSrvRecord.getNameTarget()));

			return dnsSrvRecord.getNameTarget();
		}
	}

	/**
	 * Finds the best matching SRV record.
	 * 
	 * @param domain
	 *            the domain
	 * @return DnsSrvRecord(will be null if lookup failed).
	 * @throws XMLStreamException
	 *             the xML stream exception
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	private DnsSrvRecord findBestMatchingSrvRecord(String domain)
			throws XMLStreamException, IOException {
		List dnsSrvRecordList;
		try {
			// Make DnsQuery call to get collection of SRV records.
			dnsSrvRecordList = DnsClient.dnsQuery(DnsSrvRecord.class, domain,
					this.service.getDnsServerAddress());
		} catch (DnsException ex) {
			String dnsExcMessage = String.format("DnsQuery returned error " +
					"error '%s' error code 0x{1:X8}.",
					ex.getMessage(), ex.getError());
			this.service
					.traceMessage(
							TraceFlags.AutodiscoverConfiguration,
							dnsExcMessage);
			return null;
		} catch (SecurityException ex) {
			// In restricted environments, we may not be allowed to call
			// unmanaged code.
			this.service.traceMessage(TraceFlags.AutodiscoverConfiguration,
					String.format(
							"DnsQuery cannot be called. Security error: %s.",
							ex.getMessage()));
			return null;
		}

		this.service.traceMessage(TraceFlags.AutodiscoverConfiguration, String
				.format("%d SRV records were returned.", dnsSrvRecordList
						.size()));

		// If multiple records were returned, they will be returned sorted by
		// priority
		// (and weight) order. Need to find the index of the first record that
		// supports SSL.
		int priority = Integer.MIN_VALUE;
		int weight = Integer.MAX_VALUE;
		boolean recordFound = false;
		for (DnsSrvRecord dnsSrvRecord : dnsSrvRecordList) {
			if (dnsSrvRecord.getPort() == SslPort) {
				priority = dnsSrvRecord.getPriority();
				weight = dnsSrvRecord.getWeight();
				recordFound = true;
				break;
			}
		}

		// Records were returned but nothing matched our criteria.
		if (!recordFound) {
			this.service.traceMessage(TraceFlags.AutodiscoverConfiguration,
					"No appropriate SRV records were found.");

			return null;
		}

		List bestDnsSrvRecordList = new ArrayList();
		for (DnsSrvRecord dnsSrvRecord : dnsSrvRecordList) {
			if (dnsSrvRecord.getPort() == SslPort &&
					 dnsSrvRecord.getPriority() == priority &&
					 dnsSrvRecord.getWeight() == weight) {
				bestDnsSrvRecordList.add(dnsSrvRecord);
			}
		}

		// The list must contain at least one matching record since we found one
		// earlier.
		EwsUtilities.EwsAssert(dnsSrvRecordList.size() > 0,
				"AutodiscoverDnsClient.FindBestMatchingSrvRecord",
				"At least one DNS SRV record must match the criteria.");

		// If we have multiple records with the same priority and weight,
		// randomly pick one.
		int recordIndex = (bestDnsSrvRecordList.size() > 1) ? 
				RandomTieBreakerSelector
				.nextInt(bestDnsSrvRecordList.size()) :
				 0;

		DnsSrvRecord bestDnsSrvRecord = bestDnsSrvRecordList.get(recordIndex);

		String traceMessage = String.format("Returning SRV record %d " +
										"of %d records. " +
										"Target: %s, Priority: %d, Weight: %d",
										recordIndex, dnsSrvRecordList.size(),
										bestDnsSrvRecord.getNameTarget(),
										bestDnsSrvRecord.getPriority(),
										bestDnsSrvRecord.getWeight());
		this.service.traceMessage(TraceFlags.
				AutodiscoverConfiguration, traceMessage);
		

		return bestDnsSrvRecord;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy