Package org.huihoo.willow.core

Source Code of org.huihoo.willow.core.StandardServer

//----------------------------BEGIN LICENSE----------------------------
/*
* Willow : the Open Source WorkFlow Project
* Distributable under GNU LGPL license by gun.org
*
* Copyright (C) 2004-2010 huihoo.org
* Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com>
*
* ====================================================================
* Project Homepage : http://www.huihoo.org/willow
* Source Forge     : http://sourceforge.net/projects/huihoo
* Mailing list     : willow@lists.sourceforge.net
*/
//----------------------------END  LICENSE-----------------------------
package org.huihoo.willow.core;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.AccessControlException;
import java.util.Random;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.willow.Globals;
import org.huihoo.willow.Lifecycle;
import org.huihoo.willow.LifecycleException;
import org.huihoo.willow.LifecycleListener;
import org.huihoo.willow.Server;
import org.huihoo.willow.ServerFactory;
import org.huihoo.willow.Service;
import org.huihoo.willow.util.LifecycleSupport;
import org.huihoo.willow.util.StringManager;


/**
* @author reic
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public final class StandardServer implements Lifecycle, Server
{
  private static Log log = LogFactory.getLog(StandardServer.class);

  /**
   * ServerLifecycleListener classname.
   */
  private static String SERVER_LISTENER_CLASS_NAME ="org.huihoo.willow.core.ServerLifecycleListener";

  // ------------------------------------------------------------ Constructor

  /**
   * Construct a default instance of this class.
   */
  public StandardServer()
  {
    super();
    ServerFactory.setServer(this);
  }

  // ----------------------------------------------------- Instance Variables

  /**
   * Debugging detail level.
   */
  private int debug = 0;

  /**
   * Descriptive information about this NamingServer implementation.
   */
  private static final String info = "org.huihoo.willow.core.StandardServer/1.0";

  /**
   * The lifecycle event support for this component.
   */
  private LifecycleSupport lifecycle = new LifecycleSupport(this);

  /**
   * The port number on which we wait for shutdown commands.
   */
  private int port = 8023;

  /**
   * A random number generator that is <strong>only</strong> used if
   * the shutdown command string is longer than 1024 characters.
   */
  private Random random = null;

  /**
   * The set of Services associated with this NamingServer.
   */
  private Service services[] = new Service[0];

  /**
   * The shutdown command string we are looking for.
   */
  private String shutdown = "SHUTDOWN";

  /**
   * The string manager for this package.
   */
  private static final StringManager sm = StringManager.getManager(Constants.PACKAGE);

  /**
   * Has this component been started?
   */
  private boolean started = false;

  /**
   * The property change support for this component.
   */
  protected PropertyChangeSupport support = new PropertyChangeSupport(this);

  // ------------------------------------------------------------- Properties

  /**
   * Return the debugging detail level.
   */
  public int getDebug()
  {

    return (this.debug);

  }

  /**
   * Set the debugging detail level.
   *
   * @param debug The new debugging detail level
   */
  public void setDebug(int debug)
  {

    this.debug = debug;

  }


  /**
   * Return descriptive information about this NamingServer implementation and
   * the corresponding version number, in the format
   * <code>&lt;description&gt;/&lt;version&gt;</code>.
   */
  public String getInfo()
  {

    return (info);

  }

  /**
   * Return the port number we listen to for shutdown commands.
   */
  public int getPort()
  {

    return (this.port);

  }

  /**
   * Set the port number we listen to for shutdown commands.
   *
   * @param port The new port number
   */
  public void setPort(int port)
  {

    this.port = port;

  }

  /**
   * Return the shutdown command string we are waiting for.
   */
  public String getShutdown()
  {

    return (this.shutdown);

  }

  /**
   * Set the shutdown command we are waiting for.
   *
   * @param shutdown The new shutdown command
   */
  public void setShutdown(String shutdown)
  {

    this.shutdown = shutdown;

  }

  // --------------------------------------------------------- NamingServer Methods

  /**
   * Add a new Service to the set of defined Services.
   *
   * @param service The Service to be added
   */
  public void addService(Service service)
  {

    service.setServer(this);

    synchronized (services)
    {
      Service results[] = new Service[services.length + 1];
      System.arraycopy(services, 0, results, 0, services.length);
      results[services.length] = service;
      services = results;

      if (started && (service instanceof Lifecycle))
      {
        try
        {
          ((Lifecycle) service).start();
        }
        catch (LifecycleException e)
        {
          ;
        }
      }

      // Report this property change to interested listeners
      support.firePropertyChange("service", null, service);
    }

  }

  /**
   * Wait until a proper shutdown command is received, then return.
   */
  public void await()
  {

    // Set up a server socket to wait on
    ServerSocket serverSocket = null;
    try
    {
      port=(port<=0)?Globals.PORT_SERVER_COMMAND:port;
      serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
    }
    catch (IOException e)
    {
      System.err.println("StandardServer.await: create[" + port + "]: " + e);
      e.printStackTrace();
      System.exit(1);
    }

    // Loop waiting for a connection and a valid command
    while (true)
    {

      // Wait for the next connection
      Socket socket = null;
      InputStream stream = null;
      try
      {
        socket = serverSocket.accept();
        socket.setSoTimeout(10 * 1000); // Ten seconds
        stream = socket.getInputStream();
      }
      catch (AccessControlException ace)
      {
        System.err.println("StandardServer.accept security exception: " + ace.getMessage());
        continue;
      }
      catch (IOException e)
      {
        System.err.println("StandardServer.await: accept: " + e);
        e.printStackTrace();
        System.exit(1);
      }

      // Read a set of characters from the socket
      StringBuffer command = new StringBuffer();
      int expected = 1024; // Cut off to avoid DoS attack
      while (expected < shutdown.length())
      {
        if (random == null)
          random = new Random(System.currentTimeMillis());
        expected += (random.nextInt() % 1024);
      }
      while (expected > 0)
      {
        int ch = -1;
        try
        {
          ch = stream.read();
        }
        catch (IOException e)
        {
          System.err.println("StandardServer.await: read: " + e);
          e.printStackTrace();
          ch = -1;
        }
        if (ch < 32) // Control character or EOF terminates loop
          break;
        command.append((char) ch);
        expected--;
      }

      // Close the socket now that we are done with it
      try
      {
        socket.close();
      }
      catch (IOException e)
      {
        ;
      }

      // Match against our command string
      boolean match = command.toString().equals(shutdown);
      if (match)
      {
        break;
      }
      else
        System.err.println(
          "StandardServer.await: Invalid command '" + command.toString() + "' received");

    }

    // Close the server socket and return
    try
    {
      serverSocket.close();
    }
    catch (IOException e)
    {
      ;
    }

  }

  /**
   * Return the specified Service (if it exists); otherwise return
   * <code>null</code>.
   *
   * @param name Name of the Service to be returned
   */
  public Service findService(String name)
  {

    if (name == null)
    {
      return (null);
    }
    synchronized (services)
    {
      for (int i = 0; i < services.length; i++)
      {
        if (name.equals(services[i].getName()))
        {
          return (services[i]);
        }
      }
    }
    return (null);

  }

  /**
   * Return the set of Services defined within this NamingServer.
   */
  public Service[] findServices()
  {

    return (services);

  }

  /**
   * Remove the specified Service from the set associated from this
   * NamingServer.
   *
   * @param service The Service to be removed
   */
  public void removeService(Service service)
  {

    synchronized (services)
    {
      int j = -1;
      for (int i = 0; i < services.length; i++)
      {
        if (service == services[i])
        {
          j = i;
          break;
        }
      }
      if (j < 0)
        return;
      if (services[j] instanceof Lifecycle)
      {
        try
        {
          ((Lifecycle) services[j]).stop();
        }
        catch (LifecycleException e)
        {
          ;
        }
      }
      int k = 0;
      Service results[] = new Service[services.length - 1];
      for (int i = 0; i < services.length; i++)
      {
        if (i != j)
          results[k++] = services[i];
      }
      services = results;

      // Report this property change to interested listeners
      support.firePropertyChange("service", service, null);
    }

  }

  // --------------------------------------------------------- Public Methods

  /**
   * Add a property change listener to this component.
   *
   * @param listener The listener to add
   */
  public void addPropertyChangeListener(PropertyChangeListener listener)
  {

    support.addPropertyChangeListener(listener);

  }

  /**
   * Remove a property change listener from this component.
   *
   * @param listener The listener to remove
   */
  public void removePropertyChangeListener(PropertyChangeListener listener)
  {

    support.removePropertyChangeListener(listener);

  }

  /**
   * Return a String representation of this component.
   */
  public String toString()
  {

    StringBuffer sb = new StringBuffer("StandardServer[");
    sb.append(getPort());
    sb.append("]");
    return (sb.toString());

  }

  // ------------------------------------------------------ Lifecycle Methods

  /**
   * Add a LifecycleEvent listener to this component.
   *
   * @param listener The listener to add
   */
  public void addLifecycleListener(LifecycleListener listener)
  {

    lifecycle.addLifecycleListener(listener);

  }

  /**
   * Get the lifecycle listeners associated with this lifecycle. If this
   * Lifecycle has no listeners registered, a zero-length array is returned.
   */
  public LifecycleListener[] findLifecycleListeners()
  {

    return lifecycle.findLifecycleListeners();

  }

  /**
   * Remove a LifecycleEvent listener from this component.
   *
   * @param listener The listener to remove
   */
  public void removeLifecycleListener(LifecycleListener listener)
  {

    lifecycle.removeLifecycleListener(listener);

  }

  /**
   * Prepare for the beginning of active use of the public methods of this
   * component.  This method should be called before any of the public
   * methods of this component are utilized.  It should also send a
   * LifecycleEvent of type START_EVENT to any registered listeners.
   *
   * @exception LifecycleException if this component detects a fatal error
   *  that prevents this component from being used
   */
  public void start() throws LifecycleException
  {

    // Validate and update our current component state
    if (started)
    {
      log.debug(sm.getString("standardServer.start.started"));
      return;
    }
   
    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

    lifecycle.fireLifecycleEvent(START_EVENT, null);
    started = true;

    // Start our defined Services
    synchronized (services)
    {
      for (int i = 0; i < services.length; i++)
      {
        if (services[i] instanceof Lifecycle)
        {
          ((Lifecycle) services[i]).start();
        }
      }
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

  }

  /**
   * Gracefully terminate the active use of the public methods of this
   * component.  This method should be the last one called on a given
   * instance of this component.  It should also send a LifecycleEvent
   * of type STOP_EVENT to any registered listeners.
   *
   * @exception LifecycleException if this component detects a fatal error
   *  that needs to be reported
   */
  public void stop() throws LifecycleException
  {

    // Validate and update our current component state
    if (!started)
    {
      return;
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

    lifecycle.fireLifecycleEvent(STOP_EVENT, null);
    started = false;

    // Stop our defined Services
    for (int i = 0; i < services.length; i++)
    {
      if (services[i] instanceof Lifecycle)
      {
        ((Lifecycle) services[i]).stop();
      }
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
  }

}
TOP

Related Classes of org.huihoo.willow.core.StandardServer

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.