Section 6.13. Home Interfaces


6.13. Home Interfaces

An EJB Home Interface is a factory that creates and removes EJB objects in an EJB container. A Session Bean's create( ) method initializes a new Session Bean and returns a proxy object so the client can start using the EJB. An EJB Home is analogous to a POJO's constructor, except that the EJB Home's create method gives you a client-side proxy rather than a concrete object. If you use a Local EJB Home, then you're using a Local Interface to call its business methods. If you look up a Remote EJB Home, then you're working with a Remote Interface to access a Bean's business methods.

6.13.1. Local Home Interface

The Local Home Interface defines an EJB's lifecycle methodsthat create and remove bean instancesused by local, or co-located clients (Servlets, POJOs, or EJBs) that run inside the container. Our Local Home Interface, InventoryFacadeLocalHome, looks like Example 6-11.

Example 6-11. InventoryFacadeLocalHome.java
 package com.jbossatwork.ejb; public interface InventoryFacadeLocalHome extends javax.ejb.EJBLocalHome {     public static final String COMP_NAME="java:comp/env/ejb/InventoryFacadeLocal";     public static final String JNDI_NAME="InventoryFacadeLocal";     public com.jbossatwork.ejb.InventoryFacadeLocal create(  )         throws javax.ejb.CreateException; } 

This is a Session Bean, so you only need a simple create( ) method with an empty argument list.

6.13.2. Remote Home Interface

The Remote Home Interface defines an EJB's lifecycle methodsthat create and remove bean instancesused by applications outside the container. Example 6-12 is our Remote Home Interface, InventoryFacadeRemoteHome.

Example 6-12. InventoryFacadeRemoteHome.java
 package com.jbossatwork.ejb; public interface InventoryFacadeRemoteHome extends javax.ejb.EJBHome {     public static final String COMP_NAME="java:comp/env/ejb/InventoryFacade";     public static final String JNDI_NAME="InventoryFacadeRemote";     public com.jbossatwork.ejb.InventoryFacadeRemote create(  )         throws javax.ejb.CreateException,java.rmi.RemoteException; } 

6.13.3. The Bean Class

The Bean Class provides the implementation for a Session Bean's business methods. Our Bean Class, InventoryFacadeBean, looks like Example 6-13.

Example 6-13. InventoryFacadeBean.java
 package com.jbossatwork.ejb; import java.util.*; import javax.ejb.*; import com.jbossatwork.dao.*; import com.jbossatwork.dto.CarDTO; public class InventoryFacadeBean implements SessionBean {     private SessionContext sessionCtx;     // EJB 2.1 mandated methods.     public void setSessionContext(SessionContext sessionCtx) throws EJBException {         this.sessionCtx = sessionCtx;     }     public void ejbCreate(  ) throws CreateException {  }     public void ejbRemove(  ) throws EJBException {  }     public void ejbActivate(  ) throws EJBException {  }     public void ejbPassivate(  ) throws EJBException {  }     // Business methods.     public List listAvailableCars(  ) throws EJBException {         CarDAO carDAO = new HibernateCarDAO(  );         return carDAO.filterByStatus(CarDTO.STATUS_AVAILABLE);     }     ... } 

Think of the InventoryFacadeBean as an encapsulation of all the inventory-related business functions. Each business method wraps all the activities to implement a User Story or Use Case. Consider each business method as a service that's available to clients, such as a web application, a GUI, or a Web Service client. The listAvailableCars( ) method tells the CarDAO to return only the cars that are still available (unsold). The DAO is devoid of any real business logicit's only responsible for CRUD operations on the CAR table in the database.

In addition to business methods, we must implement the following callback methods because a Session Bean implements the javax.ejb.SessionBean interface:

  • setSessionContext( )

  • ejbCreate( )

  • ejbRemove( )

  • ejbActivate( )

  • ejbPassivate( )

The EJB container calls these methods during an EJB's lifecycle (from creation, invoking business methods, through removal). With the exception of setSessionContext( ), all these methods are usually empty for Stateless Session Beans. Even though we have only one real business method, we have to add five other methods (four of which are empty) just to comply with the EJB specification. These extra methods are inconvenient because they don't add any real value, but can't deploy our EJB if we don't have them.

We've written the code for the InventoryFacadeBean, and now it's time to deploy the Bean.

6.13.4. EJB Deployment Descriptors

After developing a Session Bean's classes and interfaces, deploy it by adding information about the EJB (meta-data) to the J2EE standard (ejb-jar.xml) and JBoss (jboss.xml) EJB deployment descriptors .

In ejb-jar.xml, the <enterprise-beans> element lists all EJBs in the application. The <session> element describes the bean by telling the container:

  • That it's a Session Bean.

  • About all the classes that make up the bean.

  • That it's Stateless.

  • That it uses container-managed transactions (CMT).

  • That it uses a Hibernate Session Factory.

Example 6-14 is the ejb-jar.xml file.

Example 6-14. ejb-jar.xml
 <?xml version="1.0" encoding="UTF-8"?> <ejb-jar xmlns=http://java.sun.com/xml/ns/j2ee  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" version="2.1">   <enterprise-beans>     ...     <session>       <display-name>InventoryFacadeSB</display-name>       <ejb-name>InventoryFacade</ejb-name>       <home>com.jbossatwork.ejb.InventoryFacadeRemoteHome</home>       <remote>com.jbossatwork.ejb.InventoryFacadeRemote</remote>       <local-home>com.jbossatwork.ejb.InventoryFacadeLocalHome</local-home>       <local>com.jbossatwork.ejb.InventoryFacadeLocal</local>       <ejb-class>com.jbossatwork.ejb.InventoryFacadeBean</ejb-class>       <session-type>Stateless</session-type>       <transaction-type>Container</transaction-type>       <resource-ref>         <res-ref-name>hibernate/SessionFactory</res-ref-name>         <res-type>org.hibernate.SessionFactory</res-type>         <res-auth>Container</res-auth>       </resource-ref>     </session>     ...   </enterprise-beans>   ...   <assembly-descriptor>     ...     <container-transaction>       <method>         <ejb-name>InventoryFacade</ejb-name>         <method-intf>Local</method-intf>         <method-name>listAvailableCars</method-name>         <method-params>         </method-params>       </method>       <trans-attribute>Required</trans-attribute>     </container-transaction>     <container-transaction>       <method>         <ejb-name>InventoryFacade</ejb-name>         <method-intf>Remote</method-intf>         <method-name>listAvailableCars</method-name>         <method-params>         </method-params>       </method>       <trans-attribute>Required</trans-attribute>     </container-transaction>     ...   </assembly-descriptor> </ejb-jar> 

The <resource-ref> elements specify the JNDI resources available to the InventoryFacadeBean (or any POJO that it calls). The <res-ref-name> is the JNDI name for the resourcejava:comp/env/hibernate/SessionFactory. Notice that you don't have to specify java:comp/env/it is the assumed prefix. The <res-type> for the hibernate/SessionFactory is a Hibernate Session Factory, so org.hibernate.SessionFactory is its fully qualified class name. We want JBoss to manage our resources, so we set <res-auth> to Container.

The <assembly-descriptor> element describes security constraints, and transactions for all EJBs in the application. Each <container-transaction> element describes the transactional environment for every business method for each bean, for both the Remote and Local component interfaces. The read-only listAvailableCars( ) method wouldn't normally require a transaction, but we're using Hibernate 3 and are forced to set the transaction attributed to Required so that the method is guaranteed to run within a transaction. The "EJB Transaction Settings" section covers transactions, and later sections discuss Hibernate 3 and its relationship to EJBs and CMT.

A JNDI resource is linked into an application only if we ask for it. JBoss binds resources under its in-JVM context, java:/. The jboss.xml file provides a mapping between the J2EE-style ENC names and the local JBoss-specific JNDI names that JBoss uses to deploy EJBs and any related JNDI-based resources. Example 6-15 is the jboss.xml descriptor.

Example 6-15. jboss.xml
 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 4.0//EN"  "http://www.jboss.org/j2ee/dtd/jboss_4_0.dtd"> <jboss>   ...   <enterprise-beans>     ...     <session>       <ejb-name>InventoryFacade</ejb-name>       <jndi-name>InventoryFacadeRemote</jndi-name>       <local-jndi-name>InventoryFacadeLocal</local-jndi-name>       <resource-ref>         <res-ref-name>hibernate/SessionFactory</res-ref-name>         <jndi-name>java:/hibernate/SessionFactory</jndi-name>       </resource-ref>       <method-attributes>       </method-attributes>     </session>     ...   </enterprise-beans>   ...   <assembly-descriptor>   </assembly-descriptor>   ...   <resource-managers>   </resource-managers> </jboss> 

All EJBs described in jboss.xml must be defined in ejb-jar.xml. Here are the key elements:


<session>

Provides JBoss-specific deployment information for a session bean, including the JNDI name.


<ejb-name>

The name of the EJB. This must match the <ejb-name> element for the bean in ejb-jar.xml.


<jndi-name>

The JNDI name that JBoss uses to deploy the EJB. If not specified, JBoss uses the <ejb-name> as the JNDI name.


<local-jndi-name>

The JNDI name that JBoss uses to deploy the EJB for local access. If not specified, JBoss uses the <jndi-name> as the JNDI name. If the deployer provides the <local-jndi-name>, then the <jndi-name> specifies the remote JNDI name.

The <resource-ref> element enables the InventoryFacadeBean (or any POJO that it calls) to look up resources using JNDI. As before, <res-ref-name> is the JNDI name for each resource for which java:comp/env/ is the assumed prefix. The textual value of each <res-ref-name> element in jboss.xml MUST match the value of the <res-ref-name> in ejb-jar.xml. The <jndi-name> is the local JBoss-specific JNDI name that JBoss uses to deploy a Hibernate Session Factory. Since the java:/ ENC is internal to JBoss, the java:/hibernate/SessionFactory JNDI name indicates that the Hibernate Session Factory is available only to applications running inside of JBoss.

Now that we have our classes and interfaces in place, let's take a more detailed look at how EJBs relate to J2EE transactions.

6.13.5. EJB Transaction Settings

The two ways to manage transactions in J2EE are through Container-Managed Transactions (CMT) and Bean-Managed Transactions (BMT). BMT requires extra Java coding to handle transaction logic and forces the developer to manage the transaction and define his own transaction boundaries. In contrast, CMT doesn't require handle transaction logic, pushes transaction settings into deployment descriptors, uses JBoss transaction services, and manages transaction boundaries on behalf of the developer. We'll focus on CMT because it is considered a J2EE best practice and it allows the container to do the work.

A transaction attribute tells the container how to handle CMT transactions for an EJB's business methods. Specify transaction attributes for each Bean in the ejb-jar.xml deployment descriptor. You can set transaction attributes for an entire EJB or for each business methodmethod-level settings take precedence over bean-level settings. Here are the possible values for EJB transaction settings:


Required

The EJB method always runs within the scope of a transaction. If a transaction doesn't currently exist, the container starts a new transaction.


RequiresNew

The container always starts a new transaction before executing the EJB method. If a transaction already exists, the container suspends the current transaction until the new transaction completes.


Supports

The EJB method runs only within the scope of a transaction if the caller started a transaction before invoking the EJB method. If a transaction does not already exist, the EJB method does not run within a transaction.


Mandatory

The caller must start a transaction before invoking the EJB method. If there is no current transaction, the container throws a javax.ejb.TransactionRequiredException.


NotSupported

The EJB method does not run within the scope of a transaction. If a transaction already exists, the container suspends the current transaction until the EJB method completes.


Never

The EJB can not run within the scope of a transaction. If the caller started a transaction before invoking the EJB method, the container throws a javax.ejb.RemoteException (for remote calls) or a javax.ejb.EJBException (for local calls).

Despite the six possible values for EJB transaction settings, you'll use Required, RequiresNew, or Supports most of the time.

6.13.6. Difficulties Using EJB

At this point, you can deploy the example EJB on JBoss, but the overhead of creating at least one set of Home and Component Interfaces plus two XML deployment descriptors (ejb-jar.xml and jboss.xml, including transactional attributes) as well as the business code (the Bean Class) is tedious and burdensome. Ideally, we'd only have to write the Bean Class and somehow let deployment take care of itself. Even the Bean Class has issueswe don't care too much about the callback methods yet, but we're forced to implement them because they're part of the Session Bean interface.

How Will EJB 3.0 Help?

The main purpose of the EJB 3.0 specification (and J2EE 1.5) is to simplify deployment and make it easier to develop EJBs. EJB 3.0 will use annotations to indicate the runtime behavior of an EJB. A Session Bean will require just a business interface (that declares the EJB's business methods) and a single POJO with EJB 3.0 annotations for deployment. Thus the XML deployment descriptors, along with the Home and Component Interfaces, will become relics of the past. Although XDoclet did a great job of generating these artifacts, won't it be great when we don't have to create them at all? As part of EJB 3.0, you don't have to implement the SessionBean interface anymore. So your annotated POJO will contain only business methods and nothing elseyou're no longer forced to implement empty callback methods that you don't care about.

Dependency Injection is a replacement for JNDI lookups and for declaring resource and configuration settings in deployment descriptors. Servlets and EJBs will use annotations to specify their resources and configuration values, and the container "injects" (or uses) these values. Dependency Injection removes the need for JNDI lookup and makes your code simpler.

EJB 3.0 will be a huge leap forward, but the specification won't be final until well after the time of this writing. Although we can't accurately predict the future, we expect EJB 3.0 to be complete by the end of 2005, and that stable, fully functional implementations will be available in the first quarter of 2006.


It's important to know about the future, but we're still on EJB 2.1 because the specification and the JBoss implementation are complete and we know they'll work in a production environment. For now, we need XDoclet to generate the extra programming artifacts, and we just have to live with writing empty callback implementations in our Session Beans.

The next section shows how XDoclet generates the bean's deployment descriptors and the Home and Component Interfaces, freeing you to concentrate on the EJB's business logic.

6.13.7. Automating Stateless Session Bean Deployment Using XDoclet Tags

Example 6-16 shows the XDoclet tags in InventoryFacadeBean.

Example 6-16. InventoryFacadeBean.java
 /**  * @ejb.bean  *  name="InventoryFacade"  *  display-name="InventoryFacadeSB"  *  local-jndi-name="InventoryFacadeLocal"  *  jndi-name="InventoryFacadeRemote"  *  type="Stateless"  *  transaction-type="Container"  *  * @ejb.resource-ref  *  res-ref-name="hibernate/SessionFactory"  *  res-type="org.hibernate.SessionFactory"  *  res-auth="Container"  *  * @jboss.resource-ref  *  res-ref-name="hibernate/SessionFactory"  *  jndi-name="java:/hibernate/SessionFactory"  *  */ public class InventoryFacadeBean implements SessionBean {     ...     /**      * @ejb.interface-method      *      */     public List listAvailableCars(  ) throws EJBException {         ...     }     ... } 

The class-level @ejb.bean XDoclet tag defines the EJB and generates the <session> element in ejb-jar.xml and jboss.xml. The class-level @ejb.resource-ref XDoclet tag generates the <resource-ref> element for the EJB's Hibernate Session Factory in ejb-jar.xml, and the @jboss.resource XDoclet tag generates the corresponding <resource-ref> element in jboss.xml.

Each method-level @ejb.interface-method tag adds a business method to the Remote and Local component Interfaces.

The XDoclet tags appear in class- and method-level Javadoc comments, and you need to run an external program to look at the Java code, interpret the tags, and generate code and deployment descriptors. The next section shows how to run the XDoclet code generator from Ant.

6.13.8. Ant Build Script Using XDoclet

After modifying the EJB to use XDoclet tags, we now use XDoclet's Ant tasks to generate the Home and Component Interfaces, along with the EJB deployment descriptors (ejb-jar.xml and jboss.xml). Example 6-17 shows a portion of the ejb sub-project's Ant build script that uses XDoclet to generate deployment artifacts.

Example 6-17. ejb/build.xml
  ...  <target name="run-ejbdoclet" description="Generate EJB artifacts">      <taskdef name="ejbdoclet"           classname="xdoclet.modules.ejb.EjbDocletTask"           classpathref="xdoclet.lib.path"/>         <mkdir dir="${gen.source.dir}" />      <ejbdoclet destdir="${gen.source.dir}" ejbspec="2.1">             <fileset dir="${source.dir}">              <include name="**/*Bean.java"/>          </fileset>          <remoteinterface pattern="{0}Remote"/>          <localinterface pattern="{0}Local"/>          <homeinterface pattern="{0}RemoteHome"/>          <localhomeinterface pattern="{0}LocalHome"/>          <deploymentdescriptor destdir="${gen.source.dir}"/>             <jboss version="4.0" destdir="${gen.source.dir}"/>         </ejbdoclet>  </target>  ... 

The run-ejbdoclet invokes XDoclet's <ejbdoclet> Ant task to generate the bean interfaces and deployment descriptors. Here are the important attributes and sub-elements of <ejbdoclet>:


<ejbdoclet>

This task generates the deployment descriptors, along with the Home and Component Interfaces for all EJBs that contain XDoclet tags. The most important attributes are: destdir (where to output the generated Home and Component Interfaces) and ejbspec (the version of the EJB specification to usedefaults to "2.0").


<fileset>

Tells XDoclet where to find the Bean Class files to parse.


<remoteinterface>

Tells XDoclet to generate a Remote Component Interface for all EJBs.


<localinterface>

Tells XDoclet to generate a Local Component Interface for all EJBs.


<remotehomeinterface>

Tells XDoclet to generate a Remote Home Interface for all EJBs.


<localhomeinterface>

Tells XDoclet to generate a Local Home Interface for all EJBs.


<deploymentdescriptor>

Tells XDoclet to generate the standard J2EE ejb-jar.xml deployment descriptor. The destdir attribute tells where to output ejb-jar.xml.


<jboss>

Tells XDoclet to generate the JBoss-specifiec jboss.xml deployment descriptor. The most important attributes here are version (the JBoss version we're using) and destdir (where to output jboss.xml).

Now that we have all of the EJB-related pieces in place, let's JAR everything up.

6.13.9. EJB JAR File

An EJB JAR file is the standard deployment unit for the EJB component (EJBs, JMS Destinations, and so on) portion of a J2EE application. It contains ejb-jar.xml (the J2EE standard EJB deployment descriptor), jboss.xml (the JBoss-specific EJB deployment descriptor), the EJB classes, and a JAR manifest. We deploy the example EJB JAR file inside an EAR file alongside the WAR file containing the Controller Servlet that invokes the InventoryFacade EJB. See Figure 6-1 for the structure of the EJB JAR file.

Figure 6-1. EJB JAR file structure


The EJB JAR file above has the following structure:

  • The root directory. Some applications may store property files in the root directory.

  • The META-INF directory that contains all the metadata: ejb-jar.xml, jboss.xml, and the JAR Manifest file that references external JARS that reside in the application EAR file. The Deployment Chapter has more information on EAR files, JAR Manifest files, and ClassLoaders.

  • The com/jbossatwork/ejb directory holds EJB class files.

Now that we know the structure of the EJB JAR file, let's use Ant to create the JAR file.

6.13.10. Ant Task for Creating EJB JAR

Example 6-18 is another portion of the ejb sub-project's Ant build script that creates the EJB JAR file.

Example 6-18. ejb/build.xml
 ...  <target name="build-ejb-jar" depends="run-ejbdoclet, compile"          description="Packages the EJB files into a EJB JAR file">      <mkdir dir="${distribution.dir}" />         <jar destfile="${distribution.dir}/${ejb.jar.name}"           basedir="${classes.dir}">          <metainf dir="${gen.source.dir}" includes="*.xml"/>      </jar>  </target>  ... 

The <build-ejb-jar> target depends on the run-ejbdoclet (from the previous Ant code example) to generate all the EJB-related programming artifacts and the compile target to compile all the code. The <jar> task creates the EJB JAR file (ejb.jar) and copies the compiled Bean Class, along with the Home and Component Interfaces, into the JAR file (preserving the package directory structure). The <jar> task also copies the EJB deployment descriptors (ejb-jar.xml and jboss.xml) into the JAR's META-INF directory. So there's no real "magic" to creating an EJB JAR filethe <jar> task above looks similar to something you've seen before. The only real difference between a plain JAR file and the EJB JAR file is that you have deployment descriptors in the META-INF directory.

Now that we have our EJB JAR, let's include it in our EAR.

6.13.11. Adding an EJB JAR to the EAR

We've already covered the structure and contents of an EAR file in the Deployment chapter. Here are the steps to add the EJB JAR file to the EAR:

  • Register the EJB JAR file in application.xml.

  • Copy the EJB JAR file into the EAR.

Example 6-19 is a portion of the application.xml file that now includes the new EJB JAR file, ejb.jar.

Example 6-19. application.xml
 <?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://java.sun.com/xml/ns/j2ee"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"  version="1.4">   <display-name>JBossAtWorkEAR</display-name>   <module>     <web>       <web-uri>webapp.war</web-uri>       <context-root>ch06</context-root>     </web>   </module>   ...   <module>     <ejb>ejb.jar</ejb>   </module>   ... </application> 

As we've seen in previous chapters, the <module> element defines a J2EE module (WAR, EJB JAR, and JAR) contained in the EAR. The <ejb> element specifies the EJB JAR file name relative to the EAR file's top-level directory.

Adding the EJB JAR file to the EAR is trivial. Example 6-20 shows a portion of the main Ant build script (ch06-a/build.xml) that creates the EAR.

Example 6-20. build.xml
  ...  <ear destFile="${distribution.dir}/${ear.name}"       appxml="${meta-inf.dir}/application.xml">      <fileset dir="${ejb.jar.dir}"/>      <fileset dir="${webapp.war.dir}"/>      <fileset dir="${common.jar.dir}"/>         ...  </ear>  ... 

We've seen the <ear> task before. The only difference is that now we're copying the EJB JAR file into the EAR by adding a <fileset> task that includes the EJB JAR file.



JBoss at Work. A Practical Guide
JBoss at Work: A Practical Guide
ISBN: 0596007345
EAN: 2147483647
Year: 2004
Pages: 197

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