Code Search for Developers
 
 
  

DNSServiceImpl.java from SmartFrog at Krugle


Show DNSServiceImpl.java syntax highlighted

/** (C) Copyright 1998-2004 Hewlett-Packard Development Company, LP

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

For more information: www.smartfrog.org

*/

package org.smartfrog.services.dns;

import java.util.List;
import org.smartfrog.sfcore.componentdescription.ComponentDescription;
import java.util.Vector;
import java.util.Enumeration;
import org.smartfrog.sfcore.common.Context;
import org.smartfrog.sfcore.parser.Phases;
import org.smartfrog.sfcore.parser.SFParser;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Iterator;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.SimpleResolver;
import org.xbill.DNS.Resolver;
import org.xbill.DNS.Name;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.PTRRecord;
import org.xbill.DNS.ARecord;
import java.util.Comparator;
import java.util.TreeSet;
import java.net.InetAddress;
import org.xbill.DNS.Record;
import org.xbill.DNS.SRVRecord;
import org.xbill.DNS.TXTRecord;
import org.xbill.DNS.Type;






/**
 * A set of client methods to locate compatible services using DNS
 * SRV records.
 *
 * 
 */
public class DNSServiceImpl  implements DNSServiceQuery {

    /** A base filter for all the results (or null). */
    DNSServiceFilter baseFilter = null;

    /** A name for the service class. */
    Name serviceClassName = null;

    /** Use the default DNS port number (53). */
    public final static int DEFAULT_DNS_PORT = -1;


    /**
     * Creates a new <code>DNSServiceImpl</code> instance.
     *
     * @param service a <code>String</code> value
     * @param baseFilter a <code>DNSServiceFilter</code> value
     */
    public DNSServiceImpl(String service, DNSServiceFilter baseFilter) {
        
        serviceClassName = DNSBindingIPImpl.toAbsoluteName(service);
        this.baseFilter = baseFilter;
    }


   /**
     * Performs a look-up of the registered service class using 
     * a particular resolver and filtering according to a given 
     * criteria. Matching instances are returned in decreasing
     * priority. Multiple requests could return different results
     * since the available instances or priorities could change 
     * dynamically. It uses  default DNS settings and filters.
     *
     * @return An array of service instances matching the criteria
     * and in decreasing priority or an array of lenght zero if 
     * no services found.
     * @exception DNSException if an error occurs while looking up.
     */
    public DNSServiceInstance[] lookup()
        throws DNSException {

        return lookup(null, null);
    } 

    /**
     * Performs a look-up of the registered service class using 
     * a particular resolver and filtering according to a given 
     * criteria. Matching instances are returned in decreasing
     * priority. Multiple requests could return different results
     * since the available instances or priorities could change 
     * dynamically.
     *
     * @param resol A network connection to resolve the query.
     * @param filter An extra filtering function to be applied to the 
     * results or null if no extra filtering is required.
     * @return An array of service instances matching the criteria
     * and in decreasing priority or an array of lenght zero if 
     * no services found.
     * @exception DNSException if an error occurs while looking up.
     */
    public DNSServiceInstance[] lookup(Resolver resol,
                                       DNSServiceFilter filter)
        throws DNSException {

        Resolver resolver = (resol == null ? getResolver(null) : resol);

        List result = findAllServices(resolver);
        result = filterServices(result, filter);
        result = sortServices(result,
                              DNSServiceInstanceImpl.getComparatorInstance());
        return (DNSServiceInstance[]) result.toArray(new DNSServiceInstance[0]);
    } 


    /**
     * Filters a list of services using the base or the extra filter
     * provided.
     *
     * @param in A list of services to be filtered.
     * @param filter An extra filter to be added.
     * @return A list with all the acceptable services.
     */
    List filterServices(List in, DNSServiceFilter filter) {

        Vector result = new Vector();
        for (Iterator iter = in.iterator(); iter.hasNext();) {
            DNSServiceInstance elem = (DNSServiceInstance) iter.next();
            // Bad if it fails ANY of the filters that are set
            boolean isBAD = ((baseFilter != null) 
                             && (!baseFilter.isAcceptable(elem)));
            isBAD = isBAD || ((filter != null) 
                              && (!filter.isAcceptable(elem)));
            if (!isBAD) {
                result.add(elem);
            }
        }
        return result;
    }

    /**
     * Sorts a list of services instances according to a standard comparator.
     * More important services are first in the list. It will also eliminate
     * duplicates from the service instance input list.
     *
     * @param in A list of services instances to be sorted.
     * @param comp A comparator function.
     * @return A sorted list of services instances.
     */
    List sortServices(List in, Comparator comp) {

        Vector result = new Vector();
        TreeSet sort = new TreeSet(comp);
        sort.addAll(in);
        
        // iterator is  in ascending order (less important at the end) 
        for (Iterator iter = sort.iterator(); iter.hasNext();) {
            result.add(iter.next());
        }
        return result;        
    }

    /**
     * Queries the DNS server for all the registered services with
     * a given name.
     *
     * @param resol A connection to the DNS server.
     * @return A list of service instances.
     * @exception DNSException if an error occurs while doing the look-ups.
     */
    List findAllServices(Resolver resol) 
        throws DNSException {

        try {
            Vector results = new Vector();
            Record[] answers = doLookup(resol, serviceClassName, Type.PTR);
            for (int i=0; i < answers.length; i++) {
                if (answers[i] instanceof PTRRecord) {
                    PTRRecord ptr = (PTRRecord) answers[i];
                    List inst = findOneService(resol, ptr.getTarget());
                    results.addAll(inst);
                }
            }
            return results;
        } catch (Exception e) {
            throw new DNSException("failed services lookup", e);
        }
    }

    /**
     * Locates the SRV and TXT DNS records for a service and creates
     * a description of the service instance. Only one service should 
     * be available for a given name (others are ignored).
     *
     * @param resol A network connection to the DNS server to resolve
     *  the query.
     * @param target A name for the service.
     * @return A list containing a service instance description.
     * @exception DNSException if an error occurs
     */
    List findOneService(Resolver resol, Name target) 
        throws DNSException {

        Vector results = new Vector();
        Record[] answersSRV = doLookup(resol, target, Type.SRV);
        Record[] answersTXT = doLookup(resol, target, Type.TXT);
        // only one mapping allowed, otherwise we ignore extra records.
        // We should log if length > 1 though ...
        if ((answersSRV.length >= 1) 
            && (answersTXT.length >= 1)) {
            SRVRecord srv = (SRVRecord) answersSRV[0];
            TXTRecord txt = (TXTRecord) answersTXT[0];
            InetAddress addr = findAddress(resol, srv.getTarget());
            DNSServiceInstance inst = 
                new DNSServiceInstanceImpl(srv, txt, addr);
            results.add(inst);
        }
        return results;                    
    }


    /**
     * Finds an address for a host name. If it cannot find it, just 
     * return null (i.e., no exception). If there are more than one,
     * just return the first one.
     *
     * @param resol A network connection to the DNS server to resolve
     *  the query.
     * @param hostName A name for the host.
     * @return An IP address for the host or null.
     */
    public static InetAddress findAddress(Resolver resol, Name hostName) {

        try {
            Record[] answer = doLookup(resol, hostName, Type.A);
            if ((answer.length > 0) && (answer[0] instanceof ARecord)) {
                return ((ARecord) answer[0]).getAddress();
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * Performs a DNS lookup bypassing the cache. It silently fails
     * if it cannot do the query (returns lenght 0 array)
     *
     * @param resol A resolver to contact the DNS server.
     * @param name A name for the record.
     * @param type A type for the record.
     * @return A (possibly zero length) array of result records. 
     * @exception DNSException if an error occurs
     */
    public static Record[] doLookup(Resolver resol, Name name,
                                    int type) {
        
        Lookup lu = new Lookup(name, type);
        lu.setResolver(resol);
        // clean up the cache.
        lu.setCache(null);
        lu.run();
        // we ignore the TRY_AGAIN for now... (TCP recommended)
        if (lu.getResult() ==  Lookup.SUCCESSFUL) {
            return lu.getAnswers();
        } else {
            return new Record[0];
        }
    }


    /**
     * Gets a resolver for DNS queries (port 53, use TCP).
     *
     * @param hostName A host name for the DNS server or null 
     * if we use the platform default.
     * @return A resolver for DNS queries.
     * @exception DNSException if an error occurs while getting a resolver
     * to the  name server.
     */
    public static Resolver getResolver(String hostName)
        throws DNSException {
     
        return getResolver(hostName, true, DEFAULT_DNS_PORT);
    } 

    /**
     * Gets a resolver for DNS queries.
     *
     * @param hostName A host name for the DNS server or null 
     * if we use the platform default.
     * @param useTCP Whether to use TCP for the query.
     * @param port Port to use or -1 for the default.
     * @return A resolver for DNS queries.
     * @exception DNSException if an error occurs while getting a resolver
     * to the  name server.
     */
    public static Resolver getResolver(String hostName, boolean useTCP,
                                       int port) 
        throws DNSException {
        
        try {
            SimpleResolver resolver = new SimpleResolver(hostName);
            if (port == DEFAULT_DNS_PORT) {
                resolver.setPort(DNSComponent.DEFAULT_PORT);
            } else {
                resolver.setPort(port);
            }
            if (useTCP) {
                resolver.setTCP(true);
            }        
            return resolver;
        } catch (Exception e) {
            throw new DNSException("Cannot get resolver", e);
        }
    }




    /**
     * Converts a component description into a list of formatted 
     * strings that can be incorporated into a TXT DNS record. Non
     * basic entries in the component description are ignored.
     *
     * @param cd A component description input.
     * @return A list of strings that represent "lines" of a TXT 
     * DNS record.
     */
    public static List cdToTXT(ComponentDescription cd) {

        List resultAll = new Vector();
        System.out.println("cdToTXT: in: " + cd); // DELETE        
        Context context = cd.sfContext();
        for (Enumeration e = context.keys(); e.hasMoreElements();) {
            StringBuffer result  = new StringBuffer();
            // restrict keys to  strings, otherwise class cast exception.
            String name = (String) e.nextElement();
            result.append(name + "=");
            try {
                result.append(valueToString(context.get(name)));
                resultAll.add(result.toString());
            } catch (IllegalArgumentException ex) {
                // just ignore non-basic entries in cd
            }
        }
        System.out.println("cdToTXT: out: " + resultAll); // DELETE        
        return resultAll;
    }

    /**
     * Converts a set of lines from a DNS TXT record into a component
     * description.
     *
     * @param strings A set of lines from a DNS TXT record.
     * @return A component description for that record.
     */
    public static ComponentDescription txtToCD(List strings)
        throws DNSException {
        
        try {
            System.out.println("txtToCD: in: " + strings); // DELETE
            StringBuffer result  = new StringBuffer();
            for (Iterator iter = strings.iterator(); iter.hasNext(); ) {
                
                String line = (String) iter.next();
                result.append(stringToSF1(line));
            }

            System.out.println("txtToCD: out: " + result); // DELETE
            byte[] inBytes = result.toString().getBytes("UTF-8");
            InputStream in = new ByteArrayInputStream(inBytes);
            SFParser parser = new SFParser("sf");
            Phases phases = parser.sfParse(in);
            Vector allPhases = new Vector();
            allPhases.add("type");
            // do we need all these phases?
            allPhases.add("place");
            allPhases.add("link");
            allPhases.add("function");

            phases.sfResolvePhases(allPhases);
            return phases.sfAsComponentDescription();
        } catch (Exception e) {
            if (e instanceof DNSException) {
                throw (DNSException) e;
            } else {
                throw new DNSException("txtToCD" + strings, e);
            }
        }
        
    }


    /**
     * Formats a TXT line into a parseable SF one.
     *
     * @param line A  TXT entry line.
     * @return A parseable SF line.
     */
    static String stringToSF1(String line) {

        String line2 = line.replaceAll("\\\\\"", "\""); // \" by "
        return line2.replaceFirst("=", " ") + ";";
    }


    /**
     * Formats a basic value of a component description into a string.
     *
     * @param obj A basic value inside a component description.
     * @return A (parsable) string representation of this value.
     */
    static String valueToString(Object obj) {

        return canonicalBasic(obj);
    }


    /*  THESE FUNCTIONS ARE DUPLICATED FROM THE NEW SECURITY CODE. 

    THEY SHOULD BE DELETED AND REPLACED BY SFCanonical after 
    the changes are merged.
                
    */
    /**
     * Returns a canonical string of a SF basic type. This is,
     * a String, Float, Long, Integer, Double, Boolean or vector.
     *
     * @param obj An object of a basic type to canonicalize.
     * @return A canonical string of a SF basic type.
     */
    public static String canonicalBasic(Object obj) {

        if (obj instanceof String) {
            // quoted string 
            return canonicalString((String) obj);
        } else if (obj instanceof Number) {
            // integer, long, float or double
            return canonicalNumber((Number) obj);
        } else if (obj instanceof Boolean) {
            // boolean
            return canonicalBoolean((Boolean) obj);
        } else if (obj instanceof Vector) {
            // vector of basic types
            return canonicalVector((Vector) obj);
        } else {
            throw new IllegalArgumentException("canonicalBasic: param" + obj
                                               + " is" + "not a basic type");
        }
    }

    /**
     * Returns a canonical string of a SF vector. All the elements of a
     * SF vector need to be basic types.
     *
     * @param vector A SF vector to be canonicalized.
     * @return  A canonical string of a SF vector.
     */
    public static String canonicalVector(Vector vector) {
    
        StringBuffer result  = new StringBuffer();
        result.append("[");
        for (Iterator iter = vector.iterator(); iter.hasNext();) {
            result.append(canonicalBasic(iter.next()));
            if (iter.hasNext()) {
                result.append(", ");
            }
        }
        result.append("]");
        return result.toString();
    }


    /**
     * Escapes special characters in a String so that they can be parsed back
     * as a SmartFrog "string".
     *
     * @param str A string that we want to escape its special characters.
     * @return The input string with special characters escaped.
     */
    public static String addEscapes(String str) {

        StringBuffer strBuf = new StringBuffer(str.length());
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            switch (c) {
            case '\\': 
                strBuf.append('\\');
                strBuf.append('\\');
                break;
            case '\n':
                strBuf.append('\\');
                strBuf.append('n');
                break;
            case '\t':
                strBuf.append('\\');
                strBuf.append('t');
                break;
            case '\b':
                strBuf.append('\\');
                strBuf.append('b');
                break;
            case '\r':
                strBuf.append('\\');
                strBuf.append('r');
                break;
            case '\f':
                strBuf.append('\\');
                strBuf.append('f');
                break;
            default :
                strBuf.append(c);
            }
        }
        return strBuf.toString();
    }

    /**
     * Returns a canonical string of a SF string, i.e., quoted and with
     * escaped special characters.
     *
     * @param str A string to be canonicalized.
     * @return a  canonical string of a SF string.
     */
    public static String canonicalString(String str) {

        return "\"" + addEscapes(str) + "\"";
    }

    /**
     * Returns a canonical string of a SF boolean.
     *
     * @param bool A boolean flag to be canonicalized.
     * @return A  canonical string of a SF boolean.
     */
    public static String canonicalBoolean(Boolean bool) {

        return (bool.booleanValue() ? "true" : "false");
    }

  
    /**
     * Returns a canonical string of a SF number.
     *
     * @param num A number to be canonicalized.
     * @return A canonical string of a SF number.
     */
    public static String canonicalNumber(Number num) {

        if (num instanceof Long) {
            return num.toString() + "L";
        } else if (num instanceof Integer) {
            return num.toString();
        } else if (num instanceof Float) {
            return num.toString() + "F";
        } else if (num instanceof Double) {
            return num.toString() + "D";
        } else {
            throw new IllegalArgumentException("canonicalNumber: param" + num
                                               + " is "
                                               + "not a valid number type");
        }
    }

}




See more files for this project here

SmartFrog

SmartFrog (Smart Framework for Object Groups) is a framework for configuring and automatically activating distributed applications. \r\nThe SmartFrog framework is released under LGPL license.\r\nMore info at: www.smartfrog.org

Project homepage: http://sourceforge.net/projects/smartfrog
Programming language(s): Java,XML
License: other

  DNSBindNamedImpl.java
  DNSBindingIP.java
  DNSBindingIPImpl.java
  DNSCollectionImpl.java
  DNSComponent.java
  DNSComponentDeployerImpl.java
  DNSComponentImpl.java
  DNSData.java
  DNSDataImpl.java
  DNSDeployerGui.java
  DNSDeployerGuiImpl.java
  DNSDeployerImpl.java
  DNSException.java
  DNSManager.java
  DNSManagerImpl.java
  DNSModifier.java
  DNSModifierException.java
  DNSModifierImpl.java
  DNSNamed.java
  DNSNamedImpl.java
  DNSOpaqueImpl.java
  DNSOptions.java
  DNSOptionsImpl.java
  DNSRecord.java
  DNSRecordImpl.java
  DNSService.java
  DNSServiceBasicFilterImpl.java
  DNSServiceFilter.java
  DNSServiceImpl.java
  DNSServiceInstance.java
  DNSServiceInstanceImpl.java
  DNSServiceQuery.java
  DNSView.java
  DNSViewImpl.java
  DNSVisitor.java
  DNSZone.java
  DNSZoneImpl.java
  dns.sf
  dnsBinding.sf
  dnsData.sf
  dnsDefault.sf
  dnsDeployer.sf
  dnsNamed.sf
  dnsService.sf
  dnsSubnet.sf
  dnsTest1.sf
  dnsTest2.sf
  dnsTest3.sf
  dnsTest4.sf
  dnsTest5.sf
  dnsTestDeployer1.sf
  dnsTestDeployer2.sf
  dnsTestService1.sf
  dnsView.sf
  dnsZone.sf