Package mireka.transmission.immediate.dns

Source Code of mireka.transmission.immediate.dns.MxLookup$MXRecordPriorityComparator

package mireka.transmission.immediate.dns;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;

import mireka.address.Domain;
import mireka.smtp.EnhancedStatus;
import mireka.transmission.immediate.SendException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.MXRecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.Record;

/**
* This class wraps DNS query functionality in order to make unit testing
* easier.
*/
@NotThreadSafe
public class MxLookup {
    private static MXRecordPriorityComparator mxRecordPriorityComparator =
            new MXRecordPriorityComparator();
    private final Logger logger = LoggerFactory.getLogger(MxLookup.class);
    private final Domain domain;

    public MxLookup(Domain domain) {
        this.domain = domain;
    }

    /**
     * Returns an ordered host name list based on the MX records of the domain.
     * The first has the highest priority. If the domain has no MX records, then
     * it returns the host itself. Records with the same priority are shuffled
     * randomly.
     *
     * @see <a href="http://tools.ietf.org/html/rfc5321#section-5.1">RFC 5321
     *      Simple Mail Transfer Protocol - Locating the Target Host</a>
     */
    public Name[] queryMxTargets() throws MxLookupException {
        MXRecord[] records = queryMxRecords();
        if (records.length == 0) {
            logger.debug("Domain {} has no MX records, using an implicit "
                    + "MX record targetting the host", domain);
            return implicitMxTargetForDomain();
        } else {
            //
            ArrayList<MXRecord> list =
                    new ArrayList<MXRecord>(Arrays.asList(records));
            Collections.shuffle(list);
            // This sort is guaranteed to be stable: equal elements will not be
            // reordered as a result of the sort, so shuffle remains in effect
            Collections.sort(list, mxRecordPriorityComparator);
            list.toArray(records);
            return convertMxRecordsToHostNames(records);
        }
    }

    /**
     * looks up MX records in the DNS system
     *
     * @param domain
     * @return an empty array if no MX record was found
     * @throws SendException
     *             if the domain is invalid or if the DNS lookup fails because
     *             the domain is not registered or the DNS servers are not
     *             accessible or any other DNS related problem
     */
    private MXRecord[] queryMxRecords() throws MxLookupException {
        org.xbill.DNS.Lookup lookup;

        try {
            lookup = new Lookup(domain.smtpText(), org.xbill.DNS.Type.MX);
        } catch (org.xbill.DNS.TextParseException e) {
            throw new MxLookupException(e,
                    EnhancedStatus.BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX);
        }

        Record[] recordsGeneric = lookup.run();
        MXRecord[] records = null;
        if (recordsGeneric != null) {
            records = new MXRecord[recordsGeneric.length];
            for (int i = 0; i < recordsGeneric.length; i++)
                records[i] = (MXRecord) recordsGeneric[i];
        }
        int errorCode = lookup.getResult();

        if (errorCode == Lookup.UNRECOVERABLE)
            throw new MxLookupException(domain + " " + lookup.getErrorString(),
                    EnhancedStatus.PERMANENT_UNABLE_TO_ROUTE);
        else if (errorCode == Lookup.TRY_AGAIN)
            throw new MxLookupException(domain + " " + lookup.getErrorString(),
                    EnhancedStatus.TRANSIENT_DIRECTORY_SERVER_FAILURE);
        else if (errorCode == Lookup.HOST_NOT_FOUND)
            throw new MxLookupException(domain + " " + lookup.getErrorString(),
                    EnhancedStatus.BAD_DESTINATION_SYSTEM_ADDRESS);
        else if (errorCode == Lookup.SUCCESSFUL
                || errorCode == Lookup.TYPE_NOT_FOUND)
            ; // continue
        else
            throw new MxLookupException("Unknown DNS status: " + errorCode
                    + ". " + domain + " " + lookup.getErrorString(),
                    EnhancedStatus.PERMANENT_INTERNAL_ERROR);
        if (records == null) {
            return new MXRecord[0];
        }

        return records;
    }

    private Name[] implicitMxTargetForDomain() {
        Name[] singletonNames = new Name[] { domain.toName() };
        return singletonNames;
    }

    private Name[] convertMxRecordsToHostNames(MXRecord[] records) {
        Name[] result = new Name[records.length];
        for (int i = result.length; --i >= 0;)
            result[i] = records[i].getTarget();
        return result;
    }

    /**
     * compares MX records based on their priority value
     */
    @Immutable
    private static class MXRecordPriorityComparator implements
            java.util.Comparator<MXRecord> {
        public int compare(MXRecord o1, MXRecord o2) {
            int p1 = o1.getPriority();
            int p2 = o2.getPriority();
            if (p1 < p2)
                return -1;
            else if (p1 > p2)
                return +1;
            else
                return 0;
        }
    }

}
TOP

Related Classes of mireka.transmission.immediate.dns.MxLookup$MXRecordPriorityComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.