7.4. Implementing a Basic EJB ObjectNow it's time to start talking about actually implementing an Enterprise JavaBeans component. No matter whether you are creating an entity bean or a session bean, there are three Java interfaces/classes you need to provide:
To demonstrate the various components that make up an Enterprise JavaBeans object, we'll look at a simple example: a profile server. The profile server is a stateless session bean that provides profile information for named users. This profile information consists of name/value pairs that might represent preferences in an application, historical usage patterns, etc. You might see a profile server running behind an online information service, allowing users to personalize the content and appearance of the site when they enter. After we've gone through this general example of writing a bean, we'll look more closely at the differences between implementing session beans and entity beans. Table 7-1 shows how the methods of the home interface, the remote interface, and the bean implementation are related to each other. Table 7-1. Related Methods
7.4.1. Home InterfaceThe client needs a way to create a local reference to a profile server, so we have to provide a home interface for our bean, as shown in Example 7-1. This home interface provides a single create() method that takes no arguments and returns the bean's remote interface type, ProfileServer. Example 7-1. Home Interface for the Profile Server Beanimport javax.ejb.*; import java.rmi.RemoteException; public interface ProfileServerHome extends EJBHome { public ProfileServer create() throws CreateException, RemoteException; } The home interface for an EJB object extends the javax.ejb.EJBHome interface. The home interface is also an RMI remote interface, since EJBHome extends java.rmi.Remote. The home interface can contain multiple create() methods that take various initialization arguments for the bean to be created. The create() method returns a reference to our bean's remote interface (ProfileServer, in this case). As shown in Table 7-1, for each create() method on the home interface, the EJB object implementation must have a matching ejbCreate() method that takes the same arguments. The create() method on the home interface has to declare that it throws java.rmi.RemoteException, since the home interface is an RMI remote interface. It also has to throw javax.ejb.CreateException, in case some error occurs during the EJB creation process (as opposed to some general RMI-related problem). If the corresponding ejbCreate() method on the bean implementation throws any other exceptions, the create() method has to include these in its throws clause as well. In this example, the bean's ejbCreate() method doesn't throw any exceptions, so we don't need to add any additional exceptions here. Home interfaces for entity beans can also include finder methods, used to find existing persistent entity beans that were previously created. We'll discuss them in detail a bit later, when we talk about entity beans. 7.4.2. Remote InterfaceYou usually start putting together an EJB by defining its remote interface. This interface contains declarations of the methods that are available to remote clients, so it really points to the heart of the EJB object. The remote interface for our ProfileServer is shown in Example 7-2. A remote EJB interface must extend the javax.ejb.EJBObject interface. EJBObject in turn extends the java.rmi.Remote interface, which makes the EJB remote interface an RMI remote interface as well. Example 7-2. Remote Interface for the Profile Server Beanimport javax.ejb.*; import java.rmi.RemoteException; import java.rmi.Remote; public interface ProfileServer extends EJBObject { public Profile getProfile(String name) throws NoSuchPersonException, RemoteException; } The ProfileServer interface defines a single remote method, getProfile(), that accepts a username as its only argument. It returns a Profile object, containing the profile information for the person named. If the person's profile cannot be found on the server, a NoSuchPersonException is thrown. This is an application-specific exception whose implementation isn't shown here. Since the ProfileServer interface is an RMI remote interface, its methods must throw RemoteException in case some RMI communication problem occurs during a method call. Also, the arguments and return values for the methods have to be Serializable, and/or they need to be exportable RMI objects themselves. Our getProfile() method returns a Profile object, which we'll implement as an RMI-exportable object. The remote interface for Profile is shown in Example 7-3. The interface has only two remote methods, one to set profile entry values and one to get those values. Note: the implementation of the Profile remote interface isn't shown in this chapter. Example 7-3. RMI Remote Interface for a Profile Objectimport java.rmi.Remote; import java.rmi.RemoteException; public interface Profile extends Remote { public String getProfileEntry(String name) throws RemoteException; public void setProfileEntry(String name, String value) throws RemoteException; } When you deploy your EJB object, you can specify who is allowed to call each method on your bean through the remote interface. In this case, we might want only certain clients to be able to query for user profiles, so we might want to limit access to the getProfile() method on our ProfileServer bean. We discuss the access control features of bean deployment descriptors later in the chapter. 7.4.3. The Bean ImplementationNow that we have a home interface that lets clients create EJB references and a remote interface that describes the EJB methods, we need to actually implement the EJB object itself. Our ProfileServerBean is shown in Example 7-4. If you are familiar with RMI, this should look like an RMI server object, with some extra methods included. These extra methods are the hooks the EJB container uses to manage the bean as a component. At the end of the class is the implementation of the getProfile() method from the remote interface. The ejbCreate() method is also included here, to match the create() method on the home interface. Example 7-4. The ProfileServerBean Implementationimport javax.ejb.*; import java.rmi.RemoteException; public class ProfileServerBean implements SessionBean { private SessionContext mContext = null; // Session bean methods public void ejbPassivate() { System.out.println("ProfileServerBean passivated."); } public void ejbActivate() { System.out.println("ProfileServerBean activated."); } public void ejbCreate() { System.out.println("ProfileServerBean created."); } public void ejbRemove() { System.out.println("ProfileServerBean removed."); } // Get session context from container public void setSessionContext(SessionContext context) { System.out.println("ProfileServerBean context set."); mContext = context; } // Business methods public Profile getProfile(String name) throws NoSuchPersonException { // Here, we just create a ProfileImpl and return it. ProfileImpl profile = null; try { profile = new ProfileImpl(name); } catch (RemoteException re) { System.out.println("Failed creating profile for " + name); re.printStackTrace(); throw new NoSuchPersonException(); } return profile; } } The class for an EJB object must implement the javax.ejb.EnterpriseBean interface. This is usually done indirectly, through either the javax.ejb.SessionBean interface or the javax.ejb.EntityBean interface. In our example, we're defining a session bean, so the ProfileServerBean class implements the SessionBean interface. The EJB class must be declared as public, to allow the container to introspect the class when generating the classes that hook the bean to the container and to allow the container to invoke methods on the bean directly where necessary. The bean class can optionally implement the bean's remote interface, but this isn't strictly required. In our case, we haven't implemented the bean's remote ProfileServer interface in the ProfileServerBean class. When the EJB server generates the classes that bridge the bean to the container, it also provides a class that implements the remote interface and acts as a proxy to the EJB class itself.[4]
In fact, for practical reasons, you probably don't want your EJB implementation to implement the remote interface for your bean. The remote interface has to extend the EJBObject interface, which includes a set of abstract methods that clients can use to retrieve the bean's home interface, get the primary key for entity beans, etc. When you deploy your bean, you'll use tools provided by the EJB container tools to generate stub and skeleton classes for the remote interface that implement these methods from EJBObject. If you implement the remote interface with your bean implementation class, you have to provide implementations for the EJBObject methods as well. All Enterprise JavaBean objects, whether they are session beans or entity beans, must implement the following methods:
These methods are used by the bean's container to notify the bean of various changes in its runtime state. In our example, the ProfileServerBean doesn't need to perform any actions in these methods, so they are included as empty methods that simply print messages to standard output, indicating that they have been called. Copyright © 2001 O'Reilly & Associates. All rights reserved. | |||||||||||||||
|