Section 22.2. EJBs: You Don t Know Beans?


22.2. EJBs: You Don't Know Beans?

Enough theory about EJBs and naming services and the like. It's time to put together an actual EJB so you can see one run. First we need to write our EJB classes, then compile them. Then, in the next chapter, we'll package them, along with other supporting information, into an EAR file. But let's begin by writing some Java classes.

It's not that we just write a single EJB class, say a session bean, and we're done. Keep in mind that we're going to be using these beans in a distributed environment, so we need a way to have an application running on one system find, create, look up, or otherwise access the bean running on another machine somewhere in our enterprise network. The job of EJBs is to simplify (up to a point) the efforts of the application programmer doing all this, and make it seem as if the bean is quite local or at least independent of location.

Here's how it works. Any application that wants to use the functions provided by an EJB must first locate the bean. It uses a naming service (Chapter 21) for this. What it gets from the lookup is something called a home interface. The home interface object is in effect a factory for producing remote interfaces, which are the proxies for the actual service(s) that our application wants to use. A remote interface has the method signatures that give the functionality that the application is after, but it doesn't do the actual work of the bean. Rather, it is a proxy for the bean. The remote interface's job is to do all the work behind the scenes to marshal the arguments and send them off to the bean, and to unmarshal the results returned from the bean.

So it's a three step process:

1.

Do the lookup.

2.

Use the home interface to produce a remote interface.

3.

Use the remote interface to call the methods on the bean.

What's all this talk about interfaces? They provide a way to define the methods you want to use, but without having to write all the code to do it. For example, with the remote interface you may define a method to do something with several arguments, say Blah (a, b, c). Now the remote object doesn't really do the Blah work; its job is to marshal the arguments (serialized a, b, and c) and send them off to the EJB to do whatever Blah is, and then unmarshal the results. So you as an application programmer will write the guts of Blah in the EJB object, but for the remote object, its proxy, you only need to declare the method signature. Then the job of the EJB container (e.g., JBoss or Geronimo) is to provide the smarts of the proxythat is, to generate a Java class that implements your interface, along with the code that knows how to contact your EJB and marshal and unmarshal the arguments and results. That's right, the EJB container (server) makes code that uses your interfaces, along with its own code, to do the infrastructure work of EJBs.

Talking about all these pieces of an EJB can be confusing, too. Sometimes it is helpful to think of an EJB as a single class; sometimes it's better to think of it as a family of classes that act together pretending to be a single bean that is distributed across several hosts. This can make it a bit confusing when talking about an EJBdo we mean the family of interacting classes or do we mean the single class that provides the application functionality that we want?

The names of EJB classes and EJB interfaces (which we will extend and implement) don't help much eitherthey can be confusing, too. For example, we will extend EJBObject, but not to write an EJB session bean; no, we extend SessionBean for that, but EJBObject is the name for the remote interface. Go figure.

A bit of perspective may help here. The names Remote, Local, and Home are used as modifiers on these classes. Local means "on the same host as the bean." But Home and Remote don't offer much of a clue. The home interface is what we get from a lookup; it produces remote objects (objects which implement the remote interface). A remote object is what our application uses as if it were a Java object doing what we need, even though its application-specific activity will happen on a bean somewhere else on the network.

Let's look at a very very simple example, to see the pieces in action.

22.2.1. SessionBean

Let's write a stateless session bean that will compute the time value of money. Why that? Well, two reasons. First, we already have an SAMoney class with a save() method for computing some values; and second, we need some simple, stateless, but somewhat computationally intensive task to make for a halfway reasonable example.

The real guts of an EJB, the core of the application functionalityin our example, the computation of the time value of moneyis the session (or entity) bean. For our session bean we begin by implementing the SessionBean interface, which means that we need to define these methods:

 public void setSessionContext(SessionContext context) { } public void ejbCreate() { } public void ejbRemove() { } public void ejbActivate() { } public void ejbPassivate() { } 

which, for our example, we can implement as empty methods. A stateless session bean never needs an activation or passivation method to do anythingit is pointless to passivate a stateless session bean. Why? Since it's stateless, any instance of it is as good as any other, so the instances are interchangeable and there's no need to passivate one to get to anotherjust use the one available. It follows that if a bean is never passivated, it will never have to be activated.

But why no body to the ejbCreate() method? Well, our bean isn't doing anything extra. This would only be used if our example were more complicated and we needed to do application-specific initializations. For example, if the bean had to connect to a database (and did not use entity beans), it might establish the JDBC connection in ejbCreate and close it in ejbRemove(). Similarly, we can have an empty ejbRemove() method.

Next we add our own methods, the ones that provide the application functionality. For our MoneyBean application, we'll add save() and debt() methods which will use an SAMoney class by calling its save() and debt() methods. Example 22.1 is the listing of the SessionBean.

Example 22.1. Listing of our implementation of a SessionBean
 package com.jadol.budgetpro; import net.multitool.util.*; import javax.ejb.*; /**  * Actual implementation of the EJB  */ public class MoneyEJBean   implements SessionBean {   protected SessionContext sessionContext;   // typical; just not used now   public Cost   save(double amt, double rate, double paymnt)     throws java.rmi.RemoteException   {     return SAMoney.save(amt, rate, paymnt);   } // save   public Cost   debt(double amt, double rate, double paymnt)     throws java.rmi.RemoteException   {     return SAMoney.debt(amt, rate, paymnt);   } // debt   public void   setSessionContext(SessionContext context)   {     sessionContext = context;   } // setSessionContext   public void   ejbCreate() { }   public void   ejbRemove() { }   public void   ejbActivate() { }   public void   ejbPassivate() { } } // interface MoneyEJBean 

22.2.2. EJBObject

At the other end of the chain of EJB objects used to accomplish all this distributed computing is the object that our application is actually going to touch. When our application creates an EJB, it, acting as a client, won't actually get its hands on the distant session (or entity) bean because that session bean is running somewhere out in the network. There will be, however, a proxy object, acting on behalf of the distant EJB. It is described as the remote interface, because it is remote from the EJB (though very close to the application). It is an interface because J2EE supplies a class that does the hidden work of marshaling the data, contacting the EJB, sending the data and receiving the results; the application developer only adds a few additional application-specific methods, via this interface (Example 22.2).

Example 22.2. Sample remote interface
 package com.jadol.budgetpro; import javax.ejb.*; import java.rmi.*; import net.multitool.util.*; /**  * Remote Interface for the Money EJB  */ public interface Money   extends EJBObject {   // the methods from the remote object which we will call   public Cost   save(double amt, double rate, double paymnt)     throws java.rmi.RemoteException;   public Cost   debt(double amt, double rate, double paymnt)     throws java.rmi.RemoteException; } // interface Money 

The crucial thing to note with this interface is that we have defined two methods that match the two methods in our SessionBeanthe save() and debt() methods. These are the methods that will actually be called by our application, and the J2EE mechanisms will do their work behind the scenes to connect to the methods of our SessionBean implementation and send back the results.

22.2.3. EJBHome

Between the SessionBean and its remote interface lies the home interface, also called the remote home interface, since it pairs with the remote interface. An object that implements the home interface is the kind of object that is returned after the lookup() and then narrow() method calls. It is used to create a reference to the EJB. The home interface for a stateless session bean needs only implement a single method, the create() method with no arguments. The body of the method needs do nothing. All the real work is done by the underlying object supplied by J2EE.

Example 22.3 is a listing of our home interface. It looks like an empty shell, but it is all that we need. The rest is handled by J2EE.

Example 22.3. Sample (remote) home interface
 package com.jadol.budgetpro; import javax.ejb.*; import java.rmi.*; /**  * Remote Home Interface  */ public interface MoneyHome   extends EJBHome {   public Money   create()     throws CreateException, RemoteException   ; } // interface MoneyHome 

22.2.4. Summarizing the Pieces

With these three piecesthe session bean, the remote interface, and the home interfacewe can see the structure of the key pieces of an EJB. Let's review what we have:

Application object

Extends/implements

Talked about as

Money

EJBObject

remote interface

MoneyHome

EJBHome

home interface

MoneyBean

SessionBean

the implementation


22.2.5. EJBLocalHome and EJBLocalObject

When the session or entity bean is going to be referenced by application code that resides on the same host as the bean, there are variations on the home and remote interfaces that allow for more efficient execution. When you know that the beans are local to this host, you should use a local interface (Example 22.4) and a local home interface (Example 22.5). The local interface is in place of the remote interface and extends EJBLocalObject. The local home interface is in place of the remote home interface and extends EJBLocalHome.

Example 22.4. Sample local interface
 package com.jadol.budgetpro; import javax.ejb.*; import java.rmi.*; /**  * Local Interface for the Money EJB  */ public interface MoneyLocal   extends EJBLocalObject {   // the methods which we will call } // interface MoneyLocal 

Example 22.5. Sample local home interface
 package com.jadol.budgetpro; import javax.ejb.*; import java.rmi.*; /**  * Local Home Interface  */ public interface MoneyLocalHome   extends EJBLocalHome {   public MoneyLocal   create()     throws CreateException; } // interface MoneyLocalHome 

Why bother? Well, there's no need to marshal and unmarshal all that data if the calls are staying on the same host. This saves execution time. Perhaps more importantly, since the arguments don't have to be marshaled and unmarshaled, they don't have to be serializable. For some applications, this is the only way that they can use beans.

Finally, keep in mind that the choice of local versus remote interfaces is not necessarily an either-or choice. For our session bean we have defined both kinds of interfaces. Then the deployment can determine which one will be used.

22.2.6. Compiling Your Beans

In order to compile these bean-related Java classes, you need to have a J2EE JAR in your classpath. If you've installed JBoss into /usr/local/jboss, you could add the JAR to your classpath this way:

 export CLASSPATH="/usr/local/jboss/client"\ "/jboss-j2ee.jar:.:${CLASSPATH}" 

If you have the Sun J2EE reference implementation installed on your system (in /usr/local), then you could use:

 export CLASSPATH="/usr/local/SUNWappserver"\ "/lib/j2ee.jar:.:${CLASSPATH}" 

If you have Geronimo installed on your system (with an environment variable GHOME to hold its location), then you would use: [1]

[1] Our JAR is named geronimo-spec-j2ee-1.0-M1.jar but yours will likely have a different name by the time the J2EE-certified version of Geronimo is available. It may likely just have the trailing -M1 dropped from the name; check in the geronimo-spec/jars directory. Another option is to use any of the J2EE JARs, for example, from the Sun reference implementation. That's the advantage of standards. Any of them should work for this compilation step. The resulting compiled code should be deployable to any server. "Compile once, run anywhere," right?

 export CLASSPATH="${GHOME}/repository/geronimo-spec/jars"\ "/geronimo-spec-j2ee-1.0-M1.jar:.:${CLASSPATH}" 

In any case, the point is to have in your classpath the JAR file which contains the javax/ejb/ classes, such as EJBObject.class. If you haven't installed one of these containers on your machine, then download a copy of the JAR from the machine where that container is installed. Put your copy somewhere in your classpath, as in the examples above.

If you are using Ant (and why wouldn't you be?) you will need to put the path to the J2EE JAR in the classpath which Ant uses. Since Ant can define its own classpath, you may want to define your compile task as something like this:

 <target name="compile" > <javac srcdir="${src}"     destdir="${build}"     classpath="/usr/local/SUNWappserver/lib/j2ee.jar:${stdpath}" /> </target> 

Now it's a simple matter to compile. The basic Java compile command:

 $ javac com/jadol/budgetpro/*.java 

will compile all the various classes and interfaces that make up the EJB. There may be other classes in your source tree that need to be compiled as well. With all that going on, you can see why so many people use Ant. With the compile target defined as in our example above, you would need only the command:

 $ ant compile 



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net