Before using the RMI server, you must write your service according to the RMI specifications. The following example shows how to do that.
First, use an interface to encapsulate the functionality you want to expose through RMI. For example, say that you want to make a bank account component that allows someone to adjust the balance. You might design the BankBalance
interface to look like this:
import java.rmi.*; public interface BankBalance extends Remote { public void adjustBalance (double amount) throws RemoteException; public double getCurrentBalance () throws RemoteException; }
Remember that you do not have to put your service’s complete functionality in this interface—just the parts that you want to make accessible remotely. And remember that the interface must extend java.rmi.Remote
, and every method must declare that it throws java.rmi.RemoteException
.
After you finish writing the remote interface, write the actual implementation of that interface. For example:
import java.rmi.*; public class BankBalanceImpl extends atg.nucleus.GenericRMIService implements BankBalance { double balance; public BankBalanceImpl () throws RemoteException {} public void adjustBalance (double amount) throws RemoteException { balance += amount; } public double getCurrentBalance () throws RemoteException { return balance; } }
This implementation can have any methods you wish, as long as it implements your remote interface. It can even implement multiple remote interfaces. However, it must include the functionality of java.rmi.UnicastRemoteObject
and also implement atg.naming.NameContextElement
. The Oracle Commerce Platform provides a convenient base class that does both, called atg.nucleus.GenericRMIService
. This class extends GenericService
and adds the RMI capabilities provided by UnicastRemoteObject
.
Now compile the BankBalance
and BankBalanceImpl
classes using any Java compiler. For example:
javac BankBalance.java BankBalanceImpl.java
In order for Java to use these classes remotely through RMI, it must have stub and skeleton classes corresponding to your implementation. The JSDK comes with a command line utility called rmic
, which automatically generates the stub and skeleton classes. When you run rmic
, you should use as an argument the full class name of the implementation class (not the remote interface class). For example:
rmic BankBalanceImpl
You should see two new class files appear: BankBalanceImpl_Skel.class
, and BankBalanceImpl_Stub.class
.
Your classes are now ready for use with the RmiServer
. But first you must define an instance of your BankBalance
object in Nucleus. For example, the following might go into a BankBalance.properties
file:
$class=BankBalanceImpl
Exporting an RMI Service
After you create your RMI service, you can use the atg.server.rmi.RmiServer
class to make that service available to remote clients through the RMI interface.
To export a service, add its Nucleus name to the exportedServices
property of the RmiServer
. The Oracle Commerce Platform comes with an RmiServer
instance already configured at /atg/dynamo/server/RmiServer
. You might export your BankBalance
component by adding this property setting to your RmiServer
component:
exportedServices+=/yourcomponents/BankBalance
You can export as many services as you wish, separating their names with commas. The names must be full Nucleus names—that is, they must start with a forward slash (/
). The next time Nucleus starts after making these changes, your services are available for use through RMI.
Making an RMI Client
After you export your RMI service, you can test it by creating an RMI client. Accessing a remote object from a Java client requires a single RMI call, and the URL to the remote object. The URL for a remote object in an Oracle Commerce Platform server is formed like this:
rmi://{dynamo host}:{rmi port}{object's Nucleus name}
The standard RMI port for an Oracle Commerce Platform server is 8860, so a typical URL might look like this:
rmi://myhost:8860/yourcomponents/BankBalance
The following program demonstrates you can access an object using this URL:
import java.rmi.*; import java.io.*; public class BankBalanceClient { public static void main (String [] args) throws RemoteException, NotBoundException, IOException { BankBalance bb = (BankBalance) Naming.lookup ("rmi://myhost:8860/yourcomponents/BankBalance"); System.out.println ("current balance = " + bb.getCurrentBalance ()); System.out.println ("adding $8.23"); bb.adjustBalance (8.23); }
After starting Nucleus, you can run this program a few times (with the URL changed to match your particular configuration) to prove to yourself that you are accessing the Nucleus object remotely.