Package com.caringo.client.locate

Source Code of com.caringo.client.locate.ZeroconfLocator$NamedServiceListener

/*
*
*/
package com.caringo.client.locate;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.impl.JmDNSImpl;

import org.apache.log4j.Logger;

/**
* ZeroconfLocator implements Locator using Zeroconf (http://www.zeroconf.org/). <br>
* <br>
* Copyright (c) 2008 by Caringo, Inc. -- All rights reserved<br>
* This is free software, distributed under the terms of the New BSD license.<br>
* See the LICENSE.txt file included in this archive.<br>
* <br>
*
* @author jmike
* @created Apr 15, 2007
* @id $Id: ZeroconfLocator.java 927 2008-02-25 16:47:51Z jmike $
*/
public class ZeroconfLocator implements Locator {

    private static final Logger logger = Logger.getLogger(ZeroconfLocator.class);

    private Set<String> poolSet = new HashSet<String>();
    private List<InetSocketAddress> poolList = new ArrayList<InetSocketAddress>();

    private static final String TYPE_SCSP = "_scsp._tcp.local.";
    private static final String SUBTYPE_SCSP = "._sub." + TYPE_SCSP;

    private String clusterName;
    private JmDNS jmdns;
    private SubServiceListener subServiceListener;
    private NamedServiceListener namedServiceListener;

    public ZeroconfLocator(String clusterName) throws IOException {
        this.clusterName = clusterName;
    }

    // /
    // / Locator
    // /

    /**
     * @see com.caringo.client.locate.Locator#foundDead(java.net.InetSocketAddress)
     */
    public synchronized void foundDead(InetSocketAddress addr) {
        String addrIp = toIpString(addr);
        if (poolSet.contains(addrIp)) {
            logger.warn(addr.getAddress() + " was missing, removing from pool.");
            poolSet.remove(addrIp);
            poolList.remove(addr);
        }
        invariant();
    }

    /**
     * @see com.caringo.client.locate.Locator#foundAlive(java.net.InetSocketAddress)
     */
    public synchronized void foundAlive(InetSocketAddress addr) {
        String addrIp = toIpString(addr);
        if (!poolSet.contains(addrIp)) {
            poolList.add(addr);
            poolSet.add(addrIp);
        }
        invariant();
    }

    /**
     * @see com.caringo.client.locate.Locator#locate()
     */
    public InetSocketAddress locate() {
        InetSocketAddress result = null;

        int retries = 5;
        while (poolList.size() == 0 && retries > 0) {
            --retries;
            logger.warn("Pool was empty, re-querying.  " + retries + " retries left.");
            jmdns.list(SUBTYPE_SCSP);
        }

        int memberCount = poolList.size();
        if (memberCount > 0) {
            synchronized (this) {
                if (memberCount > 1) {
                    // rotate to spread the load
                    result = poolList.remove(0);
                    poolList.add(result);
                } else {
                    result = poolList.get(0);
                }
            }
        }
        return result;
    }

    /**
     * @see com.caringo.client.locate.Locator#locateAll()
     */
    public InetSocketAddress[] locateAll() {
        return poolList.toArray(new InetSocketAddress[poolList.size()]);
    }

    /**
     * @throws IOException
     * @see com.caringo.client.locate.Locator#start
     */
    public void start() throws IOException {
        logger.info("ZeroconfLocator starting...");
        jmdns = new JmDNSImpl();
        String queryDomain = getQueryDomain();
        subServiceListener = new SubServiceListener();
        jmdns.addServiceListener(queryDomain, subServiceListener);
        namedServiceListener = new NamedServiceListener();
        jmdns.addServiceListener(TYPE_SCSP, namedServiceListener);
        jmdns.list(queryDomain);
        try {
            Thread.sleep(6000);
        } catch (InterruptedException ex) {
            // no-op
        }
        logger.info("ZeroconfLocator started");
    }

    /**
     * @see com.caringo.client.locate.Locator#stop()
     */
    public void stop() {
        jmdns.close();
        logger.info("ZeroconfLocator stopped");
    }

    // /
    // / ServiceListener
    // /

    class SubServiceListener implements ServiceListener {
        /**
         * @see javax.jmdns.ServiceListener#serviceAdded(javax.jmdns.ServiceEvent)
         */
        public void serviceAdded(ServiceEvent event) {
            // logger.debug("SUBADDED " + event.getType() + " : " +
            // event.getName());
            Pair<String, String> nametype = splitName(event.getName());
            // logger.debug("SUBADDED ?? " + nametype.left + ": " +
            // nametype.right);
            namedServiceListener.resolve(nametype.right, nametype.left);
        }

        /**
         * @see javax.jmdns.ServiceListener#serviceRemoved(javax.jmdns.ServiceEvent)
         */
        public void serviceRemoved(ServiceEvent event) {
            // logger.debug("SUBREMOVED " + event.getType() + " : " +
            // event.getName());
        }

        public void serviceResolved(ServiceEvent event) {
            // logger.debug("SUBRESOLVED " + event.getType() + " : " +
            // event.getName());
        }
    }

    class NamedServiceListener implements ServiceListener {

        private Set<String> pendingResolution = new HashSet<String>();

        public void resolve(String type, String name) {
            pendingResolution.add(name);
            jmdns.requestServiceInfo(type, name, 0);
        }

        public void serviceAdded(ServiceEvent event) {
            // logger.debug("NAMEDADDED " + event.getType() + " : " +
            // event.getName());
            jmdns.requestServiceInfo(event.getType(), event.getName(), 0);
        }

        public void serviceRemoved(ServiceEvent event) {
            String svcName = event.getName();
            // logger.debug("NAMEDREMOVED " + event.getType() + " : " +
            // svcName);
            ServiceInfo svcInfo = event.getInfo();
            if (svcInfo != null) {
                String svcHost = svcInfo.getHostAddress();
                if (poolSet.contains(svcHost)) {
                    logger.debug("Removed" + svcName);
                    foundDead(new InetSocketAddress(svcHost, svcInfo.getPort()));
                }
                if (pendingResolution.contains(svcName)) {
                    pendingResolution.remove(svcName);
                }
            }
        }

        public void serviceResolved(ServiceEvent event) {
            // logger.debug("NAMEDRESOLVED " + event.getType() + " : " +
            // event.getName());
            String name = event.getName();
            ServiceInfo info = event.getInfo();
            if (info != null) {
                if (pendingResolution.contains(name)) {
                    String svcHost = info.getHostAddress();
                    if (!poolSet.contains(svcHost)) {
                        logger.debug("Resolved " + name + " to " + svcHost);
                        foundAlive(new InetSocketAddress(svcHost, info.getPort()));
                        pendingResolution.remove(name);
                    }
                }
            } else {
                jmdns.requestServiceInfo(event.getType(), name, 0);
            }
        }

    }

    // /
    // / Support
    // /

    private Pair<String, String> splitName(String domain) {
        int dotIdx = domain.indexOf(".");
        if (dotIdx == -1) {
            return new Pair<String, String>(domain, null);
        } else {
            String name = domain.substring(0, dotIdx);
            String type = domain.substring(dotIdx + 1);
            return new Pair<String, String>(name, type);
        }
    }

    private void invariant() {
        if (poolSet.size() != poolList.size()) {
            logger.warn("Pool set and list size mismatch, rebuilding set");
            poolSet.clear();
            for (InetSocketAddress addr : poolList) {
                poolSet.add(toIpString(addr));
            }
        }
    }

    private String getQueryDomain() {
        return clusterName + SUBTYPE_SCSP;
    }

    /**
     * Extracts the IP address as a string from an InetSocketAddress.
     *
     * @param addr
     * @return
     */
    private String toIpString(InetSocketAddress addr) {
        return addr.getAddress().getHostAddress();
    }

    @Override
    public String toString() {
        return "ZeroconfLocator (cluster='" + clusterName + "')";
    }

}
TOP

Related Classes of com.caringo.client.locate.ZeroconfLocator$NamedServiceListener

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.