Bank Application using Default Servant

In this version of the Bank Application, we will use a single servant that will services all the Account Objects. It will determine the object id of the object being invoked upon, and will do the requested operation on the object state corresponding to it.

1 Bank Interface in IDL

The bank interface is same as before.
module poaBank
{
    interface Account 
    {
    |   exception InsufficientFunds {};
    |                                                                      
    |   float deposit(in float sum);
    |                                                                      
    |   float withdraw(in float sum) raises (InsufficientFunds);
    |                                                                      
    |   readonly attribute float balance;
    };
                                                                           
    interface Bank
    {
    |   exception noSuchAccount {};
    |                                                                      
    |   Account getAccount(in long accountNum) raises (noSuchAccount);
    };
};

2 Bank Application Server

Same as before except that it uses a different BankImpl and publishes the bank object using a different name.
package poaBankDefSrvnt;
                                                                           
import util.Util;
import org.omg.CORBA.ORB;
import org.omg.CORBA.Policy;
                                                                           
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextHelper;
import org.omg.CosNaming.NamingContextPackage.NotFound;
                                                                           
import org.omg.PortableServer.POA;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.LifespanPolicyValue;
import org.omg.PortableServer.IdAssignmentPolicyValue;
                                                                           
import poaBank.Bank;
import poaBank.BankHelper;
                                                                           
public class Server
{
    public static void main(String[] args)
    {
    |   try {
    |   |                                                                  
    |   |   // create the jBroker ORB
    |   |   ORB orb = ORB.init(args, null);
    |   |                                                                  
    |   |   // get the root POA
    |   |   POA rootPOA = (POA) orb.resolve_initial_references("RootPOA");
    |   |                                                                  
    |   |   // create a persistent user assigned ids POA
    |   |   POA bankPOA = rootPOA.create_POA("bankPOA", 
    |   |       rootPOA.the_POAManager(),
    |   |       new Policy[] {
    |   |       |   rootPOA.create_id_assignment_policy(
    |   |       |       IdAssignmentPolicyValue.USER_ID),
    |   |       |   rootPOA.create_lifespan_policy(
    |   |       |       LifespanPolicyValue.PERSISTENT)
    |   |       });
    |   |                                                                  
    |   |   // create and activate bank servant
    |   |   Servant bank = new BankImpl(bankPOA, args[0]);
    |   |   bankPOA.activate_object_with_id("bank".getBytes(), bank);
    |   |                                                                  
    |   |   // get the root of the NameService
    |   |   NamingContext root = NamingContextHelper.narrow(
    |   |       orb.resolve_initial_references("NameService"));
    |   |                                                                  
    |   |   // if not done before, publish the bank objref
    |   |   NameComponent nc = new NameComponent("bank3", "");
    |   |   NameComponent[] name = new NameComponent[] { nc };
    |   |   try {
    |   |   |   root.resolve(name);
    |   |   } catch (NotFound ex) {
    |   |   |   // create the bank objref
    |   |   |   Bank bankObj = BankHelper.narrow(bankPOA.
    |   |   |       create_reference_with_id("bank".getBytes(),
    |   |   |           bank._all_interfaces(null, null)[0]));
    |   |   |                                                              
    |   |   |   System.out.println(orb.object_to_string(bankObj));
    |   |   |   root.rebind(name, bankObj);
    |   |   }
    |   |                                                                  
    |   |   // activate bankPOA
    |   |   bankPOA.the_POAManager().activate();
    |   |                                                                  
    |   |   // wait for invocations
    |   |   System.out.println("waiting for invocations ...");
    |   |   orb.run();
    |   |                                                                  
    |   } catch (Exception ex) {
    |   |   ex.printStackTrace();
    |   }
    }
}

3 Bank Implementation

The BankImpl constructor just creates a POA with USER_IDS, USE_DEFAULT_SERVANT, and MULTIPLE_IDS policies for Account objects and sets the default servant in the POA. When it is asked for an account, it manufactures a new object reference (with the given account number as the object id) using create_reference_with_id.
package poaBankDefSrvnt;
                                                                           
import java.io.File;
                                                                           
import org.omg.CORBA.Policy;
                                                                           
import org.omg.PortableServer.POA;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.IdUniquenessPolicyValue;
import org.omg.PortableServer.IdAssignmentPolicyValue;
import org.omg.PortableServer.ServantRetentionPolicyValue;
import org.omg.PortableServer.RequestProcessingPolicyValue;
                                                                           
import poaBank.BankPOA;
import poaBank.Account;
import poaBank.AccountHelper;
import poaBank.BankPackage.noSuchAccount;
                                                                           
public class BankImpl extends BankPOA
{
    POA       _acctPOA;
    String    _acctRepId; // repository Id for Account Objects
    Servant   _defaultServant;
                                                                           
    BankImpl(POA bankPOA, String dir) throws Exception
    {
    |   // make sure that the DB dir exists
    |   File dbDir = new File (dir);
    |   if (!dbDir.exists()) dbDir.mkdir();
    |                                                                      
    |   // create the POA for Transient Account Objects
    |   _acctPOA = bankPOA.create_POA("acctPOA", bankPOA.the_POAManager(),
    |       new Policy[] {
    |       |   bankPOA.create_id_assignment_policy(
    |       |       IdAssignmentPolicyValue.USER_ID),
    |       |   bankPOA.create_request_processing_policy(
    |       |       RequestProcessingPolicyValue.USE_DEFAULT_SERVANT),
    |       |   bankPOA.create_id_uniqueness_policy(
    |       |       IdUniquenessPolicyValue.MULTIPLE_ID)
    |       });
    |                                                                      
    |   // set the servant manager in Acct POA
    |   _defaultServant = new AccountImpl(dbDir);
    |   _acctPOA.set_servant(_defaultServant);
    |                                                                      
    |   // compute the repository id for Account objects
    |   _acctRepId = _defaultServant._all_interfaces(null, null)[0];
    }
                                                                           
    public Account getAccount(int acctNum) throws noSuchAccount
    {
    |   Account account = null;
    |                                                                      
    |   if ((acctNum >= 100) && (acctNum < 110)) {
    |   |                                                                  
    |   |   // construct the object id for account
    |   |   byte objectId[] = new byte[1];
    |   |   objectId[0] = (byte) (acctNum & 0xFF);
    |   |                                                                  
    |   |   try {
    |   |   |   account = AccountHelper.narrow(_acctPOA.
    |   |   |      create_reference_with_id(objectId, _acctRepId));
    |   |   } catch (Exception ex) {
    |   |   |   // org.omg.PortableServer.POAPackage.WrongPolicy
    |   |   |   // thrown on JDK 1.2 and 1.3
    |   |   |   ex.printStackTrace();
    |   |   }
    |   }
    |                                                                      
    |   if (account == null) throw new noSuchAccount();
    |                                                                      
    |   return account;
    }
}

4 Account Implementation

There is now only a single instance of the Account Servant. The state of the accounts is now maintained outside of it in the Account DataStore (see next section.)
package poaBankDefSrvnt;
                                                                           
import java.io.File;
                                                                           
import org.omg.CORBA.ORB;
import org.omg.CORBA.PERSIST_STORE;
                                                                           
import poaBank.AccountPOA;
import poaBank.AccountPackage.InsufficientFunds;
                                                                           
public class AccountImpl extends AccountPOA
{
    AccountBalances _accountsDb;
                                                                           
    public AccountImpl(File acctDb)
    {
    |   _accountsDb = new AccountBalances(acctDb);
    }
                                                                           
    public float deposit(float sum)
    {
    |   int acctNum = getAccountNumber();
    |                                                                      
    |   AccountRecord record = _accountsDb.getAccount(acctNum);
    |                                                                      
    |   float balance = 0;
    |   synchronized (record) {
    |   |   balance = record.getBalance() + sum;
    |   |   record.setBalance(balance);
    |   }
    |                                                                      
    |   return balance;
    }
                                                                           
    public float withdraw(float sum) throws InsufficientFunds
    {
    |   int acctNum = getAccountNumber();
    |                                                                      
    |   AccountRecord record = _accountsDb.getAccount(acctNum);
    |                                                                      
    |   float balance = 0;
    |   synchronized (record) {
    |   |   balance = record.getBalance();
    |   |   if ((balance - sum) < 0) 
    |   |       throw new InsufficientFunds();
    |   |   balance -= sum;
    |   |   record.setBalance(balance);
    |   }
    |                                                                      
    |   return balance;
    }
                                                                           
    public float balance()
    {
    |   return _accountsDb.getAccount(getAccountNumber()).getBalance();
    }
                                                                           
    private int getAccountNumber()
    {
    |   return _object_id()[0] & 0x000000FF;
    }
}

5 Account DataStore

A DataStore for Account balances.

5.1 Account Balances

package poaBankDefSrvnt;
                                                                           
import java.io.File;
import java.util.Hashtable;
                                                                           
// Datastore for Account Balances
class AccountBalances
{
    File      _dbDir;
    Hashtable _table;
                                                                           
    AccountBalances(File dbDir)
    {
    |   _dbDir = dbDir;
    |   _table = new Hashtable(19);
    }
                                                                           
    synchronized AccountRecord getAccount(int acctNum)
    {
    |   Integer AcctNum = new Integer(acctNum);
    |                                                                      
    |   AccountRecord record = (AccountRecord) _table.get(AcctNum);
    |                                                                      
    |   if (record == null) {
    |   |   record = new AccountRecord(0, new File(_dbDir, 
    |   |       AcctNum.toString()));
    |   |   _table.put(AcctNum, record);
    |   }
    |                                                                      
    |   return record;
    }
}

5.2 Account Record

package poaBankDefSrvnt;
                                                                           
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
                                                                           
import org.omg.CORBA.PERSIST_STORE;
                                                                           
class AccountRecord
{
    private float _balance;
    private File  _file;
                                                                           
    AccountRecord(float balance, File file) 
    {
    |   _file    = file;
    |   _balance = balance;
    |                                                                      
    |   // if file exists read balance
    |   if (_file.exists()) {
    |   |   try {
    |   |   |   FileInputStream fis = new FileInputStream(_file);
    |   |   |   ObjectInputStream ois = new ObjectInputStream(fis);
    |   |   |   _balance = ((Float) ois.readObject()).floatValue();
    |   |   |   ois.close();
    |   |   } catch (Exception ex) {
    |   |   |   throw new PERSIST_STORE();
    |   |   }
    |   }
    }
                                                                           
    float getBalance()
    {
    |   return _balance;
    }
                                                                           
    void setBalance(float balance)
    {
    |   _balance = balance;
    |                                                                      
    |   try {
    |   |   FileOutputStream fos = new FileOutputStream(_file);
    |   |   ObjectOutputStream oos = new ObjectOutputStream(fos);
    |   |   oos.writeObject(new Float(_balance));
    |   |   oos.close();
    |   } catch (Exception ex) {
    |   |   throw new PERSIST_STORE();
    |   }
    }
}

6 Register the Server

The server deployment descriptor.
server.main=poaBankDefSrvnt.Server
server.alias=bank3
server.classpath=/usr/local/jbroker30/examples/lib
server.args=/usr/local/jbroker30/examples/src/poaBankDefSrvnt/db

7 Bank Client

The same client as before.
Copyright © 2000-2003, Novell, Inc. All rights reserved.