In the CORBA
examples so far you explicitly activated instances of your servant and then
created an object reference to that servant instance:
Account_impl*
server = new Account_impl ;
CORBA::String_var
ref = orb->object_to_string(server) ;
But this is not a
very efficient or flexible way of managing servants in situations where there
are many thousands of object instances (for example a bank server has many
thousands of accounts to manage). Ideally we would activate only those account
objects that actually receive requests. Also we might want to persist the state of an object beyond the lifetime of the
server. To achieve this we need to separate the lifecycle of a CORBA Object,
which has a unique id and possibly persistent state, from the lifecycle of the
servant, which is the code that implements an interface. To improve scalability
a single servant could incarnate one or more CORBA objects during its lifetime.
To achieve persistence, a CORBA Object could be incarnated by more than one
servant in its lifetime. The POA
(Portable Object Adapter) API is the CORBA solution to separating servants and
objects. In this class you will build a
bank server that activates accounts using the POA. We will use the java J2SE
1.4 CORBA implementation:
1. Generate
client and server stubs from idl:
Copy the bank.idl file from the following directory:
http://www.cs.ucl.ac.uk/staff/w.emmerich/lectures/Z23-04-05/poa/sample/bank.idl
or copy from Unix shell:
cp /cs/research/sse/home1/rigel/ucacwxe/public_html/lectures/Z23-04-05/poa/sample/bank/bank.idl
.
Make sure you
understand the interface definitions before continuing. Now generate the client
and server stubs using the jdk idl
comipiler:
idlj
–fall bank.idl
A subdirectory
called “bank” is created. In this directory you will find all the stubs and
skeletons needed to create the bank server. Change to this as your working
directory:
cd
bank
2. Copy over the
“AccountImpl.java” servant code. This is a fairly
straightforward implementation of the Account interface.
3. Create an
Account Servant Manager by extending org.omg.PortableServer.ServantActivatorPOA implementing the etherealize and
incarnate methods.
The incarnate
method should return Account servant instances.
4. Create a class
for the BankServer
The BankServer code should create 2 POAs.
One to manage the bank object and one to manage the account objects.
1. Get a reference to the root POA using the
ORB “resolve_ initial_references” method:
ORB orb = ORB.init(args, null);
POA rootPOA = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
2. Next create the BankPOA
defining a number of policies that determine various aspects of the POA’s behaviour.
a. Set the lifespan policy to TRANSIENT. (Objects
activated by a POA with a transient lifespan policy cannot outlive the server
process. Objects activated by a POA with a persistent lifespan policy can
outlive the server process).
b. The Request Processing Policy determines
how the POA associates an object id in the request with a servant
implementation. Set this to the constant USE_ACTIVE_OBJECT_MAP_ONLY, which means the object reference is looked up in a
special lookup table maintained by the POA called the “Active Object Map”
(AOM).
c. The Servant Retention policy determines whether
the POA maintains a map of active servants (RETAIN) or not (NON_RETAIN).
3. Create the AccountPOA
with a Request Process Policy that delegates the location and incarnation of
servants to the Servant Manager.
4. Create a servant and an object ID for the
Bank Object. Hint:
byte[] objectID = new String("CORBABank").getBytes();
5. Activate the object using the POA “activate_object_with_id” method.
6. Obtain an object reference using the create_reference_with_id and bind it to root context of naming
service under the name “BankServer”:
org.omg.CORBA.Object objRef
=
orb.resolve_initial_references("NameService");
NamingContextExt
ncRef = NamingContextExtHelper.narrow(objRef);
String name = "BankServer";
NameComponent path[] = ncRef.to_name( name );
ncRef.rebind(path, bref);
7.
Start the POA’s and run the orb
// Start the POAs
accountPOA.the_POAManager().activate();
bankPOA.the_POAManager().activate();
rootPOA.the_POAManager().activate();
// Ready, Set, and Go...
System.out.println("BankServer ready and
waiting ...");
// wait for invocations from clients
orb.run();
5. Now copy the
Bank servant (BankImpl.java) and examine the “openAccount”
method. The line below shows the AccountPOA creating a new reference for an account object
with an ID based on the user generated account number for the account.
Account theAccount =
AccountHelper.narrow(accountPOA.create_reference_with_id(accNum.getBytes(),"IDL:bank/Account:1.0"));
It is important
to understand that although an object reference exists it has not yet been
associated with a servant. This will only happen when and if a client actually
tries to use the reference.
6. You need to
copy the “DBUtils.java” which provides methods for
creating and accessing account information from a simple file database. Finally
copy the test directory which contains some example client code.
http://www.cs.ucl.ac.uk/staff/w.emmerich/lectures/Z23-04-05/poa/sample/bank/test
cp –R /cs/research/sse/home1/rigel/ucacwxe/public_html/lectures/Z23-04-05/poa/sample/bank/test
.
5. Compile your
sources: Go to the parent of the directory where you copied the .java files to:
cd ..
Create a new
directory called “classes” and then compile as follows:
javac
-d ./classes bank/*.java bank/test/*.java
6. Running the
example:
orbd -ORBInitialPort 1050 -ORBInitialHost
localhost
java
-cp ./classes bank.BankServer -ORBInitialPort
1050 -ORBInitialHost localhost
3. Run the client:
java
-cp ./classes bank.test.BankClient -ORBInitialPort 1050 -ORBInitialHost
localhost
Rerun the client
a few times. Each time the client is run two new account objects are created.
In the server standard output we see that the Account Servant Activator is
accessed twice for each openAccount call.
The “find
accounts” query is then executed selecting already existing accounts of type
“saving”. But the Account Servant Activator is not accessed since active
servants matching these references are found in the Account POA Active Object
Map. (Review the USE_SERVANT_MANAGER policy if this does not make sense). Now stop the server process (Control-C) and
restart it. Run the client again. This time the Account Servant Activator was
accessed not just for the two new accounts, but also for the existing accounts
of type saving. The next time you run the client, what do you expect to happen?
Try it and see if you were right.
Shutdown the
naming service (Control-C) and remove the files “bankaccounts”,
“temp” and (with –r option) the directory orb-db.
Now change the
server code so that the Bank- and Account- POA use a persistent lifespan
policy. Recompile and restart the naming service (orbd).
The J2SE 1.4 CORBA implementation specifies that persistent servers must be
registered and activated indirectly using the “servertool”
utility. Start the servertool utility specifying the
port and host of the orbd naming service:
servertool
orbd -ORBInitialPort 1050 -ORBInitialHost localhost
Welcome to the Java IDL Server Tool
please
enter commands at the prompt
Now register the BankServer using the “register” command as follows:
servertool
> register -server bank.BankServer -applicationName BankServer -classpath ./classes -args -ORBInitialPort 1050 -ORBInitialHost
localhost
server registered (serverid =
257).
Check the server
was registered:
servertool
> list
Server
Id Server Class Name Server Application
---------
-----------------
------------------
257 bank.BankServer BankServer
Run the client to
check that the server functions as before. Now to demonstrate
that this persistent server really does outlive the server process shutdown the
BankServer with the “shutdown” command. Check
the shutdown worked by running the “listactive”
command.
servertool
> shutdown -serverid 257
server sucessfully shutdown.
servertool
> listactive
Server
Id Server Class Name Server Application
---------
-----------------
------------------
Now rerun the
client. Because the server is persistent the servant manager transparently
restarts the server when the client makes a request. To check the server is
active again retype the “listactive” command: