Step 5: coding the test client

n EJB on its own is no use; we will need at least a simple client to use its services. A user of EJBs may be another EJB, and ordinary JavaBean, a JSP page, and applet, or a stand-alone application. In this example, for simplicity, we will code a simple application. This application will create an object of class Interest, and execute its one method.
       I should point out straight away that the test client I will present below does not illustrate how you should code this sort of thing in practice; I've done it this way to show exactly what's going on. In reality, you will probably want to separate out the RMI-specific stuff into a separate class to divide the important functionality from the technical details. This class is sometimes called a `stub'. Some EJB products will generate stubs automatically; jBoss doesn't do this, so you'll have to code the stubs yourself (it isn't difficult).
       Here is the test client:

Test client: InterestClient.java


import javax.naming.*;
import com.web_tomorrow.interest.*;
import java.util.Hashtable;
import javax.rmi.PortableRemoteObject; 
import com.web_tomorrow.interest.*; 

/**
This simple application tests the `Interest' Enterprise JavaBean which is
implemented in the package `com.web_tomorrow.interest'. For this to work, the
Bean must be deployed on an EJB server.

IMPORTANT If you want to test this in a real client-server configuration, this class goes on the client; the URL of the naming provider specifed in the class must be changed from `localhost:1099' to the URL of the naming service on the server */ class InterestClient { /** This method does all the work. It creates an instance of the Interest EJB on the EJB server, and calls its `calculateCompoundInterest()' method, then prints the result of the calculation. */ public static void main(String[] args) { // Set up the naming provider; this may not always be necessary, depending // on how your Java system is configured. System.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); System.setProperty("java.naming.provider.url", "localhost:1099"); // Enclosing the whole process in a single `try' block is not an ideal way // to do exception handling, but I don't want to clutter the program up // with catch blocks try { // Get a naming context InitialContext jndiContext = new InitialContext(); System.out.println("Got context"); // Get a reference to the Interest Bean Object ref = jndiContext.lookup("interest/Interest"); System.out.println("Got reference"); // Get a reference from this to the Bean's Home interface InterestHome home = (InterestHome) PortableRemoteObject.narrow (ref, InterestHome.class); // Create an Interest object from the Home interface Interest interest = home.create(); // call the calculateCompoundInterest() method to do the calculation System.out.println ("Interest on 1000 units, at 10% per period, compounded over 2 periods is:"); System.out.println (interest.calculateCompoundInterest (1000, 0.10, 2)); } catch(Exception e) { System.out.println(e.toString()); } } }


It's important to understand that in reality this client will be running on a different computer to the Bean server. For testing you will probably run them on the same computer, but it will still be using a network connection. So the first part of the program indicates how to find the server.

	System.setProperty("java.naming.factory.initial", 
		"org.jnp.interfaces.NamingContextFactory");
	System.setProperty("java.naming.provider.url", 
		"localhost:1099");
There are several other ways to do this, which you may see described in other articles. In this case, the server is on the same machine as the client (`localhost') and the default naming port is `1099' for jBoss (other servers may use different port numbers). If you run the client and the server on different machines, you will need to change these settings.
       The comments in the program should describe how it works; one point that requires mention is that the recommended way to get a reference to the home interface on the server is like this:
InterestHome home = (InterestHome) 
	PortableRemoteObject.narrow (ref, InterestHome.class);
which ensures compatibility with different RMI servers (e.g., CORBA). `narrow' ensures that the object returned in `ref' really can be converted to an object of class `InterestHome'.
       The test client doesn't need to be in the same package as the EJB classes, and in practice it probably won't be. So it needs to import the EJB classes using their fully-qualified class name, like this:
import com.web_tomorrow.interest.*;
You will also need to pay attention to the CLASSPATH when compiling. Even though the EJB classes will run on the server, they need to be identified to the client so that the compiler can do the appropriate type checking. In the example program I have put the client at the top level of the directory hierachy, so if the CLASSPATH includes the current directory it will correctly find the EJB classes which are in the directories beneath it.
javac -classpath usr/lib/jboss/lib/ext/ejb.jar:. InterestClient.java
This generates InterestClient.class in the current directory.

©1994-2003 Kevin Boone, all rights reserved