C H A P T E R  3

Scenario: An EJB Module

FIGURE 3-1 shows an EJB module that is typical in form--a session bean and several entity beans--and engages in interactions that are typical for an EJB module. EJB modules provide server-side services within a J2EE application, so they must be able to interact with other modules in the application (this interaction is represented in the figure by arrow labeled #1). Most EJB modules contain more than one EJB component, and the enterprise beans interact with each other (represented in the figure by arrow #2). Most EJB modules also interact with external resources, such as relational database management systems (represented in the figure by arrow #3).

 FIGURE 3-1 Catalog EJB Module

Diagram of the EJB module covered in this chapter, which contains a session bean and two entity beans.[ D ]


The Interactions in This Module

This scenario looks at an EJB module that participates in the three types of interaction shown in FIGURE 3-1. The module is part of a J2EE application that supports a retail web site. Within the web site application, this EJB module supplies the data for the online catalog. This is a typical role for an EJB module in a J2EE application.

Another module in the application functions as a client of the catalog EJB module. This client module, typically a web module, requests the data, formats it, and displays it to online shoppers. The catalog data EJB module's responsibility is getting the requested data from the database and passing it to the client module. The catalog data EJB module must be able to process requests for data and return the correct data. More specifically, providing the catalog data requires these interactions:

1. The client module asks the catalog data EJB module for some catalog data. In this simple example, the client can ask either for a list of all the items in the catalog, or for detailed information about one item.

2. The catalog data EJB module processes the request by generating a database query that will get the requested data.

3. The catalog data EJB module executes the query and returns the data to the client module. The client then formats the data and displays it to the user.

These interactions between the client module and the catalog EJB module have some characteristics that determine both the J2EE technologies you choose to implement them and the internal structure of the catalog data module. First, the interaction between client modules and the catalog module is synchronous: online shoppers will ask to see the catalog and wait for the application to display it. To provide a synchronous interaction, you choose to implement this interaction with Java RMI. This means that client modules will request catalog data by invoking methods of the catalog data module.

Second, the interactions between client modules and the catalog EJB module are session-oriented. An online shopper can look at a display of the whole catalog and then request detail for a single item. With multiple end users looking at the catalog simultaneously, your EJB module needs to map requests to user sessions and return the correct data to each session. For this reason, you decide that clients need to interact with a stateful session bean enterprise bean in the catalog module. The session bean will manage the processing of each request submitted by a client module. (For details of using session beans to model sessions, see Building Enterprise JavaBeans Components.)

For the database operations, J2EE provides a type of enterprise bean known as entity enterprise beans. Entity beans model database tables, and they have methods that execute queries and work with the data stored in the tables they model. The catalog data is stored in two tables, so the catalog data module will have two entity enterprise beans, each modeling one of these tables. Connections, query language, and other aspects of the database operations are handled by these entity beans.

After considering these requirements, you design a module like the one illustrated in FIGURE 3-1. Client modules interact only with the session enterprise bean. The session bean manages the incoming requests and calls methods of the entity enterprise beans to obtain the requested data.


Programming This Module

TABLE 3-1 summarizes the programming required to create the EJB module illustrated in FIGURE 3-1.

TABLE 3-1 Programming Required for This Scenario

Application Element

Programming Required

Application server

None.

EJB module

Create a session bean (CatalogManagerBean) with remote interfaces (remote interfaces are appropriate handling remote method invocations from other modules). Add business methods that return catalog data to the caller. One of these business methods returns all items in the catalog, the other returns detail for any item selected by the client.

Create two entity enterprise beans (itemBean and itemDetailBean) to represent the two database tables that contain the catalog data. Create local interfaces for these entity enterprise beans (this is appropriate for method invocations within the module). Add a method to the itemBean that returns all items in the catalog. Requests for detail on a specific item will use the itemDetailBean's findByPrimayKey method. The session bean calls these methods to obtain the catalog data.

Create detail classes (one for the Item table, one for the ItemDetail table). The catalog data module will return these instances of these classes to the caller.

Create the catalog data EJB module, which creates an EJB module node in the IDE's Explorer. Add the three enterprise beans to the module.

After creating the EJB module, specify the datasource for the catalog data, as a property of the module.

J2EE application

To see how you add an EJB module to a J2EE application see Chapter 4.


The sections that follow show you how to perform many of these programming tasks. Interfaces and method signatures are used to show the inputs to the catalog data module and the outputs from it. The procedures show how to connect these inputs and outputs to other components, other modules, and the catalog database. Instructions for creating the enterprise beans, adding business methods, and implementing the business methods with Java code are not included. If you need to learn about these tasks, see the online help or Building Enterprise JavaBeans Components.

Creating Remote Interfaces for the Session Enterprise Bean

The design for the catalog data module is that client modules get catalog data by calling methods of the stateful session bean, using Java RMI. To make this interaction possible, the session enterprise bean must have remote interfaces. You generate the remote interfaces when you create the session bean with the Session Bean Wizard. (For more information on the Session Bean Wizard see the online help.) CODE EXAMPLE 3-1 shows the completed home and remote interfaces for the stateful session bean.

CODE EXAMPLE 3-1 Home and Remote Interfaces for the Session Bean
public interface CatalogManagerBeanHome extends javax.ejb.EJBHome {
  public CatalogBeans.CatalogManagerBean create()
    throws javax.ejb.CreateException, java.rmi.RemoteException;
}
 
 
public interface CatalogManagerBean extends javax.ejb.EJBObject {
  public java.util.Vector getAllItems() throws java.rmi.RemoteException;
  public CatalogBeans.idDetail getOneItemDetail(java.lang.String sku)  
    throws java.rmi.RemoteException;
}

Client modules can do two things with this interface. When clients wants to see the entire catalog, they calls the getAllItems() method; when they wants detail they call the getOneItemDetail() method. (Most real-world shopping applications provide more functionality that this. But the additional functionality would appear as more methods in these interfaces.)

The implementations of these methods (shown in CODE EXAMPLE 3-4), which are encapsulated by the catalog module, calls methods of the entity beans. The entity beans connect to the database and return the requested data as entity bean instances.

Because clients of the catalog data module do not update the database, the EJB module does not need to return the data in the form of entity bean instances. (Returning entity bean instances would allow the client to update fields of the instances. The container tracks changes to entity bean instances and it would automatically generates database updates.) Instead, to reduce the network bandwidth consumed by passing remote references to entity bean instances, the catalog data module returns instances of ordinary Java classes. These classes, known as detail classes, have the same fields as the entity beans. Data from entity bean instances is copied to detail class instances and the detail class instances are returned to the client. For more information on using detail classes with entity enterprise beans, see Building Enterprise JavaBeans Components.

To see how a client uses these remote interfaces to interact with the catalog data module, see .

Creating Local Interfaces for the Entity Enterprise Beans

To obtain the data that clients request, the CatalogManagerBean is going to call methods of the entity beans. Since these calls are within the module, there is no need for the entity beans to have resource-consuming remote interfaces. Instead, you can use local interfaces. Local interfaces are much faster and more efficient than remote interfaces, and you should use them whenever a remote interaction isn't necessary.

Generate the local interfaces when you create the entity beans with the Entity Bean Wizard. (For more information on the Session Bean Wizard see the online help.) CODE EXAMPLE 3-2 shows the completed local interfaces for one of the entity beans. The interfaces for the other entity bean are similar.

CODE EXAMPLE 3-2 Local Home and Local Interfaces for a Entity Bean
public interface ItemBeanLocalHome extends javax.ejb.EJBLocalHome {
  public CatalogBeans.ItemBeanLocal findByPrimaryKey(java.lang.String aKey)
    throws javax.ejb.FinderException;
  public java.util.Collection findAll() throws javax.ejb.FinderException;
}
 
 
public interface ItemBeanLocal extends javax.ejb.EJBLocalObject {
  public CatalogBeans.iDetail getIDetail();
}

The CatalogManagerBean session bean can call findAll() to obtain a list of all the items in the catalog.



Note - If you plan to test individual enterprise beans with the Sun ONE Studio 4 test application feature, you need to generate both remote and local interfaces. The test application feature will generate a web module client that exercises one enterprise bean's methods, and the web module client needs the remote interfaces.



Using the Local Interfaces in the Session Enterprise Bean

Client modules requests data by calling one of the CatalogManagerBean's business methods. (These are the methods declared in the CatalogManagerBean interface. See CODE EXAMPLE 3-1.) The implementations of these business methods manage the processing of the request for catalog data. They include calls to methods of the entity beans. To call entity bean methods, the session bean needs local EJB references to the local interfaces you created for the entity bean. Like most J2EE references, you need to program two separate parts to the reference.

  • JNDI lookup code. Each of the session bean's business methods includes code that uses the JNDI naming facility to obtain a reference to an entity bean's LocalHome.
  • A declaration of the reference. This is used by the runtime environment to identify the specific bean referred to by the lookup code.

JNDI Lookup Code for Local EJB References

CODE EXAMPLE 3-3 is the implementation of the session bean's getAllItems() method. Client modules call this method when they want to obtain data that lists all of the items in the online catalog. The method implementation shows you how the CatalogManagerBean manages the request. There are three steps:

1. The session bean uses JNDI lookup to obtain a local reference to the entity bean.

2. The session bean calls the entity bean's findAll() method.

3. The session bean copies the catalog data from entity bean instances to detail class instances, adds the detail class instances to a vector and returns the vector to the client.

Comments in the code identify these steps.

CODE EXAMPLE 3-3 CatalogManagerBean's getAllItems Method
public java.util.Vector getAllItems() {
  java.util.Vector itemsVector = new java.util.Vector();
  try{
    if (this.itemHome == null) {
    try {
      // Use JNDI Lookup to Obtain Reference to Entity Bean's Local
      InitialContext iC = new InitialContext();
      Object objref = iC.lookup("java:comp/env/ejb/ItemBean");
      itemHome = (ItemBeanLocalHome) objref;
    }
    catch (Exception e) {
      System.out.println("lookup problem" + e);
    }
 
    // Use Local Reference to Call findAll().
    java.util.Collection itemsColl = itemHome.findAll();
    if (itemsColl == null) {
      itemsVector = null;
    }
    else { 
       // Copy Data to Detail Class Instances.
      java.util.Iterator iter = itemsColl.iterator();
      while ( iter.hasNext() ) {
      iDetail detail;
      detail = ((CatalogBeans.ItemBeanLocal) iter.next()).getIDetail();
      itemsVector.addElement(detail);
    }
  catch (Exception e) {
    System.out.println(e);
  }
  return itemsVector; 
}

The lookup specifies "ItemBean", but this is actually the name of the reference, not the name of the referenced enterprise bean. The enterprise bean's name is often used as the reference name, to make it easier to remember which enterprise bean is meant. The enterprise bean is specified in the next step.

Reference Declaration for Local EJB References

To complete the JNDI lookup code, you need to set up a reference declaration as a CatalogManagerBean property. The reference declaration maps the reference name (used in the lookup statement) to an actual enterprise bean. To set up a reference declaration:

1. Right click the calling bean's node (in this case the CatalogManagerBean), choose Properties from the contextual menu, then choose the following sequence: the References tab, and the EJB Local References property, the ellipsis (...) button, and the Add button.

The Add button opens a dialog that lets you add a new reference declaration.

2. To add a reference declaration you must supply a reference name that matches the name used in the lookup statement and map it to the name of the enterprise bean.

The typical way to do this is to type in the Reference Name, matching exactly the string used in the JNDI lookup statement, and then click the Browse button. This opens a dialog that lets you select the matching enterprise bean FIGURE 3-2. shows the Add EJB References Dialog for the CatalogManagerBean, with these fields filled in for a local reference to the ItemBean.

 FIGURE 3-2 Add EJB Reference Dialog Box

Screenshot of Add Local EJB Reference dialog box.[ D ]

Assembling the EJB Module

After creating the enterprise beans that will make up the CatalogData module, you need to create and configure the EJB module. In the Sun ONE Studio 4 IDE, you configure the module on its property sheets by setting the module's properties to describe the module's runtime behavior and request specific runtime services from the J2EE environment.

The module's properties include server-specific properties for different implementations of the J2EE runtime environment (different application server products).

Creating the EJB Module

There are two ways to create an EJB module in the IDE. Both procedures create an EJB module node in the location you specify. The EJB module node represents a description of the contents of the module. It identifies the source files for all the components you add to the module, but it does not copy them to the directory where you put the EJB module node. Keep this in mind when you decide where to put your EJB module.

If you keep all of the source code for the module in a single filesystem, you could put your EJB module node at the top level of that filesystem. If the source code for the module is in different filesystems, even in filesystem that are owned by different developers, you might create a set of directories containing only modules and J2EE applications, which is separate from the filesystems containing the source code.

To create an EJB module from an enterprise bean node:

1. Right-click an enterprise bean node, and choose New EJB Module from the contextual menu.

This opens a dialog in which you name the module and choose a place in the filesystem for it. You choose a filesystem, directory, or package.

2. A node representing your new module is created underneath the filesystem, directory, or node you selected, and the enterprise bean you right-clicked on to begin the procedure is automatically included in the new module.

You can add more enterprise beans to the module. See Adding Enterprise Beans and Other Resources to the Module.

To create an EJB module from a filesystem, package, or directory node:

1. Right-click on a Explorer window node and then choose the following sequence of commands from the contextual menu: New right arrow J2EE right arrow EJB Module.

This opens a dialog on which you name the module. Click OK.

2. A node representing your new module is created underneath the filesystem, package, or directory you selected.

Both of these procedures represent your new module by a node in the directory you chose. Information describing the module, information that will eventually be used to generate a deployment descriptor for the module, is stored in this directory. The source code for the components in the module is not copied into this directory.

Adding Enterprise Beans and Other Resources to the Module

Once you have created a module you can add enterprise beans to it. To add an enterprise bean to an EJB module:

1. Right-click the module node and choose "Add EJB..." from the contextual menu.

This opens a dialog in which you can browse all your mounted filesystems for enterprise beans.

2. Select an enterprise bean and click OK. This adds a node representing the enterprise bean underneath the module node.

You can continue using this command until you have added all the enterprise beans that belong in the module.

3. When you add an enterprise bean to a module, the IDE manages any dependencies of the enterprise bean on other kinds of resources (Java classes, files, and so on). It automatically includes these in the module when you compile or deploy the module.

For the few exceptions to this, see Identifying Extra Files.

Notice that the source code for enterprise beans you add to the module is not copied into the directory that holds the module node.

Specifying a Datasource for the Entity Enterprise Beans

In this scenario, the CatalogData module must access a database to get the catalog data. You need to specify the datasource as part of configuring, or assembling, the module. Keep in mind that there are two times when you specify a datasource for an entity bean. First, at development time, you can open a live connection to a database, select a table, and tell the Entity Bean Wizard to create an entity bean that models the table you selected. (You can also use a database schema instead of a live connection.) This is covered in Building Enterprise JavaBeans Components.

Second, before you deploy the entity bean, you need to specify the database that will be used at runtime. This section covers this second case. To specify a datasource for use at runtime, you use the EJB module's property sheet to configure a resource reference for the datasource.

The way you set up the resource reference depends on the type of entity bean you are working with:

  • If you are working with an container-managed entity bean, you identify the datasource on one of the module's server-specific property tabs. The server product determines how you identify the datasource. In most cases, including the J2EE Reference Implementation, you identify the datasource by JNDI name.
  • If you are working with a bean-managed entity bean, you must set up the resource reference with JNDI lookup code and a reference declaration that maps the lookup to the datasource JNDI name.
Using the Server-specific Tabs for Container-managed Entity Beans

For container-managed entity beans, you simply specify the datasource, by JNDI name, on the module's property sheet. The IDE creates the resource reference for you automatically.

Data sources are assigned JNDI names when data sources are defined to a specific application server. You need to supply the JNDI name that is valid for the J2EE runtime environment (application server product) you are using, on the server-specific tab for that particular runtime environment. FIGURE 3-3 shows the CatalogData module's J2EE RI tab. The Data Source JNDI name property contains the JNDI name for the default Pointbase database.

 FIGURE 3-3 EJB Module Server-specific Properties

Screenshot of EJB module property sheet showing J2EE RI specific tab.[ D ]

Both the J2EE RI server and the PointBase database server were installed with Sun ONE Studio 4. In addition, the Pointbase database was defined to the J2EE RI server as "jdbc/Pointbase," so supplying this name in the Data Source JNDI Name property points to a specific database instance.

If you are using a different database product with the J2EE RI server, you need to use J2EE RI administration tools to define the datasource to the J2EE RI server. After you do this, the datasource will have a recognizable JNDI name.

If you are going to deploy in a managed test environment or a production environment, system administration will probably be responsible for defining data sources to the application server. In this case you simply need to obtain the datasource's JNDI name.

If you are using an application server other than the J2EE RI, the application server must be configured with a datasource definition. The procedures for this depend on the application server product. Once again, in a managed test environment or a production environment, this will probably be done by system administration.

Creating Resource Factory References Explicitly for Bean-managed Entity Beans

If your EJB module contains entity beans that use bean-managed persistence, instead of container-managed persistence, you've already written JDBC and JTA to extract data from the database. This is covered in Building Enterprise JavaBeans Components. In addition, you must also explicitly code the resource reference that you use to connect to a specific datasource. Like the local EJB references you coded for CatalogManagerBean, this reference has two parts:

  • JNDI lookup code. Each of the session bean's business methods includes code that uses the JNDI naming facility to obtain a reference to an entity bean's LocalHome.
  • A declaration of the reference. This is used by the runtime environment to identify the specific bean referred to by the lookup code.

A datasource you specify with a explicit lookup must be a named resource, just as it is when the resource reference is automatically generated for a container-managed bean.

JNDI Lookup Code for Resource Factory References

CODE EXAMPLE 3-4 shows code you use in a BMP entity enterprise bean to look up a datasource.:

CODE EXAMPLE 3-4 JNDI Lookup for a Database
try {
  // Obtain Initial Context--Opens Communication With JNDI Naming:
  Context ic = new InitialContext();
  // Request Lookup of Resource--In This Example a JDBC Datasource:
  javax.sql.DataSource hrDB = (javax.sql.DataSource)
                                       ic.lookup("java:comp/env/jdbc/Local_HR_DB");
}  
catch(Exception e) { 
  System.out.println(e.toString()); 
  e.printStackTrace();
  return; 
} 

Reference Declaration for Resource References

To set up a reference declaration, use the entity bean's property sheet:

1. Right-click on the enterprise bean's logical node, and then choose the following sequence of commands from the contextual menu: Properties right arrow References tab right arrow Resource References right arrow ellipsis (...) button.

This opens the resource reference property editor.

2. Click the Add button to open a dialog that lets you add a new resource reference.

A reference must contain a reference name (the name used in the JNDI lookup statement), a resource type and an authorization type. FIGURE 3-4 shows the Resource Reference Property Add dialog with these fields filled with values that match CODE EXAMPLE 3-4.

 FIGURE 3-4 Add Resource Reference Dialog Box

Screenshot of EJB node's Add Resource Reference dialog.[ D ]

Notice that unlike EJB references, resource references are not linked to other J2EE components at assembly or deployment time. Instead the named resource is defined separately in the application server's environment. Enterprise beans use the JNDI lookup to obtain references to these resources at runtime.This reference will connect to that database instance.

3. Click on the Add dialog's server specific tab to identify the resource.

FIGURE 3-5 shows the Add dialog's J2EE RI tab. The JNDI Name field has a value of jdbc/Pointbase. This value links the resource reference named jdbc/Local_HR_DB to that specific database.

 FIGURE 3-5 Add Resource Reference Dialog Box, Server-specific Tab

Screenshot of the J2EE RI-specific tab for the Add Resource Reference dialog.[ D ]

Identifying Extra Files

In most cases the IDE recognizes the dependencies of the enterprise beans in the EJB module and includes all needed files in the EJB JAR files it generates at deployment time. There are a few types of dependencies, however that the IDE does not recognize.

  • If an enterprise bean in your module uses a help file without calling it directly.
  • If an enterprise bean accesses a class dynamically and the class name appears in the code only as a string and not as a class declaration.

In these and similar cases, the IDE does not recognize the dependency and does not include the help file or class file in the archive file it creates. You need identify these files so that they are available at run time.

To identify extra files:

1. Right-click the module node. From the contextual menu, choose the following sequence: Properties right arrow Extra Files right arrow ellipsis (...) button.

This opens the Extra Files property editor.

2. Select any extra file that should be deployed or archived as part of this module.

The Extra Files property editor lets you browse all mounted filesystems. Click the extra files and click the Add button to add them to the list of extra files.

Excluding Duplicate JAR Files

In some cases you want to prevent the IDE from acting on some of the file dependencies it recognizes. In particular, when a component in you module has a dependency on a commonly used JAR file that you know will be present in the runtime environment, you can prevent the IDE from adding an unnecessary copy of the commonly used JAR file to archive files created for you module.

To exclude duplicate jar file:

1. Right-click the module node. From the contextual menu, choose the following sequence: Properties right arrow Library Jars to Exclude right arrow ellipsis (...) button.

This opens the Library Jars to Exclude property editor. It displays a list of mounted JAR files.

2. Select JAR file that should be excluded, and click the Add button to move them to the list of library JARs to excluded.

Other Module Assembly Tasks

Specifying a runtime datasource for the CatalogData module is one task that you perform as part of assembling and configuring an EJB module. Depending on the module, there may be other assembly tasks. You need to determine what assembly tasks are required. Questions that you might ask about the module include:

  • Have all the references used in the module been linked? There may be some references to components in other modules, and these can only be linked after the module has been assembled into a J2EE application.
  • Have generic security roles been set up for the module? Have any security role references in the module's enterprise beans been linked to these generic security roles? Have method permissions been mapped to these generic security roles? For more information on these issues, see Chapter 8.
  • Have container-managed transactions been defined? For more information on this issue, see Chapter 7.