5.5 Local Interfaces
One of the new features added in the EJB 2.0 specification is local interfaces for session and entity beans. What are local interfaces and when do you use them?
The EJB examples we've presented so far have all had a home interface, remote interface, and bean implementation class. A client accesses an EJB through either its home interface with create()or through its remote interface using a business method. The EJB container intercepts method invocations and, in turn, calls the respective bean implementation method, or, in the case of create()with a stateless session bean, simply grabs a bean instance from the pool (if possible). Each call from the client to the bean is a remote invocation using the Java Remote Method Invocation (RMI) API. This means argument parameters and return values are copied, serialized, and transmitted remotely. While remote calls give an enterprise application its scalability and accessibility, RMI adds overhead to the network. Furthermore, while we do want certain EJBs to have remote clients (such as our MusicIterator EJB, MusicCart EJB, and Loan EJB presented earlier) some EJBs do not need remote clients.
To implement the Value List Iterator Pattern, we created a stateful MusicIter-ator EJB to interface with a stateless MusicPage EJB. Although a remote client could certainly bypass the front-end MusicIterator EJB and invoke methods on the MusicPage EJB directly, we anticipate that clients would rather use the convenient interface provided by the MusicIterator EJB. Thus, we presume that the only clients of MusicPage EJB will be instances of MusicIterator EJB. If we're willing to limit our deployment so that all instances of MusicIterator EJB and MusicPage EJB share the same Java Virtual Machine (JVM), then we can say that all clients of MusicPage EJB will be local.
What does it mean to be a local client? A local client runs in the same JVM as the bean it accesses. A local client may be a web component or another EJB, but not an application client. With remote access, the location of the EJB is transparent to the remote client (the remote EJB may execute in the same JVM, or it may be on a machine halfway around the world). Furthermore, argument parameters and return values are passed by reference with local calls. This increases performance, since no copies are made. Passing arguments by reference can be risky, however. Methods could use a reference to inadvertently modify an argument passed to it (this is called a side effect). Then, changes to the client's view of an object change the EJB's view as well.
The MusicPage EJB is a good candidate for local access because it is tightly coupled with the MusicIterator EJB. These two enterprise beans were designed to work in tandem, and limiting their execution to the same JVM makes sense in this case. Furthermore, argument passing involves read-only operations, so we don't need to worry about side effects to parameter objects.
Other common uses of local interfaces are with the Session Facade Pattern (see "Session Facade Pattern" on page 250) and entity bean container-managed persistence (see "Introducing Container-Managed Persistence" on page 278).
Implementation Guideline
It's also possible to implement an enterprise bean with both local and remote access, although this is not common in production environments. Since you cannot access an enterprise bean from an application client through its local interface (which is typically how you would test your EJB code), you should consider implementing remote access for testing and debugging.
Local Interface Implementation
How do you implement an EJB with local access? As you might guess, it's all a matter of the interfaces. Access to the create() methods is through the local home interface. Access to the bean's business methods is through the local interface. These interfaces are distinct from their "remote cousins" and extend different interfaces. Thus, the local home interface extends EJBLocalHome(instead of EJBHome) and the local interface extends EJBLocalObject (instead of EJBOb-ject). Since access is specifically not remote, do not specify RemoteException in the throws clause for any method in a local interface.
Let's update our filename conventions in Table 5.1 to include local and local home interfaces.
Figure 5-11 shows a class diagram of the classes and interfaces that we write for MusicPage EJB with local interfaces. Interface MusicPageLocalHome is the local home interface extending interface EJBLocalHome. Interface MusicPage-Local is the local interface extending interface EJBLocalObject. And finally, class MusicPageBean is the bean implementation class that implements class SessionBean(unchanged from the previous implementation). Class Contain-erProxyintercepts calls made through the local home and local interfaces and forwards them to the appropriate method in class MusicPageBean.
Figure 5-11 Class Diagram Showing the EJB Classes for a Session Bean with Local Interfaces
Table 5.1 Naming Conventions for EJB Class and Interface Names
EJB Class/Interface |
Name |
Example |
Remote Interface |
Bean Name |
MusicPage |
Home Interface |
Bean Name + Home |
MusicPageHome |
Local Interface |
Bean Name + Local |
MusicPageLocal |
Local Home Interface |
Bean Name + LocalHome |
MusicPageLocalHome |
Bean Implementation Class |
Bean Name + Bean |
MusicPageBean |
Before we show you the MusicPage EJB with local interfaces, let's review the component architecture of our MusicCart web application and add in characteristics of the EJBs. In Figure 5-12 we've noted EJB access (remote or local), as well as which EJBs are stateful session beans (SFSB) and which are stateless session beans (SLSB). Note that anytime access is remote, the client and server components may execute in different JVMs (and thus on different machines). For local access, the client and server components must run in the same JVM.
Figure 5-12 Architectural Overview of the Music Shopping Cart Enterprise Application
Local Home Interface
We define the local home interface in MusicPageLocalHome, shown in Listing 5.20. Note that this interface extends the EJBLocalHome interface. Method create()does not need a RemoteExceptionin its throwsclause and it returns a local interface object (MusicPageLocal) instead of a remote interface object.
Listing 5.20 MusicPageLocalHome.java
// MusicPageLocalHome.java import javax.ejb.CreateException; import javax.ejb.EJBLocalHome; public interface MusicPageLocalHome extends EJBLocalHome { MusicPageLocal create() throws CreateException; }
Local Interface
We define local interface MusicPageLocal in Listing 5.21 and extend it from interface EJBLocalObject. Note that none of the methods should have RemoteException in their throws clauses. Although the method names and signatures are all identical to their remote versions, we now pass parameters and return values by reference rather than by value.
Listing 5.21 MusicPageLocal.java
// MusicPageLocal.java import javax.ejb.EJBLocalObject; import java.util.*; public interface MusicPageLocal extends EJBLocalObject { public ArrayList getTrackList(RecordingVO rec) throws NoTrackListException; public int getSize(); public ArrayList getPage(int currentIndex, int pageSize); }public interface MusicPageLocal extends EJBLocalObject {
Bean Implementation Class
For local interfaces, what changes must be made to our MusicPageBeanimple-mentation class? The answer is none. Thus, unless the bean implementation code needs to make some changes because of the way method parameters and return objects are treated, no changes are required.
MusicIterator Client
We must also update the code in MusicIteratorBean.java (Listing 5.13 on page 160) to access client MusicPage EJB through the local interfaces. Here are the changes:
We no longer have to import class javax.rmi.PortableRemoteObject.
We change the declaration of state variable pageBeanfrom MusicPageto MusicPageLocal:
private MusicPageLocal pageBean = null;
Inside method ejbCreate(), we change the declaration of variable pageHomefrom MusicPageHometo MusicPageLocalHome.
Furthermore, we no longer need PortableRemoteObject.narrowto create a home object:
MusicPageLocalHome pageHome = (MusicPageLocalHome)objref;
Deployment Descriptor
The deployment descriptor must reflect changes to both the description of MusicPage EJB (we have local and local home interfaces) and to its client, MusicIterator EJB. The client now specifies the local and local home interfaces for accessing the MusicPage EJB. In assembling our components, we've placed both the MusicPage EJB and the MusicIterator EJB in the same JAR file. Listing 5.22 shows the new deployment descriptor for <ejb-jar>(the EJB JAR file). You might want to compare this deployment descriptor to Listing 5.9 on page 156 and Listing 5.14 on page 163.
Listing 5.22 Deployment Descriptor for MusicJAR
<ejb-jar> <display-name>MusicPageJAR</display-name> <enterprise-beans> <session> <display-name>MusicPageBean</display-name> <ejb-name>MusicPageBean</ejb-name> <local-home>MusicPageLocalHome</local-home> <local>MusicPageLocal</local> <ejb-class>MusicPageBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Bean</transaction-type> <env-entry> <env-entry-name>MusicDAOClass</env-entry-name> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>MusicDAOCloudscape</env-entry-value> </env-entry> <security-identity> <description></description> <use-caller-identity></use-caller-identity> </security-identity> <resource-ref> <res-ref-name>jdbc/MusicDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> <res-sharing-scope>Shareable</res-sharing-scope> </resource-ref> </session> <session> <display-name>MusicIteratorBean</display-name> <ejb-name>MusicIteratorBean</ejb-name> <home>MusicIteratorHome</home> <remote>MusicIterator</remote> <ejb-class>MusicIteratorBean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Bean</transaction-type> <ejb-local-ref> <ejb-ref-name>ejb/MusicPage</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local-home>MusicPageLocalHome</local-home> <local>MusicPageLocal</local> <ejb-link>MusicPageBean</ejb-link> </ejb-local-ref> <security-identity> <description></description> <use-caller-identity></use-caller-identity> </security-identity> </session> </enterprise-beans> </ejb-jar>
You'll note that descriptor tags for MusicPage EJB now include <local-home> and <local>. Also, the descriptor tags for MusicIterator EJB include <ejb-local-ref> (a local EJB reference to MusicPage EJB). As before, MusicPage EJB is a stateless session bean; MusicIterator EJB is a stateful session bean.