/**
 * @(#)$Id: DetectorUtil.java,v 1.1.2.4 2004/01/09 07:56:21 telrod Exp $
 *
 * This code is PROPRIETARY AND CONFIDENTIAL to Vocalocity, Inc.
 * -- DO NOT RE-DISTRIBUTE THIS SOURCE CODE WITHOUT EXPRESS PERMISSION. --
 *
 * This source code is Copyright (c) 2003 by Vocalocity, Inc.
 * All Rights Reserved.
 *
 * The source code for this program is not published or
 * otherwise divested of its trade secrets, irrespective
 * of what has been deposited with the US Copyright Office.
 *
 */
package test.detection;

import org.apache.log4j.Level;
import org.jboss.logging.Logger;
import org.jboss.remoting.network.NetworkRegistry;
import org.jboss.remoting.network.NetworkInstance;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.ident.Identity;
import org.jboss.remoting.detection.multicast.MulticastDetector;
import org.jboss.remoting.detection.Detector;
import org.jboss.remoting.detection.Detection;
import org.jboss.remoting.detection.AbstractDetector;
import org.jboss.remoting.detection.jndi.JNDIDetector;
import org.jboss.remoting.transport.Connector;
import org.w3c.dom.Document;

import javax.management.*;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.util.StringTokenizer;


/**
 * @author <a href="mailto:telrod@vocalocity.net">Tom Elrod</a>
 * @version $Revision: 1.1.2.4 $
 */
public class DetectorUtil implements NotificationListener
{
    /** multicast **/
    public static final String TYPE_MULTICAST = "multicast";
    /** jndi **/
    public static final String TYPE_JNDI = "jndi";
    /** 2410 **/
    public static final int DEFAULT_PORT = 2410;
    /** localhost **/
    public static final String DEFAULT_HOST = "localhost";
    /** JBOSS **/
    public static final String DEFAULT_DOMAIN = "JBOSS";

    private String contextFactory = "org.jnp.interfaces.NamingContextFactory";
    private String urlPackage = "org.jboss.naming:org.jnp.interfaces";

    private String type = TYPE_MULTICAST;
    private int port = DEFAULT_PORT;
    private String host = DEFAULT_HOST;
    private String[] domains = {DEFAULT_DOMAIN};

    private List detectedServers = new ArrayList();

    public DetectorUtil()
    {
    }

    public DetectorUtil(String domain)
    {
        this(domain, TYPE_MULTICAST, DEFAULT_PORT, DEFAULT_HOST);
    }

    public DetectorUtil(String domain, String type)
    {
       this(domain, type, DEFAULT_PORT, DEFAULT_HOST);
    }

    public DetectorUtil(String domain, String type, int port)
    {
        this(domain, type, port, DEFAULT_HOST);
    }

    public DetectorUtil(String domain, String type, int port, String host)
    {
       setDomains(domain);
        this.type = type;
        this.port = port;
        this.host = host;
    }

   private void setDomains(String domain)
   {
      StringTokenizer token = new StringTokenizer(domain, ",");
      domains = new String[token.countTokens()];
      int counter = 0;
      while(token.hasMoreTokens())
      {
         domains[counter] = token.nextToken();
         counter++;
      }
   }

   public void start()
        {
            try
            {

//                org.apache.log4j.BasicConfigurator.configure();
//                org.apache.log4j.Category.getRoot().setLevel(Level.DEBUG);
//                Logger log = Logger.getLogger(getClass());

                System.setProperty("jboss.identity", String.valueOf(System.currentTimeMillis()));

                MBeanServer server = MBeanServerFactory.createMBeanServer();

                NetworkRegistry registry = NetworkRegistry.getInstance();
                server.registerMBean(registry, new ObjectName("remoting:type=NetworkRegistry"));

                InvokerLocator locator = new InvokerLocator("socket://localhost");
                //ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
                //SocketServerInvoker invokerSvr = new SocketServerInvoker(clsLoader, locator);
                //ObjectName objName = new ObjectName("jboss.remoting:type=SocketServerInvoker");
                //server.registerMBean(invokerSvr, objName);
                //invokerSvr.start();

                Connector connector = new Connector();
                StringBuffer buf = new StringBuffer();
                buf.append("<?xml version=\"1.0\"?>\n");
                buf.append("<handlers>\n");
                buf.append("  <handler subsystem=\"mock\">org.jboss.remoting.transport.mock.MockServerInvocationHandler</handler>\n");
                buf.append("</handlers>\n");
                Document xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(buf.toString().getBytes()));
                connector.setInvokerLocator(locator.getLocatorURI());
                connector.setConfiguration(xml.getDocumentElement());
                ObjectName obj = new ObjectName("jboss.remoting:type=Connector,transport=" + locator.getProtocol());
                server.registerMBean(connector, obj);
                //connector.create();
                connector.start();

                AbstractDetector detector = null;
                ObjectName objName = null;

                if(type.equals(TYPE_MULTICAST))
                {
                    MulticastDetector mdet = new MulticastDetector();
                    mdet.setPort(port);
                    detector = mdet;
                    objName = new ObjectName("remoting:type=Detector,transport=multicast");
                }
                else if(type.equals(TYPE_JNDI))
                {
                    JNDIDetector jdet = new JNDIDetector();
                    jdet.setPort(port);
                    jdet.setHost(host);
                    jdet.setContextFactory(contextFactory);
                    jdet.setURLPackage(urlPackage);
                    detector = jdet;
                    objName = new ObjectName("remoting:type=Detector,transport=jndi");
                }

                server.registerMBean(detector, objName);
                server.addNotificationListener(objName, this, null, null);
                // add domains to look for
                for(int x = 0; x < domains.length; x++)
                {
                   detector.addDomain(domains[x]);
                }
               //DEBUG - Set local domain name
               //Identity.setDomain("FOO");
               //END DEBUG
                detector.start();
                System.err.println("Starting Detector");

               //DEBUG - Test removing domain
               //Thread.sleep(5000);
               //detector.removeDomain("FOO");
               //END DEBUG
            }
            catch(Exception ex)
            {
                System.err.println("Error creating and starting DetectorUtil.");
                ex.printStackTrace();
            }
        }

        public static void main(String[] args)
        {
            DetectorUtil test = null;

            if(args.length == 1)
            {
               String domains = args[0];
               test = new DetectorUtil(domains);
            }
            else if(args.length == 2)
            {
               String domains = args[0];
               String type = args[1];
               test = new DetectorUtil(domains, type);

            }
            else if(args.length == 3)
            {
               String domains = args[0];
               String type = args[1];
               int port = Integer.parseInt(args[2]);
               test = new DetectorUtil(domains, type, port);
            }
            else if(args.length == 4)
   {
      String domains = args[0];
      String type = args[1];
      int port = Integer.parseInt(args[2]);
      String host = args[3];
      test = new DetectorUtil(domains, type, port, host);
   }
            else
            {
                test = new DetectorUtil();
                System.out.println("Using default domain (" + test.getDomains() +
                                   ") default type (" + test.getTransport() +
                                   ") and default port (" + test.getPort() + ") and " +
                                   "default host (" + test.getHost() + ")" +
                                   "\nCan enter domain, type (multicast, jndi), port, and/or host via command line." +
                                   "\nFor multiple domains, seperate by comma (and no spaces)");
            }

            test.start();


        }

   private String getDomains()
   {
      StringBuffer buffer = new StringBuffer();
      buffer.append(domains[0]);
      for(int x = 1; x < domains.length; x++)
      {
         buffer.append(", " + domains[x]);
      }
      return buffer.toString();
   }

   private String getHost()
    {
        return host;
    }

    private int getPort()
    {
        return port;
    }

    private String getTransport()
    {
        return type;
    }

   /**
    * Callback method from the broadcaster MBean this listener implementation
    * is registered to.
    *
    * @param notification the notification object
    * @param handback     the handback object given to the broadcaster
    *                     upon listener registration
    */
   public void handleNotification(Notification notification, Object handback)
   {
      Detection det = null;

      if(notification != null)
      {
         det = (Detection)notification.getUserData();
         if(Detector.SERVER_FOUND.equals(notification.getType()))
         {
            System.out.println("\nNew server detected:\nIdentity: " + det.getIdentity() + getLocators(det));
            detectedServers.add(det);
            printDetectedServerList();
         }
         else if(Detector.SERVER_LOST.equals(notification.getType()))
         {
            System.out.println("\nServer lost:\nIdentity: " + det.getIdentity() + getLocators(det));
            detectedServers.remove(det);
            printDetectedServerList();
         }
         else
         {
            System.out.println("Error processing notification.  Notification type " + notification.getType() +
                  " is not known.");
         }
      }

   }

   private void printDetectedServerList()
   {
      System.out.println("\nCurrent list of known servers:");
      Iterator itr = detectedServers.iterator();
      while(itr.hasNext())
      {
         Detection det = (Detection)itr.next();
         System.out.println("Identity: " + det.getIdentity() + getLocators(det));
      }
   }

   private String getLocators(Detection det)
   {
      StringBuffer retStr = new StringBuffer("\n");
      if(det != null)
      {
         InvokerLocator[] locators = det.getLocators();
         if(locators != null)
         {
            for(int x = 0; x < locators.length; x++)
            {
               retStr.append("\t" + locators[x] + "\n");
            }
         }
      }
      return retStr.toString();
   }


}
