Business-Tier Interfaces


Business- Tier Interfaces

Now that we ve identified the mechanisms for displaying data and handling navigation and form submission, it is time to discuss the heart of any presentation-tier architecture: interfacing with business-tier components .

First, we need to look ahead a bit to Chapter 7, where we discuss the design and development of the EJB components for this application. Clearly the business-tier interfaces available to the Web application depend on the architecture of the business tier. Although we thoroughly discuss the choice of business-tier architecture in Chapter 7, what you need to know here is that we decided to make heavy use of entity beans and container-managed persistence (CMP) throughout the business tier. Queries will be implemented as finder methods on the bean home interfaces, and all relationships between beans will be defined and managed using the EJB 2.0 CMP techniques. There will be a few stateless session beans acting as fa §ades for complex business logic not appropriate for placement in entity beans.

What does the decision to emphasize entity beans and CMP in the business tier mean to the presentation tier? Depending on the detailed design of the business-tier interfaces, perhaps very little. We need to examine some alternatives for the interaction with the business tier and make a selection.

Although we have many options available, we re going to narrow the choice of business-tier interface down to two basic approaches: indirect interaction with the entity beans via session beans and value objects and direct interaction with the entity beans. Note that many interface techniques making use of business delegates, command classes, data transfer objects, and other design patterns essentially fall in to the approach we re calling indirect interaction.

In the first approach, indirect interaction, presentation-tier components are insulated from the entity beans completely by introducing a stateless session bean or other component that acts as a session fa §ade to encapsulate the entity beans and all business-tier behaviors. Communication with the session bean is normally performed using a value object , a separate Java class containing the same basic information as the entity bean. JSP pages and controller components never access the entity beans directly or perform any finder methods to obtain collections of beans.

In the second approach, direct interaction, presentation-tier components are allowed to interact directly with entity beans in the business tier. JSP pages and controller components may retrieve data elements directly from the beans, traverse relationships in the entity beans to access other beans, perform finder queries to obtain collections of beans, and update bean information by calling set methods directly on the entity beans.

Many of the common design alternatives are simply offshoots of these basic techniques. For example, XML documents or JDBC RowSet objects might be used instead of value objects in the indirect approach, or entity beans might return value objects containing all of their data rather than allowing direct interaction from presentation-tier components. Both of these alternatives are indirect interaction in our way of thinking because the key element of the direct interaction approach is the ability for the presentation-tier components simply to call entity bean get and set methods when desired without any additional layers or objects used for communication.

Chapter 7 discusses these alternatives in detail and explains the decision-making process that led us to choose the direct interaction approach for bigrez.com . Surprised? Clearly this approach is not the normal technique employed in the J2EE community today.

The following sections highlight some of the important implications of this decision on the presentation-tier components. These implications include the following:

  • Presentation-tier components may access entity bean attributes directly, through get and set methods, during both the display of bean data and the processing of forms.

  • Presentation-tier components may traverse and manipulate relationships between entity beans using relationship get and set methods on the beans.

  • Action classes continue to place value objects and form beans in the HttpServletRequest context prior to forwarding to JSP pages, but they may also place entity bean references in that context to support direct interaction by the pages.

Displaying Bean Attributes on JSP Pages

The primary role of display JSP pages in the servlet-centric architecture is the display of data placed in the HttpServletRequest or other context by controller components. In the indirect interaction approach, the object placed in the request is often a value object or other simple data structure, but in the direct interaction approach the object is normally a local reference to an entity bean. In either approach, the JSP page declares the existence of the bean in the page using jsp:useBean and displays data from the bean using jsp:getProperty tags or the equivalent bean:write tags in Struts. Although the JSP may look similar in both approaches, there is a significant difference behind the scenes.

First, the jsp:useBean tag that declares the existence of the bean in the JSP page must obviously reflect the correct data type of the object in the request. For example, if a JSP page was displaying information in a simple PropertyInfo value object, the jsp:useBean tag would look something like this:

 <jsp:useBean id=prop type=com.bigrez.val.PropertyInfo               scope=request/> 

The page accessing the entity bean directly would use the type of the local reference:

 <jsp:useBean id="prop" type="com.bigrez.ejb.PropertyLocal"               scope="request"/> 

One important difference is the way the jsp:useBean tag handles the case where the desired bean is not found in the specified context. Recall that in this case, the tag will attempt to create an instance of the specified class using the default constructor, an operation that normally succeeds for value objects but is not valid for PropertyLocal or any other entity bean interface because they are, in fact, interfaces rather than concrete classes. Note that placing the proper findByPrimaryKey() or other initialization code in the body of the jsp:useBean tag does not help because the tag still attempts to call a default constructor prior to executing any scriptlet code placed in the tag body. Therefore, the bean reference must already be in the required scope before the jsp:useBean tag is executed to avoid a run-time exception. In most cases, the bean will be placed in the proper context by the controller component prior to forwarding to the page, so this is not a big problem.

Accessing the data in the bean is identical in both approaches, assuming the value object and entity bean both have get methods for the desired data. For example, the following tag calls the getDescription() method on the underlying object (either value object or bean) and places the result in the generated HTML response:

 Description: <jsp:getProperty name=prop property=description/> 

Bean attributes that require formatting during display might use the View Helper pattern, by invoking a formatting helper object in an expression scriptlet:

 <%= DateHelper.format(rez.getArrive()) %> 

They can also employ a custom tag that includes the ability to specify a format, as does the bean:write tag in the Struts framework:

 <bean:write name=rez property=arrive formatKey=date.format1/> 

Formatting helper classes and tags such as these are critical in the direct interaction approach. There may be a large number of fields that should appear differently on the displayed HTML page than they do in their internal representation in the entity bean.

Note that this need for formatting does not argue for value objects because value objects may also require formatting for display. Value objects should normally be exact replicas of the attributes and formats in the corresponding entity beans. If the value object includes attributes preformatted for display, it is not a true generic value object, but instead reflects presentation-tier formatting requirements, reducing its potential for reuse. Don t fall into this trap of preformatting data in business objects when using either entity beans or value objects. Formatting must be done by presentation-tier components using helper classes or tags depending on the requirements of that particular display component.

Best Practice  

Do not perform display formatting in entity beans or value objects. Use presentation-tier components such as helper classes or custom tags to map business data to display formats where required.

The final nuance in the direct interaction approach of accessing entity bean attributes directly deals with the EJB life cycle and transactions. Depending on your experience level using entity beans, you might have some significant reservations about executing get methods against the beans from within a JSP page. Normally, each get request causes a full ejbLoad()/ejbStore() life cycle of the bean, but not if you are careful, as we will explain in a moment.

One of the first things you learn about entity beans when starting out with EJB technology is the importance of accessing them efficiently , rather than one get method at a time. Most of us have written a Java client program something like this at one point in our careers:

 ... Integer pk = new Integer(1); CabinRemote cabin_2 = home.findByPrimaryKey(pk); System.out.println(cabin_2.getName()); System.out.println(cabin_2.getDeckLevel()); System.out.println(cabin_2.getShipId()); System.out.println(cabin_2.getBedCount()); ... 

If you put a log statement in the ejbLoad() method on the bean, you may be surprised to discover that the bean is being read from the database four times, once for each get method called on the bean. At this point, you might either give up on EJB completely in disgust (perhaps switching to something easier?) or read a little more and realize your mistake. Transactions control entity bean life cycles in EJB, requiring an ejbLoad() at the start of a transaction and an ejbStore() at the end, and this example begins and ends four separate transactions by calling get methods from a client program outside the scope of a transaction.

You can make this simple Java client program much more efficient by starting an explicit transaction before the findByPrimaryKey() method and ending it after the final get method:

 Context ctx = getInitialContext(); UserTransaction tran =      (UserTransaction) ctx.lookup(java:comp/UserTransaction); try {     tran.begin();     ...     Integer pk = new Integer(1);     CabinRemote cabin_2 = home.findByPrimaryKey(pk);     System.out.println(cabin_2.getName());     System.out.println(cabin_2.getDeckLevel());     System.out.println(cabin_2.getShipId());     System.out.println(cabin_2.getBedCount());     ...     tran.commit(); } catch (Exception e) {     ...     tran.rollback();     throw e; } 

The first get method now causes the bean to be loaded via ejbLoad() and kept in memory for the duration of the transaction, allowing the subsequent get methods to access the data more efficiently.

To apply this lesson to display JSP pages that need to get and display many bean attributes without incurring multiple transaction cycles, you simply place transaction-control code similar to the begin() and commit() code shown here in your JSP pages surrounding the tags that access the entity bean. In bigrez.com , we ve placed this code in two JSP scriptlet snippets, BeginTrans.jspf and EndTrans.jspf , shown in Listing 3.4 and Listing 3.5. These snippets are included on appropriate pages at the top and bottom of the page. This technique ensures that the transaction is properly committed or rolled back regardless of run-time exceptions thrown by the page, and it ensures that all access to beans in the page is done in the context of a transaction.

Listing 3.4:  BeginTrans.jspf starts the transaction.
start example
 <% // We create a block here to allow multiple transactions per page {     Context utJNDIContext = getInitialContext();     UserTransaction tran = (UserTransaction)         utJNDIContext.lookup("java:comp/UserTransaction");     try {         tran.begin(); %> 
end example
 
Listing 3.5:  EndTrans.jspf ends the transaction.
start example
 <% // This include file terminates a transaction start block         tran.commit();     }     catch (Exception e) {         e.printStackTrace();         tran.rollback();         throw e;     } } //end trans block %> 
end example
 
Best Practice  

Wrap all direct access to entity beans made by presentation-tier components in explicit transactions created using the UserTransaction interface. This rule applies to JSP pages and controller components.

The JSP scriptlet files listed in Listing 3.4 and Listing 3.5 represent a low-tech solution to the problem of wrapping entity bean access in a transaction. You might consider creating a custom tag that starts the transaction in doStartTag() and ends it in doEndTag() as an alternative, but take care to trap and handle exceptions occurring in the tag body by implementing the TryCatchFinally interface in your tag class and overriding the doCatch() method.

You could also modify the PageDisplayServlet itself, wrapping the forward() invocation in transaction-control logic to place all included display JSP pages in an explicit transaction automatically:

 ... RequestDispatcher dispatch =     request.getRequestDispatcher("/Master.jsp?page="+newpage); Context utJNDIContext = getInitialContext(); UserTransaction tran = (UserTransaction)      utJNDIContext.lookup("java:comp/UserTransaction"); try {  tran.begin();   dispatch.forward(request,response);   tran.commit();  } catch (Exception e) {  tran.rollback();  ... } 

This technique has the advantage of being automatic, requiring no explicit tags or included files in display JSP pages, but it also reduces performance by creating a transaction for all pages regardless of their need for one.

We ve chosen to include the simple transaction-control .jspf files in appropriate JSP pages rather than use a more advanced technique to keep the implementation simple and transparent. This simple technique has its limitations, the chief one being that all transaction control occurs at the individual page level. Because the overall HTML response is generated by a series of JSP pages in our master-page-assembly approach, multiple transactions may be required to create the response. This simple technique will also fail if a page starts a transaction and includes another page that attempts to start its own transaction. Consider using a more advanced technique, such as creating a transaction in the PageDisplayServlet or master JSP page, if these limitations are unacceptable to you.

The need to wrap all entity bean access in an explicit transaction represents the biggest weakness of the direct interaction approach. The actual performance cost of this requirement is fairly small given the basic approach of collocating Web application components and EJB components in the same enterprise application archive ( .ear ) file and using only local interfaces. We contend that the benefits of direct interaction outweigh the drawbacks in certain applications, and we discuss this in more detail in Chapter 7. Remember that patterns such as session fa §ade grew out of the limitations of the EJB 1.1 entity bean model and the absence of local interfaces; perhaps it is time to revisit the need for that pattern for simple entity bean interaction.

In summary, the choice of direct interaction affects display JSP pages in two primary ways:

  • Bean references must be present in the required scope before the corresponding jsp:useBean tag is encountered in the page to avoid run-time exceptions.

  • Pages that access entity bean attributes directly must perform this activity in a transaction by including BeginTrans.jspf and EndTrans.jspf at the top and bottom of the page, respectively.

Relationships in Presentation Components

One of the significant benefits of the direct interaction approach is the ability of presentation-tier components such as JSP pages and Action classes to work directly with the object lattice and relationships implemented in the entity beans themselves . There is no need to write session bean methods that fetch and return lattices of value objects simulating the entity bean relationships or implement some form of lazy instantiation of relationship collections in parent value objects. When the entity beans are used directly, all retrieving of relationships and related beans is managed automatically by the CMP code in the container, and in WebLogic Server, this relationship management code has been optimized for performance. Chapter 6 discusses these caching and relationship management features of WebLogic Server and provides best practices for their use.

If a JSP page or Action class has a reference to a particular RoomType bean, for example, it can simply use the getRates() method on the bean to obtain a collection of related Rate entity bean references. Relationships can be traversed in the opposite direction with equal ease because we re implementing bidirectional relationships for all entity beans in the system.

The result is clean, natural code in the presentation-tier components without any additional development of specialized session bean methods and data transfer objects to retrieve and manage relationships. For example, a page that displays information about a particular property and the room types defined in that property needs only the property bean reference placed in the HttpServletRequest , and it can use the getRoomTypes() relationship method on the property bean to iterate through the room types for display:

 <jsp:useBean id=prop scope=request              type=com.bigrez.ejb.PropertyLocal/> ... <logic:iterate id=roomtype type=com.bigrez.ejb.RoomTypeLocal                 collection=<%= prop.getRoomTypes() %>>   <tr>     <td width=30% align=left>       ...       <jsp:getProperty name=roomtype property=description/>     </td>   </tr> ... </logic:iterate> 

Don t let the < logic:iterate > tag confuse you. It s another tag in the Struts framework that we ll be using in the bigrez.com site to iterate through a collection and define a page bean for each element in the collection. In this case, roomtype will be a reference to each room type entity bean related to the property. Check out the Struts home page at http://jakarta.apache.org/struts for more information on this and many other useful custom tags.

Code in the Action classes can also traverse relationships naturally to improve readability. For example, when the user clicks on an offer, we must load the correct property bean in the request before forwarding to the next page. This code snippet in OfferAction.java is made much clearer by traversing the relationship between an offer and its related property directly using getProperty() :

 String offer_id = request.getParameter("id"); int id = Integer.parseInt(offer_id);  OfferLocal offer = (OfferLocal) Locator.getBean("OfferLocal", id);   PropertyLocal prop = offer.getProperty();  ActionUserHelper.loadPropertyBean(request, prop); 

Some of the helper methods and utility classes present in this code have not been covered yet, but you should get the idea. In a session bean architecture, we would likely use two calls to the fa §ade bean: the first to fetch the offer-related value object containing the property ID and the second to fetch the property-related value object associated with the offer. The code here represents the better option in terms of clarity.

So far we ve talked only about retrieving and traversing relationships with presentation-tier components. The benefits of direct interaction during these operations are relatively minor, as it turns out, compared to the benefits during updates. For example, you can manipulate relationships between EJB 2.0 CMP entity beans by simply manipulating the Collection classes returned by the bean methods. Chapter 7 will describe why this feature is important for the bigrez.com administration site and how direct interaction represents a significant improvement over alternative indirect techniques when it comes to managing complex relationships.

In summary, the use of direct interaction simplifies the traversal and management of relationships between business objects by allowing the presentation-tier components access to the relationship methods available on the entity beans themselves.

Action Classes Load Beans and Forms for Display

The servlet-centric architecture we ve chosen for bigrez.com requires that controller components load required objects in the HttpServletRequest prior to forwarding control to the display JSP page. The objects loaded in the request are typically one of three types:

Entity bean local references.    Because we are using the direct interaction approach, the objects loaded in the request will often be local references to entity beans required by the display page.

Form beans.    If the display JSP page is a Struts form, the controller must load an appropriate ActionForm object in the request containing the current attributes of the corresponding bean.

Value objects or collections.    Some pages in the site require specialized collections or complex data structures best prepared ahead of time by the controller rather than created in the JSP page itself.

To load a local bean reference in the request, the controller components ( Action classes in Struts) simply locate the desired bean and place the reference in the HttpServletRequest using code similar to the following:

 PropertyHomeLocal propertyhome = (PropertyHomeLocal)     ctx.lookup(java:comp/env/ejb/PropertyHomeLocal); PropertyLocal prop = propertyhome.findByPrimaryKey(pk); request.setAttribute(prop, prop); 

The display JSP page may now obtain this bean reference using jsp:useBean tags or equivalent Struts tags to retrieve bean attribute data:

 <jsp:useBean id=prop type=com.bigrez.ejb.PropertyLocal               scope=request/> ... Description: <jsp:getProperty name=prop property=description/> 

Form beans required by Struts forms are loaded in the request by the controller class in a similar manner. For example, if a Property was being edited on a form page, the code to fetch the entity bean, create the form bean, and place the form bean in the request might look like this:

 PropertyHomeLocal propertyhome = (PropertyHomeLocal)     ctx.lookup("java:comp/env/ejb/PropertyHomeLocal"); PropertyLocal prop = propertyhome.findByPrimaryKey(pk); PropertyMainForm pform = new PropertyMainForm(); pform.setId(prop.getId()); pform.setDescription(prop.getDescription()); ... pform.setFeatures(prop.getFeatures());  request.setAttribute("PropertyMainForm", pform);  

The target page can now locate the required form bean and display the form with values representing the current attributes of the property. Note that locating entity beans and copying attribute data from entity beans to form beans are straightforward tasks but require a fair number of lines of code. In bigrez.com these tasks are handled by two helper objects, Locator and CopyHelper , which shrinks the required code substantially:

 PropertyLocal prop =      (PropertyLocal)  Locator.getBean("PropertyLocal", pk);  PropertyMainForm pform = new PropertyMainForm();  CopyHelper.copy(prop, pform);  request.setAttribute("PropertyMainForm", pform); 

The Locater and CopyHelper classes are detailed in subsequent chapters. Note that all get method invocations on the entity bean, whether explicit in the code or performed in the helper class, must be performed in a transaction for the same reasons described earlier in this chapter. As you ll see when we examine some sample code from the application, utility methods comparable to BeginTrans.jspf and EndTrans.jspf are used to begin and end transactions in Action classes.

Value objects and specialized collections of objects or references are also precreated and placed on the HttpServletRequest for use by display JSP pages requiring this type of data. A good example of this technique is the PropertyList display page that displays property information for hotels matching the user s search criteria. The controller performs the search and loads the collection of matching properties in the request using code similar to the following:

 PropertyHomeLocal propertyhome =      (PropertyHomeLocal) Locator.getHome(PropertyHomeLocal); props = propertyhome.findByCityState(city, stateCode); request.setAttribute(props, props); 

Note that the controller uses a finder defined on the home interface for Property to perform the search rather than a specialized method defined on a stateless-session bean or other fa §ade. The direct interaction approach allows the direct invocation of entity bean finder methods in presentation-tier components. Although there are occasions in bigrez.com when the presentation tier must use a fa §ade to perform complex business logic, simple finder methods do not warrant another layer of abstraction in our opinion.

The direct interaction approach requires that controller components place entity bean references on the HttpServletRequest along with the usual ActionForm classes and value objects required in any servlet-centric architecture using Struts.

Best Practice  

Controller components should generally prepare the request or session context before forwarding to display JSP pages rather than allowing JSP pages to obtain bean references themselves.

Action Classes Perform Bean Updates

The servlet-centric architecture dictates that controller components are responsible for processing HTML form submissions and performing the required updates to the underlying business objects. In the direct interaction approach, the controller components are therefore allowed to modify the underlying entity beans and relationships modeling the business data directly.

For example, in bigrez.com the PropertyMainAction class is the controller responsible for taking changes made in the main property information form and applying them to the database. We ll examine this class in detail later, but for now, look at just the key lines that perform the transfer from the form bean to the entity bean:

 PropertyMainForm pform = (PropertyMainForm)form; ... PropertyLocal prop =      (PropertyLocal) Locator.getBean(PropertyLocal, id); CopyHelper.copy(pform, prop); // calls set methods on entity bean 

This process is really just a mirror image of the code in the previous section that created the form bean from the entity bean before displaying the form page. The controller, a presentation-tier component, is allowed to locate and modify the contents of the PropertyBean entity bean directly through this code. As before, it must be done in a transaction.

In a similar way, the controllers that create new beans or add beans to relationships simply perform these tasks using the entity bean home interfaces or relationship get and set methods, as appropriate. You could encapsulate these functions in fa §ade beans to avoid direct manipulation of the beans, but there are some benefits to avoiding the creation of additional layers in the architecture solely for encapsulation.

Note that selected operations in bigrez.com are complex enough to warrant a fa §ade bean with methods encapsulating the behavior. For example, the creation of a reservation bean and all related entity beans is best implemented in a session bean and accessed from the presentation-tier components through that fa §ade. This technique is the exception rather than the rule in the direct interaction approach, however.




Mastering BEA WebLogic Server. Best Practices for Building and Deploying J2EE Applications
Mastering BEA WebLogic Server: Best Practices for Building and Deploying J2EE Applications
ISBN: 047128128X
EAN: 2147483647
Year: 2003
Pages: 125

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