Package JACE.netsvcs.Time

Source Code of JACE.netsvcs.Time.TSClerkProcessor

package JACE.netsvcs.Time;

import java.net.*;
import java.io.*;
import java.util.*;

import JACE.ASX.TimeValue;
import JACE.Connection.*;
import JACE.OS.*;
import JACE.Reactor.*;
import JACE.Misc.*;

/**
* Clerk used to query a number of time servers, compute the average
* of the time differences, and report it with a sequence number.  This
* can be used to adjust the current local time accordingly.
* <P>
* <B>Valid command line arguments:</B>
* <PRE>
*   -h (host name:port)   Specify a time server to contact
*   -t (time in seconds)  Specify how often to query the servers
*                         (Defaults to five minutes)
*   -d                    Enable debugging messages
* </PRE>
*/
public class TSClerkProcessor implements EventHandler, Runnable
{
  /**
   * Prints out the valid command line arguments.  See the class
   * description for more information. 
   */
  public void printUsage ()
  {
    ACE.ERROR ("Valid options:");
    ACE.ERROR ("-h <host name>:<port>  Specify a time server to contact");
    ACE.ERROR ("-t <time in seconds>   How often to query the servers");
    ACE.ERROR ("-d                     Enable debugging messages");
  }

  /**
   * Parses the command line arguments.  See the class description
   * for more information.
   */
  protected int parseArgs (String args[])
  {
    GetOpt opt = new GetOpt (args, "h:t:d", true);
    for (int c; (c = opt.next ()) != -1; )
      {
  switch (c)
    {
      // Specify a hostname:port pair to query
    case 'h':
      if (newHandler (opt.optarg ()) == -1) {
        printUsage ();
        return -1;
      }
      break;
      // Specify time interval to query servers
    case 't':
      int sec = Integer.parseInt (opt.optarg ());
      updateInterval_ = new TimeValue (sec);
      break;
    case 'd':
      ACE.enableDebugging ();
      ACE.DEBUG ("Debugging is enabled");
      break;
    default:
      ACE.ERROR ("Unknown argument: " + (char)c);
      printUsage ();
      return -1;
    }
      }
    return 0;
  }

  /**
   * Safely shut down the clerk and all its handlers.
   */
  public synchronized void close ()
  {
    if (!done_) {
      done_ = true;
      tq_.cancelTimer (this);

      for (int i = 0; i < handlerSet_.size (); i++) {
  TSClerkHandler h = (TSClerkHandler)handlerSet_.elementAt (i);
 
  h.close ();
      }
    }
  }

  /**
   * Called by the JVM when the clerk is run in its own thread.  If the
   * TimerQueue provided to (or created by) this TSClerkProcessor isn't
   * running its event loop, it will be run in this thread (by calling
   * handleEvents ()).
   *
   *@see JACE.Reactor.TimerQueue
   */
  public void run ()
  {
    if (handlerSet_.size () == 0) {
      ACE.DEBUG ("No servers are registered.  Call init first.");
      return;
    }

    if (!tq_.eventLoopRunning ())
      tq_.handleEvents ();
  }

  /**
   * Initialize this TSClerkProcessor with command line arguments.  See
   * the class description for more information.  This also schedules
   * a timeout with the timer queue for when to query the servers.
   *
   *@return -1 on failure, 0 on success
   */
  public int init (String args[])
  {
    if (args.length < 2) {
      printUsage ();
      return -1;
    }

    if (parseArgs (args) == -1)
      return -1;

    if (handlerSet_.size () == 0) {
      ACE.ERROR ("No servers are registered.");
      done_ = true;
      return -1;
    }

    if (tq_ == null)
      tq_ = new TimerQueue (true);

    tq_.scheduleTimer (this,
           "Time Service Processor",
           TimeValue.zero,
           updateInterval_);

    return 0;
  }

  /**
   * Called by TSClerkHandler instances when they need to connect
   * (or reconnect) to a server.  This uses Connector to make the
   * connection.
   *
   *@param handler TSClerkHandler to connect to the server
   *@param host name of the service
   *@param port port to connect to on the server
   */
  void connectHandler (TSClerkHandler handler,
           String host,
           int port)
  {
    // Don't let handlers reconnect if we are in the process of closing
    if (done_)
      return;

    ACE.DEBUG ("Connecting handler to " + host + " on port " + port);
    try {

      Connector c = new Connector ();
      c.open (host, port);
      c.connect (handler);

    } catch (UnknownHostException e) {
      synchronized (this) {
  handlerSet_.removeElement (handler);
      }
      ACE.ERROR (e);
    } catch (SocketException e) {
      ACE.ERROR (e);
    } catch (InstantiationException e) {
      ACE.ERROR (e);
    } catch (IllegalAccessException e) {
      ACE.ERROR (e);
    } catch (IOException e) {
      ACE.ERROR (e);
    }
  }

  /**
   * Create a new TSClerkHandler for the given (host name):(port)
   * combination.  See the class description for more information about
   * providing a host names and ports on the command line.
   *
   *@param hostAndPort String with the host name and port separated by
   *                   a colon.
   *@return -1 on failure, 0 on success
   */
  protected int newHandler (String hostAndPort)
  {
    int colon = hostAndPort.lastIndexOf (':');

    if (colon < 1) {
      ACE.ERROR ("Invalid -h <host>:<port> parameter: " + hostAndPort);
      return -1;
    }

    int port = Integer.parseInt (hostAndPort.substring (colon + 1));
    String host = hostAndPort.substring (0, colon);

    ACE.DEBUG ("New handler for server " + host + " on port " + port);

    TSClerkHandler handler = new TSClerkHandler (this, host, port);
    handlerSet_.addElement (handler);

    return 0;
  }

  /**
   * Have each TSClerkHandler query its time server, average the results,
   * and set the timeStatus accordingly.  This is called by the
   * TimerQueue when appropriate.  The interval can be specified on the
   * command line.
   */
  public synchronized int handleTimeout (TimeValue tv, Object obj)
  {
    if (done_)
      return -1;

    // Increment the sequence number
    int sequenceNumber = status_.sequenceNumber () + 1;
    Enumeration handlers = handlerSet_.elements ();

    long total = 0;
    int count = 0;

    // Use each handler to query its server, collecting the time
    // difference information.
    while (handlers.hasMoreElements ()) {
      TSClerkHandler h = (TSClerkHandler)handlers.nextElement ();

      if (h.sendRequest () < 0)
  continue;

      total += h.delta ();
      count++;
    }

    if (count == 0) {
      ACE.ERROR ("Could not reach any time servers, will keep trying.");     
      return 0;
    }

    timeStatus (new TimeInfo (sequenceNumber, total / count));

    ACE.DEBUG ("Status: " + timeStatus ());

    return 0;
  }

  /**
   * Return the current sequence number and time difference pair.
   */
  public synchronized TimeInfo timeStatus ()
  {
    return status_;
  }

  /**
   * Set the current sequence number and time difference pair.
   */
  protected synchronized void timeStatus (TimeInfo status)
  {
    status_ = status;
  }

  /**
   * Default constructor.  Results in this TSClerkProcessor creating
   * a new timer queue which runs in its own thread.  Thus, this
   * TSClerkProcessor runs in its own thread.
   */
  public TSClerkProcessor ()
  {
    // Effectively runs in its own thread because of the timer queue
  }

  /**
   * Constructor allowing the timer queue to be specified.  If the timer
   * queue isn't already running, the caller is responsible for calling
   * handleEvents to start the clerk.  Be careful since the querying
   * process for the servers may take a while.
   *
   *@param queue TimerQueue to register with
   */
  public TSClerkProcessor (TimerQueue queue)
  {
    tq_ = queue;
  }

  private boolean done_ = false;

  // List of the TSClerkHandlers this uses to maintain its
  // server connections.
  private Vector handlerSet_ = new Vector ();
  private TimerQueue tq_ = null;

  // Default is every five minutes
  private TimeValue updateInterval_ = new TimeValue (300, 0);

  TimeInfo status_ = new TimeInfo ();
}
TOP

Related Classes of JACE.netsvcs.Time.TSClerkProcessor

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.