The bank application demostrates creating POAs for transient and persistent objects, with user assigned object ids.
poaBank
module contains two interfaces - Account
,
and Bank
. The Account
has methods for depositing, withdrawing,
and checking balance. The Bank
just method for getting an
Account
object for the given account number.
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); }; };
The bank server creates a POA with user assigned object ids, and persistent object lifecycle policies. It then creates a bank object using "bank" as the object id.
If this is the first incarnation of the server, it publishes the bank object in the COS namespace. The server checks the namespace to determine if it published the object last time. This demonstrates the persistence of the object reference. No matter how many times the server terminates and restarts the object reference remains valid.
package poaBank; 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; 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 the 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("bank", ""); | | 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(); | } } }
This is the implementation of the bank object. It creates a transient object POA with user assigned Ids, pre-creates 10 account objects, and saves them in a hash table.
package poaBank; import java.io.File; import java.util.Hashtable; import org.omg.CORBA.Policy; import org.omg.PortableServer.POA; import org.omg.PortableServer.Servant; import org.omg.PortableServer.IdAssignmentPolicyValue; import poaBank.BankPackage.noSuchAccount; public class BankImpl extends BankPOA { POA _acctPOA; Hashtable _accounts; 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) | }); | | // create the account objects | _accounts = new Hashtable(19); | byte objectId[] = new byte[1]; | for (int i=100; i < 110; i++) { | | | | // construct the object id for account | | objectId[0] = (byte) (i & 0xFF); | | | | // create a servant | | Servant servant = new AccountImpl(dbDir, i); | | | | // activate the object and get an object reference | | _acctPOA.activate_object_with_id(objectId, servant); | | Account account = AccountHelper.narrow( | | _acctPOA.create_reference_with_id(objectId, | | servant._all_interfaces(null, null)[0])); | | | | // save the objref | | _accounts.put(new Integer(i), account); | } } public Account getAccount(int acctNum) throws noSuchAccount { | Account account = (Account) _accounts.get(new Integer(acctNum)); | | if (account == null) throw new noSuchAccount(); | | return account; } }
The account implementation uses a file to maintain the account balance. Since multiple deposit and withdraw methods may be fired at the object at the same time, these methods are made synchronized.
package poaBank; 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; import poaBank.AccountPackage.InsufficientFunds; public class AccountImpl extends AccountPOA { float _balance; File _acctDb; public AccountImpl() {} public AccountImpl(File dir, int i) { | _acctDb = new File(dir, new Integer(i).toString()); | if (_acctDb.exists()) _balance = readBalance(); } public synchronized float deposit(float sum) { | _balance += sum; | | writeBalance(); | | return _balance; } public synchronized float withdraw(float sum) throws InsufficientFunds { | if ((_balance - sum) < 0) throw new InsufficientFunds(); | | _balance -= sum; | | writeBalance(); | | return _balance; } public synchronized float balance() { | return _balance; } void writeBalance() { | try { | | FileOutputStream fos = new FileOutputStream(_acctDb); | | ObjectOutputStream oos = new ObjectOutputStream(fos); | | | | oos.writeObject(new Float(_balance)); | | | | oos.close(); | } catch (Exception ex) { | | throw new PERSIST_STORE(); | } } float readBalance() { | try { | | FileInputStream fis = new FileInputStream(_acctDb); | | ObjectInputStream ois = new ObjectInputStream(fis); | | | | float balance = ((Float) ois.readObject()).floatValue(); | | | | ois.close(); | | | | return balance; | } catch (Exception ex) { | | throw new PERSIST_STORE(); | } } }
A server implementing persistent objects needs to be registered with the ORB. The ORB uses a server deployment descriptor to define a server. The server deployment descriptor can be expressed as a Java properties file.
server.main=poaBank.Server server.alias=bank server.classpath=c\:\\mp\\examples\\orb\\lib server.args=c\:\\mp\\examples\\orb\\src\\poaBank\\db
Please see the Server Activation section for
details. Run ant deploy
to register the server.
The bank application client gets the object reference of the bank and presents a prompt to the user to do transactions on their choice of an account object.
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; } }
Run the client using ant client
.
Copyright © 2003, 2004 Novell, Inc. All rights reserved. Copyright © 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.