/*
 * Copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */
package examples.rmi.stock;

import weblogic.rmi.*;
import weblogic.rmi.server.*;
import weblogic.rmi.registry.LocateRegistry;
import java.util.*;

/**
 * This class is used with the WebLogic RMI Stock example package.
 * The StockServer supplies information about stocks to its
 * applet clients. It keeps a Vector of those stocks of interest
 * to each of its clients, and it keeps a Vector of all those
 * clients that have registered interest in stock changes. When
 * a stock price changes, it notifies each client that has registered
 * an interest in the change.
 * <p>
 * The classes in this package have been adapted to work with
 * WebLogic RMI from WebLogic. To run this example, see
 * the <a href=Package-examples.rmi.stock.html>package
 * description</a>.
 *
 * @author Adapted 1997 by WebLogic, Inc.
 */
public class StockServer extends UnicastRemoteObject implements StockWatch, Runnable {
  
  public final static String host="localhost";
  public final static String port="7001";
  public final static String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";
  /** Table that maps StockNotify objects to a vector of stocks. */
  private Hashtable notifyTable = new Hashtable();
  /** Table that maps stock names to stock update info. */
  private Hashtable stockTable = new Hashtable();
  /** Thread for notifying watchers of stock updates. */
  private Thread notifier = null;
  
  private static String name[] = { "Sun", "HP", "Microsoft", "DEC","Novell",
                                   "IBM","Apple","Netscape","Borland","SGI"};
  /**
   * Constructs the stock server.
   *
   * @exception               weblogic.rmi.RemoteException
   *                          if remote object cannot be exported
   */
  public StockServer() throws RemoteException {
    for (int i = 0; i < name.length; i++) {
      stockTable.put(name[i], new Stock(name[i]));
    }
  }
  
  /**
   * Requests notification of stock updates.
   *
   * @param stock             Stock name
   * @param obj               Remote object to be notified
   * @return                  Latest update of the stock
   * @exception               examples.rmi.stock.StockNotFoundException
   *                          if stock is not known
   */
  public synchronized Stock watch (String stock, StockNotify obj)
       throws StockNotFoundException
  {
    if (!stockTable.containsKey(stock))
      throw new StockNotFoundException(stock);
    
    Vector stocks = (Vector)notifyTable.get(obj);
    
    // Register interested party
    if (stocks == null) {
      stocks = new Vector();
      notifyTable.put(obj, stocks);
    }
    
    // Add stock to list
    if (!stocks.contains(stock)) {
      stocks.addElement(stock);
    }
    
    // Start thread to notify watchers...
    if (notifier == null) {
      notifier = new Thread(this, "StockNotifier");
      notifier.start();
    }
    return (Stock)stockTable.get(stock);
  }
  
  /**
   * Cancels request for stock updates for a particular stock.
   * 
   * @param stock             Stock name
   * @param obj               Remote object canceling the notification
   */
  public void cancel(String stock, StockNotify obj) {
    Vector stocks = (Vector)notifyTable.get(obj);
    stocks.removeElement(stock);
  }
  
  /**
   * Returns an array of stock update information for the stocks
   * already registered by the remote object, or null if the
   * object is not watching any stocks.
   * 
   * @param obj               Remote object
   * @return                  List of stocks, or null
   */
  public Stock[] list(StockNotify obj) {
    Vector stocks = (Vector)notifyTable.get(obj);
    Stock[] stockList = null;
    
    if (stocks != null) {
      Enumeration enum = stocks.elements();
      stockList = new Stock[stocks.size()];
      int i=0;
      // collect updates to the stocks this watcher is
      // interested in
      while (enum.hasMoreElements()) {
        String stockname = (String)enum.nextElement();
        stockList[i++] = (Stock)stockTable.get(stockname);
      }
    }
    return stockList;
  }
  
  /**
   * Cancels all requests for stock updates for the remote object.
   *
   * @param obj               Remote object canceling the request
   */
  public synchronized void cancelAll(StockNotify obj) {
    notifyTable.remove(obj);
    if (notifyTable.isEmpty()) {
      Thread thread = notifier; // in case current thread is notifier
      notifier = null;
      thread.stop();
    }
  }
  
  /**
   * Private method to generate random stock updates.
   */
  private void generateUpdates() {
    Enumeration enum = stockTable.elements();
    while (enum.hasMoreElements()) {
      Stock stock = (Stock)enum.nextElement();
      stock.update();
    }
  }
  
  /**
   * The run method (called from the notifier thread) sends out stock
   * updates periodically to those remote objects that have
   * registered interest in being notified.
   */
  public void run() {
    while (true) {
      try {
        // Wait for a few seconds between updates
        Thread.currentThread().sleep(3000);
      }
      catch (InterruptedException e) {
      }
      
      Date date = new Date();
      // Update stocks in table
      generateUpdates();
      
      // Enumerate through each watcher...
      Enumeration enum = notifyTable.keys();
      while (enum.hasMoreElements()) {
        StockNotify obj = (StockNotify)enum.nextElement();
        Stock[] stockList = list(obj);
        if (stockList != null) {
          // Send update
          try {
            obj.update(date, stockList);
          }
          catch (RemoteException e) {
            // Can't reach watcher; cancel notification request
            e.printStackTrace();
            cancelAll(obj);
          }
        }
      }
    }
  }
  
  /**
   * Starts up the stock server. In the original example, it
   * also created a registry so that the StockApplet
   * could look up the server. In WebLogic RMI, the registry is
   * created and maintained by the WebLogic Server; a call to
   * create a registry merely finds the appropriate running
   * registry.
   */
  public static void main(String args[]) {
    
    // Note that with WebLogic RMI, there is no need to
    // create and install a security manager
    //System.setSecurityManager(new RMISecurityManager());
    try {
      System.out.println("StockServer.main: creating registry, port=" + port);
      LocateRegistry.createRegistry(new Integer(port).intValue());
      System.out.println("StockServer.main: creating server");
      StockServer server = new StockServer();
      System.out.println("StockServer.main: binding server to: "+
      "//"+ host +":" + port + "/example.stock.StockServer");
      //Naming.rebind("//:2005/example.stock.StockServer", server);
      Naming.rebind("//"+ host +":" + port + "/example.stock.StockServer", server);
      System.out.println("StockServer.main: Done.");
    }
    catch (Exception e) {
      System.out.println("StockServer.main: an exception occurred: " +
                         e.getMessage());
      e.printStackTrace();
    }
  }
}







