Now that we have deployed our Calculator EJB, let's write a short Java program that uses it. Listing 4 contains the source code for such a class, UseCalculator.java.
While our program is completely independent from our EJB classes and can be compiled and run separately (or even on a separate computer), we use Ant to keep track of the CLASSPATH (which must include the JBoss classes, as well as those from our .jar file), compile our code and then run it. In order to run our application, we simply can say
This runs our program after ensuring that our EJB is compiled, turned into a .jar file and deployed.
Anything that UseCalculator.main() writes to System.out (also known as the stdout filehandle) is printed on the screen when we run Ant. However, anything that our CalculatorBean method writes to stdout is printed to the JBoss logging output. By keeping JBoss open in one terminal window and running Ant in another, we can see them communicate with each other.
UseCalculator's main() method consists of several standard steps for connecting to and using our EJB. We first connect to JNDI, which keeps track of the objects currently deployed to JBoss. This connection is known as a context. Our program looks for jndi.properties, a short Java properties file that tells it where it can go to find a context (this file should be placed in $CALCULATOR/resources/, as specified in build.xml). This file is in Java resources format, where every line contains name=value:
java.naming.factory.initial= java.naming.provider.url=localhost:1099 java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
Once we have our context, we look up our object using the name that we gave it in jboss.xml, which is inside of our ejb-jar.xml. Without jboss.xml, JBoss will not associate the right name with our EJB, making it impossible to find using JNDI.
JNDI returns an object reference, which we then cast into an instance of CalculatorHome, which is then used to create an instance of Calculator. Notice how we create an instance of Calculator (the remote interface), rather than one of CalculatorBean. The remote interface provides us with a transparent connection to an instance of CalculatorBean on the server, wherever that might be. At no time do we actually know where the real instance of CalculatorBean resides.
Finally, we invoke one of the methods that has been defined in Calculator (the remote interface). Our method invocation is passed along to CalculatorBean (the bean class), where it executes (and prints out some logging information) and returns (where we print the result to stdout).
This month we started to look at Enterprise JavaBeans, an infrastructure for creating distributed applications using Java. While EJB is far more complex than SOAP, XML-RPC or other distributed object systems, it is also designed to handle more complicated tasks. (For example, SOAP doesn't attempt to handle transactions; that's left to the application layer to implement.)
At the same time, working with Java often means spending more time on administrative and logistical issues, rather than on programming. Determining which file must be in which directory can often be frustrating, especially if you are used to working with a more dynamic language such as Perl or Python. Nevertheless, the pain quickly subsides when you see how easily you can create distributed applications with EJB. The fact that JBoss is so easy to download, install and run, and has a very small memory footprint, makes it simple for newcomers to try EJB.
Next month, we will continue working with EJB, looking at the heart of EJB, the entity beans that provide an object interface to our relational databases.