/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 * 
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits r?serv?s.
 * Ce logiciel est propri?t? de Sun Microsystems, Inc.
 * Distribu? par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)MfDiscoveryCommon.java 1.7     04/09/27 SMI"
 *
 */


package com.sun.mfwk.discovery;

// J2SE
import java.util.*;
import java.net.*;
import java.io.*;
import java.util.logging.Logger;
import java.util.logging.Level;

// Jesma Discovery stuff
import com.sun.mfwk.discovery.*;

// JESMA log
import com.sun.mfwk.util.log.MfLogService;

//BS TBD throws exception....
abstract class MfDiscoveryCommon extends java.net.MulticastSocket {    


// ----------------------------------------------------------
// Constructor
// ----------------------------------------------------------
    public MfDiscoveryCommon(String multicastGroup, int multicastPort) throws IOException
  {
	// ------------------------
	// Set multicastSocket port
        // ------------------------
	super(multicastPort) ;
        logger.entering("MfDiscoveryCommon", "MfDiscoveryCommon (after super)");        
	logger.finer("group = " + multicastGroup  + ", " + "port  = " + multicastPort);


	// ------------------------
	// Set multicastGroup
	// ------------------------
	try {
            this.multicastGroup = InetAddress.getByName(multicastGroup) ;
	}
	catch(UnknownHostException e) {
            logger.finer("constructor");
            logger.throwing(null, null,e);
	}

	// ------------------------
	// Set multicast Port
	// ------------------------
	this.multicastPort  = multicastPort  ;

	// ------------------------
	// Set local host
	// ------------------------
	try
	{
		localHost     = InetAddress.getLocalHost() ;
		localHostName = InetAddress.getLocalHost(). getHostName() ;

		selectedHost     = InetAddress.getLocalHost() ;
		selectedHostName = InetAddress.getLocalHost(). getHostName() ;
	}
	catch(UnknownHostException e)
	{
            logger.finer("constructor");
            logger.throwing(null, null,e);
	}
        logger.exiting("MfDiscoveryCommon", "MfDiscoveryCommon");        	
  }


// ----------------------------------------------------------
// ttl
// ----------------------------------------------------------
  /**
   * Set the default time-to-live for multicast packets sent out on this socket. 
   * The TTL sets the IP time-to-live for DatagramPackets sent to a MulticastGroup, 
   * which specifies how many "hops" that the packet will be forwarded on the network 
   * before it expires. 
   *
   * The ttl must be in the range 0 < ttl <= 255 or an IllegalArgumentException will be thrown.
   */
    public void setTimeToLive(int ttl) throws IOException {
	try {
		super.setTimeToLive(ttl) ;
	} catch (IOException e) {		
	 	logger.finer("Unable to set Time-to-live to" + ttl);	
		logger.throwing (null,null, e) ;
	}
    	logger.info("Set Time-to-live to " + ttl);	
        this.ttl = ttl ;
        logger.exiting("MfDiscoveryCommon", "setTimeToLive");        	
  }

   /**
   * Get the time-to-live for multicast packets sent out on this socket. 
   * The TTL sets the IP time-to-live for DatagramPackets sent to a MulticastGroup, 
   * which specifies how many "hops" that the packet will be forwarded on the network 
   * before it expires. 
   *
   * The ttl must be in the range 0 < ttl <= 255 or an IllegalArgumentException will be thrown.
   */
   public int getTimeToLive() {
        logger.entering("MfDiscoveryCommon", "getTimeToLive");        	       
        logger.exiting("MfDiscoveryCommon", "getTimeToLive");        	
        return ttl ;
  }  
  
// ----------------------------------------------------------
// start/stop listening
// ----------------------------------------------------------

  void connectToGroup() throws IOException {
        logger.entering("MfDiscoveryCommon", "connectToGroup");        	       
	// ------------------------
	// Join the group
	// ------------------------
	logger.info("join Group " + multicastGroup);	
	joinGroup(multicastGroup);
        logger.exiting("MfDiscoveryCommon", "connectToGroup");        	       
  }

  void disconnectFromGroup() throws IOException {
        logger.entering("MfDiscoveryCommon", "disconnectFromGroup");        	       
	// ------------------------
	// Leave the group
	// ------------------------
	logger.info("leave Group " + multicastGroup);	
	leaveGroup(multicastGroup);
        logger.exiting("MfDiscoveryCommon", "disconnectFromGroup");        	               
  }

// ----------------------------------------------------------
// get Host 
// ----------------------------------------------------------
  public String getLocalHostName()
  {
        return localHostName ;
  }

  public InetAddress getLocalHostAddr()
  {
        return localHost ;
  }

  public String getHostName()
  {
        return selectedHostName ;
  }

  public InetAddress getHostAddr()
  {
        return selectedHost ;
  }




// ----------------------------------------------------------
// variables
// ----------------------------------------------------------

        /* Multicast */
        protected int                   multicastPort           ;
        protected InetAddress           multicastGroup          ;

        protected InetAddress           localHost               ;
        protected String           	localHostName           ;
        protected InetAddress           selectedHost            ;
        protected String           	selectedHostName        ;

        private int			ttl			= 1 ;
	private int			defaultTtl		= 1 ;

      	protected boolean		stopListeningThread     = false ;
	Thread                          rcvThread               = null ;

        /* Tracing utility. */
        protected static Logger logger = MfLogService.getLogger("Discovery");
        



// ------------------------------------------
// protocol implemented by the derived object 
// ------------------------------------------
   abstract void applyProtocol();

// -------------------------------------------------------------
// Starts/Stops the thread that implements the protocol to apply 
// -------------------------------------------------------------
    public void startListeningThread() {
        logger.entering("MfDiscoveryCommon", "startListeningThread");        	       

 	// -----------------------
 	// Create a thread to get responses
 	// ------------------------
	ReceivedMsgObj rcvMsg    = new ReceivedMsgObj(this) ;
	rcvThread = new Thread (rcvMsg) ;
        
        logger.info("Starting listening thread");	
	rcvThread.start();
        logger.exiting("MfDiscoveryCommon", "startListeningThread");        	               
    }

    public void stopListeningThread() {
        logger.entering("MfDiscoveryCommon", "stopListeningThread");        	       
        stopListeningThread     = true;
       	try {
            rcvThread.join();
        } catch (InterruptedException ie) {
            logger.warning ("Discovery listening thread has been interrupted");
        }           
    }

// ----------------------------------------------------------
// Inner class (listening thread)
// ----------------------------------------------------------
   class ReceivedMsgObj implements Runnable {

       private MfDiscoveryCommon responder;

       ReceivedMsgObj(MfDiscoveryCommon myresponder){
	   this.responder = myresponder;
       }

       public void run(){
	       responder.applyProtocol();
       }
   }        
}

