An 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, an ordinary JavaBean, a JSP page, an 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.
On deployment of the bean as performed in the previous step, the server has bound the EJB home interface under the JNDI name of interest/Interest and exported the home interface so that it can be invoked via RMI. What we are going to cover here is the way you lookup a the home interface using JNDI from a client and invoke methods on it. The example client code is listed in the following figure:
Figure 1.8. Test client, file name InterestClient.java
package org.jboss.docs.interest; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; import org.jboss.docs.interest.Interest; import org.jboss.docs.interest.InterestHome; /** This simple application tests the 'Interest' Enterprise JavaBean which is implemented in the package 'org.jboss.docs.interest'. For this to work, the Bean must be deployed on an EJB 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) { // 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()); } } }
Please note that the client lookup up the InterestHome interface under the JNDI name "interest/Interest". Your bean's home interface has been bound to this name if you supplied a proper jboss.xml file. If not, the JNDI name will be "Interest". Connecting to the JBoss JNDI implementation entails creating an InitialContext object with the correct jndi.properties in the client classpath. In the source, all that is required is:
// Get a naming context InitialContext jndiContext = new InitialContext(); System.out.println("Got context");
The jndi.properties file we have to use is located in the examples/resources/jndi.properties of the documentation examples distribution. Its contents are:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.provider.url=jnp://localhost:1099 java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfacesThis specifies the InitialContextFactory, provider url, and the packages of object factories specific to the JBoss JNDI provider. The provider url can be abbreviated to simply "localhost" or the hostname on which JBoss is running when using the default port of 1099.
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 protocols (e.g., RMI/IIOP). The 'narrow' method ensures that the 'ref' object 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 as illustrated.
To compile and run the InterestClient execute the following ant command:
The output is what you should see if all goes well. This shows that the classpath used to execute the client included a number of jars located in the JBoss client directory as well as the directory containing the compiled example classes and the directory containing the jndi.properties file. These JBoss client jars contain the standard EJB and JNDI interfaces as well as the JBoss specific container code. The various jars are:
There should be output from the Interest EJB on the server console as well. This is generated to show that the bean has executed on the server, not the client. Look for something like this in the server log or console:
[Interest] Someone called `calculateCompoundInterest!'
Well, that's it. We covered coding, compiling and deploying an EJB, and coding and running a simple test client.