HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

As Java technology has matured over the last few years so have we. We've learned that building complex enterprise applications that respond to change requires more than standardized APIs and virtual machines. Fortunately, we're now starting to see the widespread adoption of best practices, patterns, and even frameworks with templates and prebuilt components.

This article looks at the MVC design pattern and reviews its implementation in Struts, a presentation-tier application framework, as well as recognizing analogies of MVC to a well-formed, EJB-tier framework that Struts can be integrated with.

MVC for J2EE
Struts is an implementation of the presentation tier using MVC. The Struts controller encapsulates the presentation logic, handling the interaction of the JSP pages view with the JavaBeans model, which might access a database through JDBC.

When we integrate with a business tier, the recommended pattern is to access a Session Fašade or Business Service - analogous to an MVC view. The model could be thought of as our data access objects or entity beans. The model can be queried by the view, but updates occur through the controller, which would then represent our business logic.

When we consider the applicability of the MVC pattern to the business tier, it enables us to recognize the separation of responsibilities between the interface, model, and business logic. It demarcates responsibilities across our infrastructure components. We see, for example, how to use different interfaces or views for the same model or controller.

Struts Implementation of MVC
Struts delivers on its promise of a framework that follows the MVC design pattern by effectively segregating the various components into a small set of extendable classes. Also note the declarative nature of its XML-based action mappings and JSP tags.

Figure 1 illustrates the interaction between the key Struts components as they relate to editing user information.

Figure 1
Figure  1:

Figure 2 illustrates how each major component of Struts maps into the MVC.

Figure 2
Figure  2:

The Model
The Struts implementation of the Model comes by way of the abstract class, ActionForm. It manages the data required by the View (JSP) and changes its state according to the Controller (Action). In its simplest terms, the ActionForm is a standard JavaBean with getters and setters used to access its state. It defines no abstract methods, but you have the option of overriding the validate method to perform server-side validation of the application data.

An ActionForm used to maintain data about a user may look like Listing 1.

The View
The extensive Struts tag libraries combine to create a mechanism of presentation and interaction that allows developers to develop, and designers to design. The JSP will use the ActionForm (Model) as a means of allowing the client to interact with the application.

Listing 2 provides an example of a JSP page with Struts tags.

The Controller
Two Struts classes make up the Controller, ActionServlet and Action. Both work in concert to manage the flow of the application, but have distinct differences. The ActionServlet is responsible for mapping URI requests to specific Actions, while the Actions are responsible for interacting with the Model (ActionForms).

The developer extends the Action class to implement logical units of work that will be invoked by the ActionServlet upon receiving a request. Saving user information may be part of the SaveUserAction (see Listing 3).

UserDelegate is a class based on the J2EE Business Delegate design pattern. It hides the implementation of the business-tier's view of the model and will be explained in detail later in this article. The important thing to note is how the Struts model interacts with the business-tier's view - the action is the bridge that joins the two.

The ActionServlet is made aware of the URI to Action mappings via an XML configuration file. This file describes request URIs and how the ActionServlet should dispatch them. A typical mapping is provided in Listing 4.

When the ActionServlet receives the request such as http://myapp/SaveUser.do from the EditUser.jsp, it understands that its mapping corresponds to the path attribute defined in the XML configuration file, and that it should invoke the perform method of the SaveUserAction class. The attribute "name" defines the ActionForm (model) that the action will receive and the scope attribute defines where the form will be found (request, session, context). It also defines URI mappings that the Action will use to determine where to forward. By keeping the application mappings external, the Struts framework can be easily modified without recompiling classes.

Online Business Systems has used the Struts application framework on many successful projects including Viewtrak.com, an integrated food source management tool that tracks production of cattle from producer to consumer. The architect, Curtis Linton of Online Business Systems, used Struts as the Web application framework and the Versata Logic Suite for business logic development and management. Example code from this project has been used in this article, and updated to current versions.

Business-Tier Pattern Framework
Naturally there are many approaches to implementing business-tier design patterns such as developing infrastructure components and business components.

First, to develop the business components we should consider a declarative approach, a business rules approach. Barbara von Halle in her book, Building Business Rule Systems, states, "It is no longer desirable to bury rules in specifications and program code where they are locked away, requiring costly intervention and overhead to effect change."

Second, we need to pay careful attention to J2EE best practices to avoid those performance pitfalls we've read about: too many fine-grained entity beans, caching, use of CMP, and so on.

Business-Tier Design Pattern Framework
Figure 3 illustrates a well-formed design pattern framework for the business tier.

Figure 3
Figure  3:

What follows is a discussion of this pattern framework in terms of the core J2EE design patterns. Using this framework, we'll also look at how products within the Versata Logic Suite leverage and implement these patterns and how they accelerate and simplify business logic development and maintenance.

Within the Versata Logic Suite, business components are built with the Versata Logic Studio from business-logic specifications, especially business rules. Java artifacts, such as value objects, value object assemblers, business objects (entity and session beans), and data access objects, are produced as well as deployment artifacts, such as database schemas, deployment descriptors, and test data scripts.

The business components may be accessed as regular Enterprise JavaBeans through the Versata Transaction Logic Engine or through the Versata Logic Server that includes the framework that follows the patterns we describe below. The Versata Logic Server also includes the optional Versata Presentation Engine, which supports the model-based development of HTML servlet (presentation tier) and Java (client tier) Web applications.

Business Delegate
Business Delegates within the presentation tier hide the remote method invocation and interaction with the Business Service pattern on the business tier.

The Business Delegate pattern represents the Model of our presentation-tier MVC pattern.

Business Service
The Business Service is the component that presents the actual business functionality to the outside world. This could be through RMI to an EJB, through messaging with JMS, or perhaps through SOAP to a Web service.

As an interface into our business logic we would consider Business Service one of the View components of our MVC-like pattern.

Value Objects
While a client may access EJBs directly via RMI calls to attribute getter and setter methods, in practice this conversational approach is expensive. A "value object" is an encapsulation of business data that can be serialized, allowing the client to make one RMI call to retrieve or update a set of related data.

The Versata Suite enables value objects to be created declaratively through the Versata Logic Studio, allowing attri- butes to be selected from objects in the entity object model, and creating composite objects by joining across object relationships. Value objects are also created for each entity object by default.

These value objects are also updatable, encapsulating behavior that allows them to interact directly with the Business Service, such as update, create, delete, and refresh. This is also true for composite objects - updates may be distributed across different business objects. They're also metadata value objects accessed somewhat like javax.sql.RowSet objects.

Considering the MVC pattern, value objects represent the view. This suggests to us that they should be model-independent, not encapsulate business logic. We should look to create value objects that represent how a system presents itself to the outside world as opposed to necessarily re-presenting internal models.

Value Object Assembler
Value objects are supported at runtime by the Value Object Assembler that builds and aggregates them from underlying business objects.

Would this component be a view or a controller? Value Object Assemblers typically are involved only in query operations, so they would be equivalent to a view component.

If we were more faithful to the MVC pattern, the view objects would access the model directly for querying state, only accessing the controller for updates. In fact, we sometimes see this pattern as a performance optimization, especially for accessing large sets of data. The value object will pull data straight from the data access object or JDBC, alleviating the need to instantiate an entity bean for each object instance.

Our implementation uses this optimization transparently. The Versata Value Object Assembler instantiates only business objects for query operations when it has to. Since it knows attributes are persisted or calculated, it infers whether it can retrieve data straight back from the data access object or whether business logic needs to be executed.

Data Access Object
Enterprise applications need to access data from multiple sources, SQL databases, LDAP servers, and legacy systems, for example. Data access objects form an abstraction layer and an encapsulation of the data between the data source and the business objects. This allows the business objects to use the same API no matter where the data is coming from.

You can write data access objects or use tools. A good example is IBM's VisualAge for Java (VAJ). VAJ's Enterprise Access Builder allows you to create data access objects for sources ranging from DB2 to CICS.

The Versata Logic Server has a powerful implementation of the data access layer. Access objects are created at runtime based on object metadata, runtime configuration properties, and transaction requirements. The administrator can change the data source at runtime and tune options, such as whether to use prepared statements, the prepared statement cache-size, connection pooling, and lock isolation levels, giving a great deal of flexibility and high performance without requiring hand-coded BMP.

Data access objects clearly represent the Model of our MVC-like business-tier pattern.

Business Objects
The components of the Business Object pattern encapsulate the business logic of our system. For J2EE enterprise applications, these components will usually be session beans, entity beans, and dependent object JavaBeans. We use the term business objects to describe these. The J2EE pattern recognizes that business objects could also be data access objects or JDBC helpers. For our framework these would be part of the Data Access Object pattern.

The business objects operate within the EJB container of the J2EE application server and use the services for coordinated transaction management and persistence, for example.

The Versata Logic Suite supports the automated creation of business objects from specifications. The system sequences, optimizes, and translates these specifications or what we call business rules into the business objects - the Java components. Typically some custom Java coding is required, which might be entered directly into business rules or used to subclass or add code to Java components. We typically see about 98-99% of the Java component built directly from rules.

Looking at the MVC patterns, would business objects be akin to the model or the controller? You could argue that they're part of the model, the intrinsic representation of what the business is. In a way though that's what the whole business tier represents. We prefer thinking about business objects as the controller. Recall that for the presentation tier, the controller provides the presentation logic. For the business tier, the business objects handle business logic, providing a clean separation from the data (the model) and from business services (the view).

Declarative Business Logic
What Not How - Declarative Not Procedural
As elaborated by C.J. Date in his book, What Not How, there's a move away from procedural programming - coding the steps of how we accomplish something - to the declarative - just saying what we want to accomplish in the first place and letting the system work out the best way of doing it.

An example of declarative programming is the EJB deployment descriptor, specifying what fields should have their persistence managed by the container. EJB 2.0 goes further by adding declarative support for container-managed relationships; something you have to manage programmatically today. We've also seen the Struts action mappings and view definitions as declarative approaches.

Automation of Business Rules
Consider the business requirement that the account balance is total billed invoices less payments received. Taking a procedural approach, we could then write code to update the account balance every time a payment is received or an invoice is sent out. What about when an invoice is cancelled? What about a cancelled invoice that's reinstated? What about deleting a payment? What about when a payment bounces? We need to be conscious of a number of side effects with a procedural approach. What about when the invoice's account changes? You need to subtract from one account and add to another, but only if the invoice has been billed.

Declaratively we might express this logic as:

  1. Account Balance=Total Billed-Total Payments
  2. Total Billed=sum (Invoice.TotalFee where InvoiceStatus ="Billed")
  3. Total Payments=sum (Payment.Total where PaymentStatus ="Active")
These are called business rules. Taking into account all side effects, these rules require over 300 lines of Java code across the Account, Invoice, and Payment objects. Listing 5 provides a small portion of the code built using the Versata Logic Suite as it appears in the Invoice object. The code implements logic to deal with a change in the InvoiceStatus of TotalFinalFee of an invoice and the impact on TotalBilled of an account.

Constraints are another type of business rule; they represent the policies under which a business can operate. Figure 4 shows constraints for the Customer object.

Figure 4
Figure  4:

In business rules terminology we call these calculations derivation rules - the attribute definitions are derived from other attributes. Figure 5 shows several derivation rules for the Account business object, providing detail from the Total-Billed sum rule. Additional derivation types can be seen in the grid: a replicate, a calculation, a default, two sums, and a count.

Figure 5
Figure  5:

Business Rules Paradigm Shift
To develop with business rules a paradigm shift from the procedural to the declarative is required. Fortunately, it's an easier shift than we made to the object-oriented world, and one that business analysts quickly identify with.

After all, they're business rules. Some of the advantages of a rules approach are:

  • Business logic is not hidden in code: Business rules can be quickly found and understood and thus speedily and reliably modified.
  • Reduces errors: Business rules can be understood and signed-off by business users with no implementation errors as the system translates specifications into procedural code automatically. The testing cycle is also significantly reduced.
  • Naturally separates business logic from presentation logic: J2EE architects can concentrate on infrastructure and integration, not on the supervision of business logic development and maintenance.
  • Enables new Java developers who know the business to be quickly productive with J2EE technology.
Summary
The Model-View-Controller pattern continues to offer a powerful abstraction to the J2EE architect, creating well defined but loosely coupled components, enabling change. Although typically applied at the presentation tier, the MVC pattern can also guide us within the business tier, providing a clear delineation of work to developers and infrastructure components. Through the discussion of the Struts framework and the Versata Logic Suite for business logic development we also saw how change is enabled through systems driven from specifications, not code - moving toward what not how.

References

  • Date, C.J.(2000). What Not How: The Business Rules Approach to Application Development. Addison-Wesley.
  • The original GUIDE paper and continuing work: www.businessrulesgroup.org
  • von Halle, B. (2001). Building Business Rule Systems. John Wiley & Sons, Inc. www.buildingbusinessrulesystems.com
  • Alur, D., Crupi, J., and Malks, D. (2001). Core J2EE Patterns: Best Practices and Design Strategies. Prentice Hall.
  • Sucharitakul, A. (2001). "Seven Rules for Optimizing Entity Beans." http://developer.java.sun.com/developer/technical
    Articles/ebeans/sevenrules/.
    May.
  • Geary, D.M. (2001). Advanced JavaServer Pages. Prentice Hall.
  • Struts: http://jakarta.apache.org/struts
  • Versata, Inc.: www.versata.com

    Author Bios
    Steven Sweeting is director of product management with Versata, Inc. Ever since he developed a C++ program to write most of his college COBOL assignment, he's worked hard to avoid coding repetitive business logic. [email protected]

    Clive Jones is a senior enterprise Java developer with Online Business Systems, a leading consulting company employing over 300 people throughout Canada and the U.S. He is based in Winnipeg, Manitobo. [email protected]

    Aaron Rustad is a senior Java developer for Online Business Systems. He specializes in architecting and developing enterprise applications with a primary focus on Java and open-source technologies. [email protected]

    	
    
    
    
     Listing 1 
    
    public UserForm extends ActionForm { 
    private String user = null; 
    private String address = null; 
    
    public getUser() { .. } 
    public setuser() { .. } 
    .. 
    .. 
    
    public ActionErrors validate (ActionMapping mapping, 
    HttpServletRequest req) 
    { 
      ActionErrors errors = new ActionErrors(); 
      If (user == null || user.length() < 1) 
       { 
    Errors.add("user", new ActionError("error.user.required")); 
      } 
      .. 
      .. 
      return errors; 
    } 
    } 
    
    
     Listing 2 
    
      <!-- Importing the tag strut tag libraries --> 
    <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> 
    <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> 
    
    .. 
    .. 
    
    <html:form action="/SaveUserAction" focus="user"> 
    <table border="0" width="100%"> 
    
       <tr> 
         <th align="right"> 
           <bean:message key="prompt.username"/> 
         </th> 
         <td align="left"> 
           <html:text property="user" size="16" maxlength="16"/> 
         </td> 
       </tr> 
    
       <tr> 
         <th align="right"> 
           <bean:message key="prompt.address"/> 
         </th> 
         <td align="left"> 
           <html:text property="address" size="16" maxlength="16"/> 
         </td> 
       </tr> 
    
       <tr> 
         <td align="right"> 
           <html:submit property="submit" value="Submit"/> 
         </td> 
         <td align="left"> 
           <html:reset/> 
         </td> 
       </tr> 
    
    </table> 
    
    </html:form> 
    .. 
    .. 
     Listing 3 
    
      public final class SaveUserAction extends Action { 
    Public ActionForward perform(ActionMapping mapping, 
    ActionForm form, 
    HttpServletRequest req, 
    HttpServletResponse res ) throws 
    IOException, 
    
    ServletException { 
    ActionForward forward = null; 
    
    UserForm userForm = (UserForm) form; 
    
    UserDelegate userDelegate = new UserDelegate(); 
    
    try { 
    userDelegate( userForm ); 
    } catch ( DelegateException e) { 
    forward = mapping.findForward("failure"); 
    } finally { 
    if (forward == null) { 
    forward = mapping.findForward("success"); 
    } 
    } 
    return forward; 
    } 
    
    
     Listing 4 
    
      <action-mapping> 
    <action 
    path="/SaveUser" 
    type="com.demo.SaveUserAction" 
    name="userForm" 
    scope="request"/> 
    <forward name="success" path="/saveSuccessful.jsp"/> 
    <forward name="failure" path="/saveFailed.jsp"/> 
    </action-mapping> 
    
     Listing 5 
    
      if ( childCascadeUpdate ) 
    { 
        BigDecimal addValue = new BigDecimal("0"); 
        BigDecimal subValue = new BigDecimal("0"); 
        BigDecimal delta    = new BigDecimal("0"); 
    
        if ((this.getInvoiceStatus()).equals("B")) 
        { 
         addValue = getTotalFinalFee(); 
        } 
        if ((this.getOldInvoiceStatus()).equals("B")) 
        { 
         subValue = getOldTotalFinalFee(); 
        } 
        delta = addValue.subtract(subValue); 
        if ( ! delta.equals(new BigDecimal("0")) ) 
        { 
         if ( !newParent.isInitialized() ) 
            newParent.setDataObject(this.getAccount()); 
    
         if ( ! newParent.isObjNull() ) 
       newParent.getDataObject().setAdjust("TotalBilled",delta, true); 
            } 
        } 
        return; 
    } 
    
      
     
    

    All Rights Reserved
    Copyright ©  2004 SYS-CON Media, Inc.
      E-mail: [email protected]

    Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.