The Different Types of Presentation Tiers

   

Using a Fa §ade Pattern to Hide EJB

Another design pattern that you'll see used quite often in presentation tiers that have to communicate with a distributed middleware is the Fa §ade pattern. The Fa §ade pattern uses a single object or a small number of objects as a front end to a larger set of interrelated objects. So, suppose you have several session beans in your EJB application that the presentation tier needs to communicate with. Rather than expose the different session beans to the presentation tier, the Fa §ade pattern can be used to present a single interface to the presentation layer and make the component interfaces easier to deal with. The object that implements the Fa §ade pattern can live in the presentation tier or in the application tier . For example, you can have a single session bean act as a fa §ade to the remote client. When a client invokes an operation onto the session bean, it can, in turn , call multiple other session bean methods . In this way, the client isn't aware of the other session beans. Figure 19.2 shows an example using the Fa §ade pattern to hide multiple session bean objects from the presentation tier.

Figure 19.2. A Fa §ade pattern can be used to present a simpler interface to the presentation tier.

graphics/19fig02.gif

Although the Fa §ade pattern in this example is on the Web tier, the fa §ade is being performed for the presentation tier. The object providing the Fa §ade pattern still might have to use the multiple session beans, but the rest of the presentation layer would not know this.

Building a Service-Oriented Interface

Sometimes, you will see the Remote Proxy and Fa §ade patterns combined to produce an object or set of objects that encapsulates the ugliness of doing remote method calls to an EJB server. At the same time, it also presents a more cohesive interface that sometimes is referred to as a service-oriented interface.

A service-oriented interface is a set of public methods that are at a certain level of granularity that basically matches your functional requirements. For example, the auction application must support certain functional methods on the presentation tier so that an end user can use the application to view and participate in the auctions. Fortunately, this is the exact purpose of the business interface discussed in Chapter 16. Because the business interface exposes the methods that are available to clients to call, it makes sense that this interface be used on the client tier somehow. Listing 19.1 shows the business interface for the auction house session bean that an auction client can implement.

Listing 19.1 A Service-Oriented Interface for the Auction Client to Implement
 package com.que.ejb20.auction.controller;  /**   * Title:        IAuctionHouse<p>   * Description:  Remote business method interface for the AuctionHouse.   *               This interface illustrates a few of the methods needed to   *               serve the information requirements for auction bidders.<p>   */  import java.util.List;  import java.rmi.RemoteException;  import javax.ejb.FinderException;  import com.que.ejb20.auction.exceptions.InvalidAuctionStatusException;  import com.que.ejb20.auction.exceptions.InvalidBidException;  import com.que.ejb20.auction.view.AuctionDetailView;  public interface IAuctionHouse {   /**     * Return entries for an auction pick list     *     * @param startIndex the element to start with (1-based)     * @param numToReturn the number of auction views to return     * @return a list of AuctionSummaryView objects sorted by name     */    public List getAllAuctions(int startIndex, int numToReturn)      throws RemoteException;    /**     * Return a list of all open, closed, or cancelled auctions     *     * @return a List of AuctionSummaryView objects     */    public List getNonPendingAuctions() throws FinderException, RemoteException;    /**     * Return a detailed description of a specific auction     *     * @param auctionId the primary key for the selected auction     * @return a description of the auction and its offered item     */    public AuctionDetailView getAuctionDetail(int auctionId)      throws FinderException, RemoteException;    /**     * Submit a bid to an open auction     *     * @param bidAmount the amount bid     * @param auctionId the primary key for the selected auction     * @param bidderId the primary key for the bidder     *     */    public String submitBid(double bidAmount, int auctionId, int bidderId)      throws InvalidBidException, InvalidAuctionStatusException, RemoteException;    /**     * Return a list of BidView objects describing all bids submitted by a bidder     */    public List getBids(int bidderId) throws FinderException, RemoteException;  } 

Notice the granularity of the interfaces in Listing 19.1. They basically match up with the functional requirements from Chapter 2, Setting the Stage ”An Example Auction Site. You don't see very fine-grained methods, but rather methods that are at the appropriate level of what the presentation tier needs to accomplish.

A class that implements this interface might have to perform multiple steps to accomplish the task, but from the viewpoint of the presentation component that uses this interface, it's just a single method call to perform the service. The presentation components don't have to know that it actually takes multiple steps to complete this operation. The class that implements the service interface hides this fact. That's what we mean when we say service-oriented. Listing 19.2 shows a class that implements the IAuctionHouse interface from Listing 19.1.

Listing 19.2 AuctionClientProxy Class Used by the Presentation Tier for Auctions
 /**   * Title:        AuctionClientProxy<p>   * Description:  The remote proxy object that the auction presentation tier   *               uses to interact with the auction EJB application.<p>   */  package com.que.ejb20.client;  import java.util.Collection;  import java.util.List;  import java.rmi.RemoteException;  import javax.naming.Context;  import javax.naming.InitialContext;  import javax.naming.NamingException;  import javax.ejb.CreateException;  import javax.ejb.FinderException;  import com.que.ejb20.auction.controller.IAuctionHouse;  import com.que.ejb20.auction.controller.AuctionHouseHome;  import com.que.ejb20.auction.controller.AuctionHouse;  import com.que.ejb20.auction.exceptions.InvalidAuctionStatusException;  import com.que.ejb20.auction.exceptions.InvalidBidException;  import com.que.ejb20.auction.view.AuctionDetailView;  public class AuctionClientProxy implements IAuctionHouse {   // Reference to a home factory for the auction house session bean    private AuctionHouseHome auctionHouseHome = null;    // Reference to the remote interface of the auction house bean    private AuctionHouse auctionHouse = null;    /**     * Return entries for an auction pick list     *     * @param startIndex the element to start with (1-based)     * @param numToReturn the number of auction views to return     * @return a list of AuctionSummaryView objects sorted by name     */    public List getAllAuctions(int startIndex, int numToReturn)      throws RemoteException {     return getAuctionHouse().getAllAuctions(startIndex, numToReturn );    }    /**     * Return a list of all open, closed, or cancelled auctions     *     * @return a List of AuctionSummaryView objects     */    public List getNonPendingAuctions() throws FinderException,      RemoteException {     return getAuctionHouse().getNonPendingAuctions();    }    /**     * Return a detailed description of a specific auction     *     * @param auctionId the primary key for the selected auction     * @return a description of the auction and its offered item     */    public AuctionDetailView getAuctionDetail(int auctionId)      throws FinderException, RemoteException {     return getAuctionHouse().getAuctionDetail( auctionId );    }    /**     * Submit a bid to an open auction     *     * @param bidAmount the amount bid     * @param auctionId the primary key for the selected auction     * @param bidderId the primary key for the bidder     *     */    public String submitBid(double bidAmount, int auctionId, int bidderId)      throws InvalidBidException, InvalidAuctionStatusException, RemoteException{     return getAuctionHouse().submitBid( bidAmount, auctionId, bidderId );    }    /**     * Return a list of BidView objects describing all bids submitted by a bidder     */    public List getBids(int bidderId) throws FinderException, RemoteException{     return getAuctionHouse().getBids( bidderId );    }    // Return an instance of the remote interface for the auction house    // session bean. If the remote reference has not been created, create    // it here.    private AuctionHouse getAuctionHouse() throws RemoteException {     Context initCtx = null;      // Get the home Factory for the auction house bean if not already created      if ( this.auctionHouse == null ){       try{         initCtx = new InitialContext();          Object obj = initCtx.lookup( "java:comp/env/ejb/AuctionHouseHome" );          // Narrow the object so that this is portable          auctionHouseHome = (AuctionHouseHome)            javax.rmi.PortableRemoteObject.narrow( obj, AuctionHouseHome.class );          // Create a remote reference and store it into the instance reference          auctionHouse = auctionHouseHome.create();        }catch( Exception ex ){         throw new RemoteException( "Can't create the remote interface" );        }finally{         if ( initCtx != null ){           try{             initCtx.close();            }catch( Exception ex ){             // Do nothing for now            }          }        }      }      // return the instance of the remote interface already created      return this.auctionHouse;    }    // Get the JNDI initial context    private Context getInitialContext() throws NamingException {     return new InitialContext();    }  } 

In Listing 19.2, you can see how the proxy class has to take care of several naming service tasks that you don't necessarily want the rest of the presentation components to get involved with. An instance of the class must locate the remote interface to the session bean and, if one doesn't exist, use the JNDI InitialContext to find the home and narrow it. This type of encapsulation, or "behavior hiding," will save plenty of headaches for the programmers responsible for the presentation tier.

Notice in Listing 19.2 that the AuctionClientProxy class holds on to references to the session bean. Each Web user typically would have its own instance of this class cached in the HTTPSession object or in some container object that is stored in the session. This solves many problems, one being how to allow for security for an individual user to be propagated to the application tier.

For more information on how security works between a client and an EJB container, see "Security Design and Management," p. 387.

Tip

If you find yourself doing JNDI lookups or other common EJB operations from more than one proxy class, you'll probably want to separate this functionality out into a separate class that is then used by the different proxies. This will help with reuse in the presentation tier.


Here's one final note on using a remote proxy class as we have described. Obviously, someone must build these proxy classes, whether the work is done by a Web tier developer or an application tier developer ”or maybe you're responsible for both. It might seem like more work to build these extra classes rather than just put the code inside the actual presentation code. It is true that you end up building a few extra classes doing it this way. However, one huge benefit is that you can actually build a test harness that uses these proxy classes separated from the presentation tier and test every method within the proxy. In this way, you can ensure that when the presentation tier calls the methods, it's going to get the correct results. This extra unit testing might be a little harder to perform if the code was directly inside the presentation components.

This will also help when defects are reported from the presentation tier. You can easily determine whether the defects are in the presentation tier or application tier by exercising your unit tests again with the proxies and examining the results. If it works from the proxy objects, you know that the defects must be in the application layer. Taking a little extra time earlier in the development stream can have huge payoffs downstream when the product gets into QA or into production.



Special Edition Using Enterprise JavaBeans 2.0
Special Edition Using Enterprise JavaBeans 2.0
ISBN: 0789725673
EAN: 2147483647
Year: 2000
Pages: 223

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