ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Business Logic, Part 1
Pages: 1, 2

I'll run briefly through the rest of the OfficeManager classes, as the actual implementation is fairly trivial. Example 8-2 is the home interface for the bean.



Example 8-2: The OfficeManager Home Interface

package com.forethought.ejb.office;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;

public interface OfficeManagerHome extends EJBHome {

    public OfficeManager create( ) throws
CreateException, RemoteException;
}

As you can see, this is a stateless session bean, which is the most efficient session bean. I'll discuss this more later. You can see from the implementation class in Example 8-3 that no state is required for the bean to function, and therefore using a stateless bean makes sense in this case.

Also in this series:

Business Logic, Part 3
In Part 3 of our excerpt from Building Java Enterprise Applications (Vol. 1, Architecture), Brett McLaughlin addresses issues of statelessness and statefulness.

Business Logic, Part 2
In Part 2 of our excerpt from Chapter 8 of Building Java Enterprise Applications, Vol I: Architecture, Brett McLaughlin builds a UserManager component, and illustrates why managers are a good thing.

Example 8-3: The OfficeManager Implementation Class

package com.forethought.ejb.office;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.naming.Context;
import javax.naming.InitialContext;

import com.forethought.ejb.util.SessionAdapter;

public class OfficeManagerBean extends SessionAdapter {

    public void ejbCreate( ) throws CreateException {
        // No action required for stateless session beans
    }

    public OfficeInfo get(String city, String state) throws RemoteException {
        Office office = getOffice(city, state);
        if (office != null) {
            return office.getInfo( );
        } else {
            return null;
        }
    }

    public OfficeInfo add(String city, String state) {
        try {
            // Get an InitialContext
            Context context = new InitialContext( );

            // Look up the Office bean
            OfficeHome officeHome = (OfficeHome)
                context.lookup("java:comp/env/ejb/OfficeHome");
            Office office = officeHome.create(city, state);
            
            return office.getInfo( );
        } catch (Exception e) {
            // Any problems - just return null
            return null;
        }
    }

    public void update(OfficeInfo officeInfo) throws RemoteException {
        Office office = getOffice(officeInfo.getId( ));
        office.setInfo(officeInfo);
    }

    public boolean delete(String city, String state) {
        Office office = getOffice(city, state);
        return delete(office);
    }

    public boolean delete(OfficeInfo officeInfo) {
        Office office = getOffice(officeInfo.getId( ));
        return delete(office);
    }

    private Office getOffice(int id) {
        try {
            // Get an InitialContext
            Context context = new InitialContext( );

            // Look up the Office bean
            OfficeHome officeHome = (OfficeHome)
                context.lookup("java:comp/env/ejb/OfficeHome");
            Office office = officeHome.findByPrimaryKey(new Integer(id));
            
            return office;
        } catch (Exception e) {
            // Any problems - just return null
            return null;
        }
    }

    private boolean delete(Office office) {
        if (office == null) {
            return true;
        }
        
        try {
            office.remove( );
            return true;
        } catch (Exception e) {
            // any problems - return false
            return false;
        }
    }

    private Office getOffice(String city, String state) {
        try {
            // Get an InitialContext
            Context context = new InitialContext( );

            // Look up the Office bean
            OfficeHome officeHome = (OfficeHome)
                context.lookup("java:comp/env/ejb/OfficeHome");
            Office office = officeHome.findByLocation(city, state);
            
            return office;
        } catch (Exception e) {
            // Any problems - just return null
            return null;
        }
    }

You'll notice that this bean uses a new finder method on the Office entity bean, findByLocation( ). You can add this method to your OfficeHome class:

public Office findByLocation(String city, String state)
    throws FinderException, RemoteException;

Here's the relevant addition for the ejb-jar.xml file:

<query>
  <query-method>
    <method-name>findByLocation</method-name>
    <method-params>
      <method-param>java.lang.String</method-param>
      <method-param>java.lang.String</method-param>
    </method-params>
  </query-method>
  <ejb-ql>
    <![CDATA[WHERE city = ?1 AND state = ?2]]>
  </ejb-ql>
</query>

Before leaving the façade pattern behind, there are a few other details related to this first business-related bean worth detailing. First, notice that the manager beans are placed within the same package as the related entity bean. This provides logical groupings of managers and the related entities, and also makes access from manager component to entity bean simple (notice that there weren't a lot of import statements required in the source code).

Additionally, the method names have been changed a bit; instead of create( ), setCity( ), and getState( ), the more conventional method names add( ), update( ), and delete( ) are used. This is more in line with an administrative component, and moves away from the strict conventions required in CMP entity beans. It also provides an easier-to-use interface for client code.

Performance Penalties

In the interests of full disclosure, you should certainly be aware that the façade pattern, with all of its positives, does have some negatives. The significant problem with using this pattern is that it can introduce some performance penalties into your applications. Using an extra bean for communication (the session manager component) means that additional RMI calls must be made. This, of course, causes increases in network traffic, serialization of arguments, and all of the costs that any RMI call has. If both entity beans and session beans reside in the same EJB container on a single server, these costs shrink to almost nothing (in fact, most advanced EJB containers have optimizations for these "in-VM" calls, and will essentially drop the calls off the RMI stack and make the calls locally, removing any RMI penalties at all); however, this is often not the case It's more common to have session beans in one EJB container and entity beans in another, often on completely different physical machines.

However, even this problem can be overcome. Instead of packaging all entity beans and deploying them on one server, and packaging all session beans and deploying them on another, you can use more logical (and sensible) groupings to improve performance. Remember that you packaged a session bean, the SequenceBean, with the Forethought entities already. In this same fashion, manager components that implement the façade design pattern can be packaged with entity beans, ensuring that RMI communication is as fast as possible; this also provides logical divisions between entities and their accessor classes (the manager components) and business-driven components (the rest of the session beans). Figure 8-4 shows this configuration in action.

Diagram.
Figure 8-4. Logical separation of beans.

Here, the manager components are packaged in the forethoughtEntities.jar archive, and in that way, become simple entities.

Additionally, almost all manager components turn out to be stateless; in other words, each method of the component operates on its own without any saved information. This also helps to offset penalties incurred through using the façade pattern. As mentioned several times, stateless session beans outperform all other types of entity beans substantially. Interestingly enough, entity beans consume the most resources of any bean, as often one single instance is shared for containers (although there are as many variations on this theme as there are container vendors). So it is safe to make your manager session beans stateless.

These changes address the major downside of using the façade pattern; there are really no other penalties (other than some extra coding) to this approach. Clearly it makes sense, then, to implement it in the Forethought application as well as in your own.


View catalog information for Building Java Enterprise Applications Vol I: Architecture

Return to ONJava.com.