[ Team LiB ] Previous Section Next Section

21.1 Remote Banking

Example 21-1 shows a class, Bank, that contains inner classes and interfaces for a remote bank client/server example. In this example, the RemoteBank interface defines remote methods to open and close accounts, deposit and withdraw money, check the account balance, and obtain the transaction history for an account. The Bank class contains all of the classes and interfaces required for the example, except for the server class, which is the class that actually implements the RemoteBank interface. This server class is shown in Example 21-2.

Example 21-1 defines the following inner classes and interfaces:


The Remote interface implemented by the bank server and used by the bank client.


A trivial class that represents money in this banking example. It is nothing more than a wrapper around an int, but it serves to demonstrate that Serializable objects can be passed as arguments to remote methods and returned by remote methods.


A simple exception subclass that represents banking-related exceptions, such as "Insufficient funds." It demonstrates that remote method implementations on a server can throw exceptions that are transported across the network and thrown in the client program.


This class is a standalone program that serves as a simple client to the bank server. It uses Naming.lookup( ) to look up the desired RemoteBank object in the system registry and then invokes various methods of that RemoteBank object, depending on its command-line arguments. It is really as simple as that; the use of RMI is almost transparent.

A session using the Bank.Client class might look as follows (note that the command-line argument "david" is the account name and "javanut" is the password that protects the account):

% java je3.rmi.Bank\$Client open david javanut
Account opened.
% java je3.rmi.Bank\$Client deposit david javanut 1000
Deposited 1000 wooden nickels.
% java je3.rmi.Bank\$Client withdraw david javanut 100
Withdrew 100 wooden nickels.
% java je3.rmi.Bank\$Client balance david javanut 
You have 900 wooden nickels in the bank.
% java je3.rmi.Bank\$Client history david javanut
Account opened at Wed Jul 12 15:30:12 PDT 2000
Deposited 1000 on Wed Jul 12 15:30:31 PDT 2000
Withdrew 100 on Wed Jul 12 15:30:39 PDT 2000
% java je3.rmi.Bank\$Client close david javanut
900 wooden nickels returned to you.
Thanks for banking with us.

In this example session, the bank client is running on the same host as the server. This need not be the case; the Client class looks for a system property named bank to determine which bank server to connect to. So you could invoke the client program like this (one long command line that has been broken into two lines):

% java -Dbank=rmi://bank.trustme.com/TrustyBank \
je3.rmi.Bank\$Client open david javanut
Example 21-1. Bank.java
package je3.rmi;
import java.rmi.*;
import java.util.List;

 * This class is a placeholder that simply contains other classes and 
 * interfaces for remote banking.
public class Bank {
     * This is the interface that defines the exported methods of the 
     * bank server.
    public interface RemoteBank extends Remote {
        /** Open a new account, with the specified name and password */
        public void openAccount(String name, String password) 
            throws RemoteException, BankingException;
        /** Close the named account */
        public FunnyMoney closeAccount(String name, String password) 
            throws RemoteException, BankingException;
        /** Deposit money into the named account */
        public void deposit(String name, String password, FunnyMoney money)
            throws RemoteException, BankingException;
        /** Withdraw the specified amount of money from the named account */
        public FunnyMoney withdraw(String name, String password, int amount) 
            throws RemoteException, BankingException;
        /** Return the amount of money in the named account */
        public int getBalance(String name, String password) 
            throws RemoteException, BankingException;
         * Return a List of Strings that list the transaction history 
         * of the named account 
        public List getTransactionHistory(String name, String password) 
            throws RemoteException, BankingException;
     * This simple class represents a monetary amount.  This implementation
     * is really nothing more than a wrapper around an integer.  It is useful
     * to demonstrate that RMI can accept arbitrary non-String objects as
     * arguments and return them as values, as long as they are Serializable.
     * A more complete implementation of this FunnyMoney class might bear
     * a serial number, a digital signature, and other security features to 
     * ensure that it is unique and non-forgeable.
    public static class FunnyMoney implements java.io.Serializable {
        public int amount;
        public FunnyMoney(int amount) { this.amount = amount; }
     * This is a type of exception used to represent exceptional conditions
     * related to banking, such as "Insufficient Funds" and  "Invalid Password"
    public static class BankingException extends Exception {
        public BankingException(String msg) { super(msg); }
     * This class is a simple stand-alone client program that interacts
     * with a RemoteBank server.  It invokes different RemoteBank methods
     * depending on its command-line arguments, and demonstrates just how
     * simple it is to interact with a server using RMI.
    public static class Client {
        public static void main(String[  ] args) {
            try {
                // Figure out what RemoteBank to connect to by reading a system
                // property (specified on the command line with a -D option to
                // java) or, if it is not defined, use a default URL.  Note
                // that by default this client tries to connect to a server on
                // the local machine
                String url = System.getProperty("bank", "rmi:///FirstRemote");
                // Now look up that RemoteBank server using the Naming object,
                // which contacts the rmiregistry server.  Given the url, this
                // call returns a RemoteBank object whose methods may be
                // invoked remotely
                RemoteBank bank = (RemoteBank) Naming.lookup(url);
                // Convert the user's command to lower case
                String cmd = args[0].toLowerCase( );
                // Now, go test the command against a bunch of possible options
                if (cmd.equals("open")) {           // Open an account
                    bank.openAccount(args[1], args[2]);
                    System.out.println("Account opened.");
                else if (cmd.equals("close")) {     // Close an account
                    FunnyMoney money = bank.closeAccount(args[1], args[2]);
                    // Note: our currency is denominated in wooden nickels
                    System.out.println(money.amount +
                                       " wooden nickels returned to you.");
                    System.out.println("Thanks for banking with us.");
                else if (cmd.equals("deposit")) {   // Deposit money
                    FunnyMoney money=new FunnyMoney(Integer.parseInt(args[3]));
                    bank.deposit(args[1], args[2], money);
                    System.out.println("Deposited " + money.amount +
                                       " wooden nickels.");
                else if (cmd.equals("withdraw")) {  // Withdraw money
                    FunnyMoney money = bank.withdraw(args[1], args[2], 
                    System.out.println("Withdrew " + money.amount +
                                       " wooden nickels.");
                else if (cmd.equals("balance")) {   // Check account balance
                    int amt = bank.getBalance(args[1], args[2]);
                    System.out.println("You have " + amt +
                                       " wooden nickels in the bank.");
                else if (cmd.equals("history")) {   // Get transaction history
                    List transactions =
                        bank.getTransactionHistory(args[1], args[2]);
                    for(int i = 0; i < transactions.size( ); i++)
                else System.out.println("Unknown command");
            // Catch and display RMI exceptions
            catch (RemoteException e) { System.err.println(e); }
            // Catch and display Banking related exceptions
            catch (BankingException e) { System.err.println(e.getMessage( )); }
            // Other exceptions are probably user syntax errors, so show usage.
            catch (Exception e) { 
                System.err.println("Usage: java [-Dbank=<url>] Bank$Client " + 
                                   "<cmd> <name> <password> [<amount>]");
                System.err.println("where cmd is: open, close, deposit, " + 
                                   "withdraw, balance, history");
    [ Team LiB ] Previous Section Next Section