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.
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);
};
};
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();
| }
}
}
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 the create_reference_with_id method.
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;
}
}
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 data store (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;
}
}
A data store for 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;
}
}
The AccountRecord class:
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();
| }
}
}
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
The same client as before.
package poaBank;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import org.omg.CORBA.ORB;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextHelper;
import poaBank.AccountPackage.InsufficientFunds;
public class Client
{
ORB _orb;
Bank _bank;
Account _account;
public static void main(String[] args)
{
| try {
| | new Client().run(args);
| } catch (Exception ex) {
| | ex.printStackTrace();
| }
}
public void run(String[] args) throws Exception
{
| // create the jBroker ORB
| _orb = ORB.init(args, null);
|
| // get the root of the NameService
| NamingContext root = NamingContextHelper.narrow(
| _orb.resolve_initial_references("NameService"));
|
| // get the bank object reference
| NameComponent nc = new NameComponent(args[0], "");
| NameComponent[] name = new NameComponent[] { nc };
| _bank = BankHelper.narrow(root.resolve(name));
|
| // enter the request processing loop
| processCommands();
}
void processCommands() throws Exception
{
| // create a input stream reader
| BufferedReader reader = new BufferedReader(new InputStreamReader(
| System.in));
|
| // get the account number
| System.out.print("Enter Account number: ");
| System.out.flush();
| _account = _bank.getAccount(new Integer(reader.readLine()).intValue());
|
| // enter the read-execute loop
| while (true) {
| | System.out.print("bank > ");
| | executeCommand(readCommandLine(reader));
| }
}
void executeCommand(String[] command) throws Exception
{
| if (command.length == 0)
| printHelp();
|
| // get balance
| else if (command[0].equals("b"))
| System.out.println("\tbalance: $" + _account.balance());
|
| // check the command for addition parameter
| else if (command[0].equals("d")) {
| | if (command.length != 2) printHelp();
| | else System.out.println("\tbalance: $"+ _account.deposit(new Float(
| | command[1]).floatValue()));
| }
|
| // deposit money
| else if (command[0].equals("w")) {
| | if (command.length != 2) printHelp();
| | else {
| | | try {
| | | | System.out.println("\tbalance: $"+ _account.withdraw(
| | | | new Float(command[1]).floatValue()));
| | | } catch (InsufficientFunds ex) {
| | | | System.out.println("\tInsufficient Funds!");
| | | }
| | }
| }
|
| // quit
| else if (command[0].equals("q")) {
| | System.exit(0);
| }
|
| // print help
| else printHelp();
}
void printHelp()
{
| System.out.println();
| System.out.println("\tCommands:");
| System.out.println("\t b // get balance");
| System.out.println("\t d <sum> // deposit sum");
| System.out.println("\t w <sum> // withdraw sum");
| System.out.println("\t q // quit");
| System.out.println();
}
String[] readCommandLine(BufferedReader reader) throws Exception
{
| int i=0;
|
| String line = reader.readLine();
|
| if (line == null) System.exit(0);
|
| StringTokenizer tokenizer = new StringTokenizer(line);
| String[] command = new String[tokenizer.countTokens()];
| while (tokenizer.hasMoreTokens()) {
| | command[i++] = tokenizer.nextToken();
| }
|
| return command;
}
}
Copyright © 2003, 2004 Novell, Inc. All rights reserved. Copyright © 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.