alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ServiceLocator.java)

This example Java source code file (ServiceLocator.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

comparable, dircontext, exception, invalidnameexception, ldapname, naming, random, rdn, servicelocator, srv_rr, srv_rr_attr, srvrecord, string, stringbuffer, stringtokenizer, util

The ServiceLocator.java Java example source code

/*
 * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.jndi.ldap;

import java.util.Arrays;
import java.util.Hashtable;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.List;

import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.NamingManager;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

/**
 * This class discovers the location of LDAP services by querying DNS.
 * See http://www.ietf.org/internet-drafts/draft-ietf-ldapext-locate-07.txt
 */

class ServiceLocator {

    private static final String SRV_RR = "SRV";

    private static final String[] SRV_RR_ATTR = new String[]{SRV_RR};

    private static final Random random = new Random();

    private ServiceLocator() {
    }

    /**
     * Maps a distinguished name (RFC 2253) to a fully qualified domain name.
     * Processes a sequence of RDNs having a DC attribute.
     * The special RDN "DC=." denotes the root of the domain tree.
     * Multi-valued RDNs, non-DC attributes, binary-valued attributes and the
     * RDN "DC=." all reset the domain name and processing continues.
     *
     * @param dn A string distinguished name (RFC 2253).
     * @return A domain name or null if none can be derived.
     * @throw InvalidNameException If the distinugished name is invalid.
     */
    static String mapDnToDomainName(String dn) throws InvalidNameException {
        if (dn == null) {
            return null;
        }
        StringBuffer domain = new StringBuffer();
        LdapName ldapName = new LdapName(dn);

        // process RDNs left-to-right
        //List<Rdn> rdnList = ldapName.getRdns();

        List<Rdn> rdnList = ldapName.getRdns();
        for (int i = rdnList.size() - 1; i >= 0; i--) {
            //Rdn rdn = rdnList.get(i);
            Rdn rdn = rdnList.get(i);

            // single-valued RDN with a DC attribute
            if ((rdn.size() == 1) &&
                ("dc".equalsIgnoreCase(rdn.getType()) )) {
                Object attrval = rdn.getValue();
                if (attrval instanceof String) {
                    if (attrval.equals(".") ||
                        (domain.length() == 1 && domain.charAt(0) == '.')) {
                        domain.setLength(0); // reset (when current or previous
                                             //        RDN value is "DC=.")
                    }
                    if (domain.length() > 0) {
                        domain.append('.');
                    }
                    domain.append(attrval);
                } else {
                    domain.setLength(0); // reset (when binary-valued attribute)
                }
            } else {
                domain.setLength(0); // reset (when multi-valued RDN or non-DC)
            }
        }
        return (domain.length() != 0) ? domain.toString() : null;
    }

    /**
     * Locates the LDAP service for a given domain.
     * Queries DNS for a list of LDAP Service Location Records (SRV) for a
     * given domain name.
     *
     * @param domainName A string domain name.
     * @param environment The possibly null environment of the context.
     * @return An ordered list of hostports for the LDAP service or null if
     *         the service has not been located.
     */
    static String[] getLdapService(String domainName, Hashtable<?,?> environment) {

        if (domainName == null || domainName.length() == 0) {
            return null;
        }

        String dnsUrl = "dns:///_ldap._tcp." + domainName;
        String[] hostports = null;

        try {
            // Create the DNS context using NamingManager rather than using
            // the initial context constructor. This avoids having the initial
            // context constructor call itself (when processing the URL
            // argument in the getAttributes call).
            Context ctx = NamingManager.getURLContext("dns", environment);
            if (!(ctx instanceof DirContext)) {
                return null; // cannot create a DNS context
            }
            Attributes attrs =
                ((DirContext)ctx).getAttributes(dnsUrl, SRV_RR_ATTR);
            Attribute attr;

            if (attrs != null && ((attr = attrs.get(SRV_RR)) != null)) {
                int numValues = attr.size();
                int numRecords = 0;
                SrvRecord[] srvRecords = new SrvRecord[numValues];

                // create the service records
                int i = 0;
                int j = 0;
                while (i < numValues) {
                    try {
                        srvRecords[j] = new SrvRecord((String) attr.get(i));
                        j++;
                    } catch (Exception e) {
                        // ignore bad value
                    }
                    i++;
                }
                numRecords = j;

                // trim
                if (numRecords < numValues) {
                    SrvRecord[] trimmed = new SrvRecord[numRecords];
                    System.arraycopy(srvRecords, 0, trimmed, 0, numRecords);
                    srvRecords = trimmed;
                }

                // Sort the service records in ascending order of their
                // priority value. For records with equal priority, move
                // those with weight 0 to the top of the list.
                if (numRecords > 1) {
                    Arrays.sort(srvRecords);
                }

                // extract the host and port number from each service record
                hostports = extractHostports(srvRecords);
            }
        } catch (NamingException e) {
            // ignore
        }
        return hostports;
    }

    /**
     * Extract hosts and port numbers from a list of SRV records.
     * An array of hostports is returned or null if none were found.
     */
    private static String[] extractHostports(SrvRecord[] srvRecords) {
        String[] hostports = null;

        int head = 0;
        int tail = 0;
        int sublistLength = 0;
        int k = 0;
        for (int i = 0; i < srvRecords.length; i++) {
            if (hostports == null) {
                hostports = new String[srvRecords.length];
            }
            // find the head and tail of the list of records having the same
            // priority value.
            head = i;
            while (i < srvRecords.length - 1 &&
                srvRecords[i].priority == srvRecords[i + 1].priority) {
                i++;
            }
            tail = i;

            // select hostports from the sublist
            sublistLength = (tail - head) + 1;
            for (int j = 0; j < sublistLength; j++) {
                hostports[k++] = selectHostport(srvRecords, head, tail);
            }
        }
        return hostports;
    }

    /*
     * Randomly select a service record in the range [head, tail] and return
     * its hostport value. Follows the algorithm in RFC 2782.
     */
    private static String selectHostport(SrvRecord[] srvRecords, int head,
            int tail) {
        if (head == tail) {
            return srvRecords[head].hostport;
        }

        // compute the running sum for records between head and tail
        int sum = 0;
        for (int i = head; i <= tail; i++) {
            if (srvRecords[i] != null) {
                sum += srvRecords[i].weight;
                srvRecords[i].sum = sum;
            }
        }
        String hostport = null;

        // If all records have zero weight, select first available one;
        // otherwise, randomly select a record according to its weight
        int target = (sum == 0 ? 0 : random.nextInt(sum + 1));
        for (int i = head; i <= tail; i++) {
            if (srvRecords[i] != null && srvRecords[i].sum >= target) {
                hostport = srvRecords[i].hostport;
                srvRecords[i] = null; // make this record unavailable
                break;
            }
        }
        return hostport;
    }

/**
 * This class holds a DNS service (SRV) record.
 * See http://www.ietf.org/rfc/rfc2782.txt
 */

static class SrvRecord implements Comparable<SrvRecord> {

    int priority;
    int weight;
    int sum;
    String hostport;

    /**
     * Creates a service record object from a string record.
     * DNS supplies the string record in the following format:
     * <pre>
     *     <Priority> " "  " "  " " 
     * </pre>
     */
    SrvRecord(String srvRecord) throws Exception {
        StringTokenizer tokenizer = new StringTokenizer(srvRecord, " ");
        String port;

        if (tokenizer.countTokens() == 4) {
            priority = Integer.parseInt(tokenizer.nextToken());
            weight = Integer.parseInt(tokenizer.nextToken());
            port = tokenizer.nextToken();
            hostport = tokenizer.nextToken() + ":" + port;
        } else {
            throw new IllegalArgumentException();
        }
    }

    /*
     * Sort records in ascending order of priority value. For records with
     * equal priority move those with weight 0 to the top of the list.
     */
    public int compareTo(SrvRecord that) {
        if (priority > that.priority) {
            return 1; // this > that
        } else if (priority < that.priority) {
            return -1; // this < that
        } else if (weight == 0 && that.weight != 0) {
            return -1; // this < that
        } else if (weight != 0 && that.weight == 0) {
            return 1; // this > that
        } else {
            return 0; // this == that
        }
    }
}
}

Other Java examples (source code examples)

Here is a short list of links related to this Java ServiceLocator.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.