SDSU CS 696 Emerging Technologies: Distributed Objects
Spring Semester, 1998
RMI Stock Watch Example

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98

Contents of Doc 15, RMI Stock Watch Example

  1. Reference
  2. Stock Example
    1. Stock
    2. StockNotify
    3. StockWatch
    4. StockNotFoundException
    5. StockServer
    6. StockViewer

Reference


RMI example distributed with JDK 1.1.3


Doc 15, RMI Stock Watch Example Slide # 2

Stock Example


The following example is from Sun

It has been modified slightly to make it run under JDK 1.1.5 and not use applets

The source code can be found on rohan in the directory ~whitney/rmi/examples/stock

The following Copyright notice applies to all the classes used in this example except StockViewer
/*
 * 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.
 */

Doc 15, RMI Stock Watch Example Slide # 3

Stock


import java.util.Random;

/**
 * A Stock object is used to encapsulate stock update information
 * that is sent in an update notification. Note that the class
 * implements the java.io.Serializable interface in order to be
 * passed as an argument or return value in RMI.
 */
public class Stock implements java.io.Serializable {
   String symbol;
   float current;

   private static Random random = new Random();
   private final static float MAX_VALUE = 67;

   /**
    * Constructs a stock with the given name with a initial random
    * stock price.
    */
   public Stock(String name) 
      {
      symbol = name;
      if (symbol.equals("Sun")) 
         {
         current = 30.0f;
         } 
      else 
         {
         // generate random stock price between 20 and 60
         current = (float)(Math.abs(random.nextInt()) % 40 + 20);
         }
      }

   /**
    * Added 2/28/98 Rew
    */
   public String toString()
      {
      return symbol + " " + current;
      }


Doc 15, RMI Stock Watch Example Slide # 4
//Stock Continued
      
   /**
    * Update the stock price (generates a random change).
    */
   public float update() 
      {
      float change = ((float)(random.nextGaussian() * 1.0));
      if (symbol.equals("Sun") && current < MAX_VALUE - 5)
         change = Math.abs(change);      // what did you expect?

      float newCurrent = current + change;

      // don't allow stock price to step outside range
      if (newCurrent < 0 || newCurrent > MAX_VALUE)
         change = 0;

      current += change;
      
      return change;
      }
   }

Doc 15, RMI Stock Watch Example Slide # 5

StockNotify

import java.rmi.*;
import java.util.Date;

/**
 * The StockNotify remote interface is used to receive a stock
 * update.
 */
public interface StockNotify extends java.rmi.Remote 
   {

   /**
    * Notification of stock updates for a particular time.
    * @param date the time of the stock update
    * @param stocks an array containing the stocks for which the
    * object has registered interest.
    * @exception RemoteException if a communication failure occurs
    */
   void update (Date date, Stock[] stocks) throws RemoteException;
   }

StockWatch

import java.rmi.*;

/**
 * The StockWatch remote interface is used to register interest in
 * receiving stock updates.
 */
public interface StockWatch extends java.rmi.Remote 
   {

   /**
    * Request notification of stock updates.
    * @param stock the stock name
    * @param obj the remote object to be notified
    * @return the latest update of the stock
    * @exception StockNotFoundException if stock is not known
    * @exception RemoteException if some communication failure occurs
    */
   Stock watch(String stock, StockNotify obj)
      throws StockNotFoundException, RemoteException;

   /**
    * Cancel request for stock updates for a particular stock.
    * @param stock the stock name
    * @param obj the remote object canceling the notification
    * @exception RemoteException if some communication failure occurs
    */
   void cancel(String stock, StockNotify obj) throws RemoteException;

   /**
    * Returns an array of stock update information for the stocks
    * already registered by the remote object.
    * @param obj the remote object
    * @return the list of stocks, or null if obj is not watching any
    *  stocks
    * @exception RemoteException if some communication failure occurs
    */
   Stock[] list(StockNotify obj) throws RemoteException;

   /**
    * Cancel all requests for stock updates for the remote object.
    * @param obj the remote object canceling the request
    * @exception RemoteException if some communication failure occurs
    */
   void cancelAll(StockNotify obj) throws RemoteException;
   }


Doc 15, RMI Stock Watch Example Slide # 6

StockNotFoundException

/**
 * StockNotFoundException is thrown if a stock, for which notifications
 * of updates are requested, is not known.
 */
public class StockNotFoundException extends Exception 
   {

   public StockNotFoundException(String s) 
      {
      super(s);
      }

   }


Doc 15, RMI Stock Watch Example Slide # 7

StockServer

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.util.*;
import sdsu.util.*;

public class StockServer extends UnicastRemoteObject
   implements StockWatch, Runnable
   {
   
   /** 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"};

   /**
    * Construct the stock server
    * @exception 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]));
         }
      }


Doc 15, RMI Stock Watch Example Slide # 8
//StockServer Continued
   /**
    * Request notification of stock updates.
    * @param stock the stock name
    * @param obj the remote object to be notified
    * @return the latest update of the stock
    * @exception StockNotFoundException if stock is not known
    */
   public synchronized Stock watch (String stock, 
                                    StockNotify obj)
   throws StockNotFoundException
      {
      System.out.println("StockServer.watch: " + stock );
      
      if (!stockTable.containsKey(stock))
         throw new StockNotFoundException(stock);
      
      Vector stocks = (Vector)notifyTable.get(obj);

      // register intereted 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);
      }

Doc 15, RMI Stock Watch Example Slide # 9
//StockServer Continued

   /**
    * Cancel request for stock updates for a particular stock.
    * @param stock the stock name
    * @param obj the 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.
    * @param obj the remote object
    * @return the list of stocks, or null if obj is not watching any
    *  stocks
    * @exception RemoteException if some communication failure occurs
    */
   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;
      }


Doc 15, RMI Stock Watch Example Slide # 10
//StockServer Continued

   /**
    * Cancel all requests for stock updates for the remote object.
    * @param obj the remote object canceling the request
    * @exception RemoteException if some communication failure occurs
    */
   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();
         }
      }

Doc 15, RMI Stock Watch Example Slide # 11
//StockServer Continued

   /**
    * 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  {
                  System.out.println(
                        "StockServer.run: sending update " +
                           date);
                  obj.update(date, stockList);
               } 
               catch (RemoteException e) {
                  // can't reach watcher; cancel notification request
                  System.out.println("StockServer.run: exception");
                  e.printStackTrace();
                  cancelAll(obj);
               }
            }
         }
      }
   }

Doc 15, RMI Stock Watch Example Slide # 12
//StockServer Continued

   /**
    * Start up the stock server; also creates a registry so that the
    * StockApplet can lookup the server.
    */
   public static void main(String args[])  {
      // Create and install the security manager
      System.setSecurityManager(new RMISecurityManager());

      try {
         // Some changes from Sun code
         ProgramProperties flags = 
               new ProgramProperties( args );
         int port = flags.getInt( "p", 1099 );
         String serverLabel =  "StockServer";

         System.out.println(
            "StockServer.main: creating registry");
         Registry localRegistry = 
            LocateRegistry.createRegistry(port);;

         System.out.println("StockServer.main: creating server");
         StockServer server = new StockServer();
         
         System.out.println("StockServer.main: binding server ");
         localRegistry.rebind( serverLabel, server);
         
         System.out.println("StockServer.main: done");
      } 
      catch (Exception e) {
         System.out.println(
               "StockServer.main: an exception occurred: " +
                  e.getMessage());
         e.printStackTrace();
      }
   }
} //end class


Doc 15, RMI Stock Watch Example Slide # 13

StockViewer

import java.io.*;
import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
import sdsu.util.List;
import sdsu.util.ProgramProperties;


public class StockViewer implements StockNotify, Serializable
   {
   /** reference to StockWatch server */
   private StockWatch stockServer = null;

   private PrintWriter out;
   
   public StockViewer( StockWatch stockServer, Writer output ) 
      throws RemoteException
      {
      this.stockServer = stockServer;
      out = new PrintWriter( output);
      UnicastRemoteObject.exportObject(this);
      }
   
   public boolean watch( String stock )
      {
      try
         {
         stockServer.watch( stock, this );
         }
      catch (StockNotFoundException badName )
         {
         return false;
         }
      catch (RemoteException transmissionError)
         {
         return false;
         }
      return true;
      }
   

Doc 15, RMI Stock Watch Example Slide # 14
//StockViewer Continued
   public boolean cancel( String stock )
      {
      try
         {
         stockServer.cancel( stock, this );
         }
      catch (RemoteException transmissionError)
         {
         return false;
         }
      return true;
      }
   
   public void update( Date stockUpdateTime, Stock[] stockList )
      {
      System.err.println( "Viewer update" );
      if ( stockList.length <=0 )
         return;
      
      out.println( "The following stocks were updated on: " +  
               stockUpdateTime );
      for ( int k=0; k < stockList.length; k++ )
         {
         out.println( stockList[k] );
         }
      out.flush();
      }
   

Doc 15, RMI Stock Watch Example Slide # 15
//StockViewer Continued
   public static void main( String[] args )
      {
      try 
         {
         String serverAddress = getServerAddress( args);
         StockWatch server = (StockWatch) 
            Naming.lookup( serverAddress );
         
         StockViewer aViewer = new StockViewer( server, 
                                 new PrintWriter( System.out ));
         Enumeration stocks = getStockList( args );
         while ( stocks.hasMoreElements() )
            aViewer.watch( (String) stocks.nextElement() );
            
         } 
      catch ( Exception error) 
         {
         error.printStackTrace();
         }
      }

   private static Enumeration getStockList( String args[] ) 
      throws IOException
      {
      ProgramProperties flags = new ProgramProperties( args );
      String stockNames = flags.getString( "s" );
      List stockList = new List();
      stockList.fromString( stockNames );
      return stockList.elements();
      }


Doc 15, RMI Stock Watch Example Slide # 16
//StockViewer Continued

   private static String getServerAddress( String args[] ) 
      throws IOException
      {
      ProgramProperties flags = new ProgramProperties( args );
      String host = flags.getString( "h" );
      String port = flags.getString( "p", "1099" );
      
      return "rmi://" + host + ":" + port + "/StockServer";
      }
   }




visitors since 01-Mar-98