Guidelines, Patterns, and code for end-to-end Java applications.Java Adventure Builder Demo 1.0 Early Access 3 > Architecture Guide Adventure Builder Application Architecture, Early AccessThis document examines the architecture behind the early access version of the Adventure Builder Sample Application, which focuses on using the latest Java 2 Platform, Enterprise Edition (J2EE) 1.4 technologies. For recommendations and guidelines on architecting and designing enterprise applications, see Designing Enterprise Applications With the J2EE Platform, Second Edition. For recommendations and guidelines on architecting and designing Web services, see Designing Web Services with the J2EE Platform. The Adventure Builder application will consist of four application modules: a Web customer application, and three applications for fulfilling an order. This document covers only the Web application. It illustrates how Web-only developers can benefit from the J2EE technologies and demonstrates Web tier design strategies and patterns. One interesting point to note is that the Web customer application is a Web-only application and does not have an Enterprise JavaBeans tier (EJB tier). We chose a Web-centric design primarily so that we could provide guidelines for applications that do not have an EJB tier. Using the J2EE platform, a Web application can be designed in two ways: EJB-centric or Web-centric. The Java Pet Store Application illustrates how to write a Web application in an EJB-centric manner. It is an MVC-based application that makes a heavy use of local enterprise beans to implement the model and the controller. The Adventure Builder application illustrates the other option: how to write a Web application in a Web-centric manner. EJB technology is a key technology in the J2EE platform, but not all J2EE applications need to use it. A Web-only application is a valid J2EE application as well. Also note that other applications in the Adventure Builder enterprise, such as the order fulfillment application, follow an EJB-centric design and illustrate guidelines for applications using EJB technology. The Adventure Builder application is a simple travel shopping application. Adventure Builder customers use a browser to shop for travel packages. The Adventure Builder Web application requirements are as follows:
Figure 1 shows the use case diagram for the Web application. Figure 1: Use Case Diagram for Adventure Builder Web ApplicationAdventure Builder Architecture The following sections discuss the considerations (often referred to as motivational forces) for the application design, followed by a description of the specific choices that were made for the example application itself. In addition, this section provides the rationale for why these choices were made. A number of factors were considered when designing the Adventure Builder Web application. Some of the key design considerations will now be outlined briefly. The following areas were identified as prime motivational design factors: Choice of TiersOne important design consideration is mapping application modules and functionality to the different tiers and technologies on the J2EE platform. Some choices are obvious, such as having a Web tier when a Web browser client is required. Other choices may depend on several factors. Issues such as data access and transactional needs, security, portability and modularity of design, lead to deciding how to optimally map the application modules to the client, Web, EJB, and EIS (data storage) tiers. An important question is whether to use an EJB tier. Based on the application's needs, one might choose not to use enterprise beans and the EJB container and tier. One factor that may lead to choosing an EJB tier is the need for a formal business tier and data model. Often the choice is not really based on technical requirements, but may be based on other factors. The expertise of the development team may also affect this decision. For example, a team with strong Web-tier and SQL skills may find it easier to write a Web-only application. Data Access and Transactional NeedsAnalyzing the application's requirements made it apparent that very few of Adventure Builder's actions are transactional in nature. When the user browses the catalog shopping for trips Adventure Builder's database access actions are predominantly read operations. The application performs update operations when a user creates a new user account or when a user creates a new sign on. Also, when a user submits an order, the interaction is transactional. The application's transactional model is a simple model, as it only performs transactions to a single database. There are no distributed transactions across multiple databases. In addition, the data in both the catalog and the user accounts is fairly stable and the tolerance for stale data is fairly high. The catalog of trips changes infrequently, and the data that has been read and displayed to the user is not a transactional view (database locks are not held between a user's requests). Considering these database usage requirements, the Adventure Builder Web application is not heavily transactional. Session State StorageSession state, or conversational state, is information that relates to a particular user's interactions with an application and which may span multiple user requests. However, session state does not usually persist beyond the user's session. Examples of session state are shopping cart state and sometimes multi-page form data not yet pushed to the database. Typically, an application that spans all four J2EE tiers--that is, client tier, Web tier, EJB tier, and EIS or data storage tier--keeps session state in the EJB tier. The choice of where to store session state is primarily impacted by how the application is mapped to the J2EE tiers. For a complete discussion on maintaining session state, see: http://java.sun.com/blueprints/qanda/app_arch/index.html . SecurityThe application makes use of a simple security model: self-registration of users. That is, the user manages the account without any administrative intervention. The Adventure Builder Web site supports registered and anonymous customers. An anonymous customer can:
A registered customer has all of the above capabilities, plus a registered customer can sign on and sign off to the application. Sign on requires entering the previously registered user name and password, and sign off assures that subsequent requests to the application require an explicit sign on. A registered customer that is signed on can purchase a trip. The Web application needs to track customers who have not signed on so that it can present a sign-on page when these customers request sign on or when they attempt to purchase the contents of the shopping cart. The sign on page allows sign on and registration operations. CommunicationWhen a user submits an order, a purchase order document is sent from the Adventure Builder Web application to the back-end order processing application, which fulfills the order. The communication protocol between Adventure Builder and the order processing application does not require a message provider, although there may be a third party messaging service for the order processing application. The Adventure Builder Web application's communication is to the back-end order processing system, which may or may not be programmed in Java. In the J2EE platform, you can choose among various communication technologies, such as JAX-RPC, Java Message Service, RMI over IIOP, and so forth. Application Architectural Model and Design Now that we've discussed the design motivations or forces, let's look at how the application was designed to solve these issues. The application leverages the J2EE 1.4 platform features available for implementations relying heavily on the Web tier. The Adventure Builder Web application's architecture follows the model-view-controller (MVC) architectural approach. The MVC architecture divides applications into three layers--model, view, and controller--and decouples their respective responsibilities. Note that this document does not repeat the discussion on the model-view-controller architecture, nor does it discuss the motivations for using this architecture (see the MVC pattern for more detail). This application is also designed using several common patterns catalogued on the BluePrints Web site pattern section. Patterns provide a great means for implementing a J2EE application. Patterns allow for component reuse, good design, and future revisions. The Adventure Builder utilizes a set of patterns in its architecture to provide a solid foundation. Figure 2 demonstrates a pattern architecture that may be used to develop a Web application such as the Adventure Builder Demo consumer application.
Reusable application logic is provided utilizing the command pattern. An application controller maps a request to a specific command handler to process various requests to update the model. The Facade pattern is utilized to access model data in such a way as to allow for separation of model data type from control code. The Data Access Object (DAO) pattern is used to abstract the source of data being accessed from the application. Used together the patterns provide a solid architecture for Web applications. Choosing TiersIt is important to choose the proper tier on which the application resides. This is a process of mapping the application functionality to J2EE tiers. Typically, applications are spread across the client, Web, EJB, and EIS (data storage) tiers. It was decided to use a Web-centric design by using only the Web tier and by accessing data using the JDBC API rather than enterprise beans. As mentioned in the beginning of this document, a Web-centric design was chosen in order to illustrate guidelines for Web-centric applications. Choosing whether to have an EJB tier or not impacts your application design significantly. Since this application did not use an EJB tier, the application had to programmatically provide the services that an EJB tier provides. For instance, handling of transactions, handling of user sign on, handling of data access, handling of concurrency, etc. The following sections will address how a Web-centric design deals with these types of issues. Storing Session StateUsually, applications store session
state in the Web or EJB tiers. Since this application is Web-centric
and does not have an EJB tier, session state is stored in the Web
tier. This application has very little session state.
It stores the virtual cart state describing the current vacation
package which consists of the activities, lodging, transportation, and
package options such as date and number of people. Also, the
application will store multi-form
data when creating accounts and signing on new users for the first
time. For a Web-tier centric design, session
state for a user is stored in the Web tier in the servlet Managing Business LogicTypically, when an application design includes an EJB tier, business logic code is placed in the enterprise beans. However, the Adventure Builder application uses a Web-centric design with no EJB tier. There are programmatic implications for the Adventure Builder Web site application because it does not use enterprise beans. Principally, most of the business logic is performed in the command handler implementation classes. A Web-centric design should still follow a model-view-controller pattern and separate presentation, controller, and business logic. To achieve this separation, the Adventure Builder Web application places business logic in its command handler implementation classes and it could also put business logic and rules into the Facades. The command classes use facades, which in turn use Data Access Objects (DAOs), to interact with the data sources. Accessing DataSince this application does not use enterprise beans, it uses the JDBC API for all the data access and follows the Data Access Object pattern to interact with the EIS tier. The application's model consists of three components: a customer component, a sign on component, and a catalog component. All three components follow the same design: a facade, a DAO factory, a DAO interface, and a DAO implementation object. (Refer to the classes below Command Handler in See Class Diagram of Web Application Architecture in Figure 3.) Each component has appropriate tables in the database to persist the data. In this design, the facade objects hide the data access objects from the client command. The client command interacts with the facade and does not need to know the type of data source (enterprise bean, DAO object, or some other object) masked by the facade. The DAO Factory is used to create the particular DAO class corresponding to the database type in this environment. When a user request requires data access, the CommandHandler's implementation class to process that type of request interacts with the application's customer, catalog, or sign on facade, depending on the desired operation. The facade returns a data model object, representing data held in the database, to the command. The application uses a service locator to look up the data source. The DAO implementations contain all database access code. It also manages the connections to the database. For each method call, it opens a connection and closes that connection when the call completes. The J2EE platform pools database connections to minimize performance overhead. An example of this data access interaction is the CustomerHTMLAction command calling the Customer Facade to access the customer data source. The CustomerFacade uses the DAO Factory to create the proper kind of instance of the AccountDAO interface, which in this case is the PointbaseAccountDAO . The PointbaseAccountDAO has all the data access code for the PointBase database in this deployment environment. When a client command needs to get the details of an existing account, the CustomerFacade returns an Account model object re(DAO) factory, a DAO interface reflecting the data in the database. For cases where data access is read only, such as to the catalog, the view uses JavaServer Pages Standard Tag Library (JSTL) database access tags to read from the database. Managing ConcurrencyThe facade caches the DAO implementation instance reference so that all clients accessing the application use the same implementation instance. Thus, there is one instance of a customer facade (and sign on and catalog facade) and DAO implementation in existence for the entire life of the application, and all subsequent clients use this same instantiation. This can be done because the DAO implementation is a stateless class; that is, it maintains no client state. By having a stateless DAO implementation that is reused for all clients, database access to look up the deployment descriptor is done only once and only one object is created. This reduces performance costs. In addition, keeping the DAO implementation stateless means that there is no shared state among clients, thus eliminating some concurrency issues, something normally handled by the EJB container. The application holds references to the facades in its application scope; that is, for the entire application life. Application scope is stored in the servlet container and is shared state among all application users. This application caches these facades in the AdventureComponentManager . Managing TransactionsWhile the J2EE platform permits both container-managed and programmatically-managed transactions, container-managed transactions are only available for enterprise beans. Thus, for a Web application such as the Adventure Builder Web site, the only choice is to write code to manage transactions. The J2EE 1.4 platform provides two choices for handling Web container (that is, non-EJB container) transactions: the JDBC API or the Java Transaction API (JTA) transaction facilities. Note that the J2EE platform includes an implementation of JTA so it is always available to Web applications written on the J2EE platform. With either one, the developer must include code in the application to manage any necessary transactions. This code explicitly marks the boundaries of the transaction. JDBC TransactionsWith JDBC transactions, which are
controlled by the transaction manager for a DBMS, the transaction
data is committed based on the J2EE platform's default
auto-commit per connection. The developer can use the If the connection is in auto-commit mode, then all its SQL statements are executed and committed as individual transactions. Note that each statement being executed is a separate transaction, even if done on the same open connection. This is adequate for simple cases, where the application opens a JDBC connection, performs a query, and then closes the connection. For more complex cases, the developer needs to group a set of SQL
statements
into a single transaction. This is done by disabling the auto-commit
mode and grouping
the SQL statements into transactions that are terminated by a call to
either the method JTA TransactionsJTA, which is controlled by the J2EE transaction manager, provides a standard interface for demarcating transactions. Although the JDBC auto commit functionality is fine for simple cases, since it assures an application that it is viewing updated data after a single database read or write operation, JTA should be used when an application performs multiple database access operations that are dependent on each other. Applications should use JTA to demarcate that the entire transaction includes multiple database access operations--the demarcation indicates where the transaction begins and where it rolls back or commits. JTA transactions can span multiple
databases, even those from different vendors. However, it does not
support nested transactions: a given transaction must complete before
another transaction may be started. JTA transactions are demarcated
using the begin, commit, and rollback
methods of the Accessing multiple DAOs and using more than one connection requires using JTA. JTA must be used to demarcate a transaction when an application performs two separate database access operations that depend on each other to commit properly, since these multiple operations form one complete transaction. The TransactionFilter which is (part of the WAF) provides Adventure Builder the ability to wrap specific request processing and response generation in a single JTA transaction. This filter based on settings in the WAF configuration file mappings.xml will demarcate a transaction and commit the transaction for specified requests. This allows requests that must access to more than one transactional resource to perform such transactions as a single unit. When a user in Adventure Builder creates an account using the CustomerHTMLAction a single transaction is started when data is written to the SignOn components database table (for the SignOnFilter) and the Adventure Builder's Customer component database table. If either of the operations fails such as the user name is already selected or there was an error writing data to the Customer components database both fail and the data will be rolled-back to its original state. The following example is from the mappings.xml file which is used by the TransactionFilter to determine where or not the processing of an HttpServletRequest will be transactional.
Note that the attribute "isTransactional" is set to true for the createcustomer.do which is mapped to the CustomerAction. Choosing Between JDBC and JTA TransactionsUsing JDBC transaction management methods on a connection is not the preferred mechanism, principally because JTA provides the same capabilities as JDBC without restricting the transaction to a single connection. Since a DAO is used to encapsulate JDBC code, it is best if each DAO manages its own connections, and on each method should open its own connection and then close that connection when the method completes. Although it is possible to bypass the JDBC auto-commit option and pass an open connection to other components, and thus access multiple DAOs, this is not considered good practice. Instead, it is better to use JTA to manage the transaction. For example, an application with a transaction that accesses two different DAOs (and each DAO accesses a database table) uses JTA to start the transaction, then calls the methods on the DAOs. Each DAO opens and closes its connections within the method call, and the application commits or rolls back the transaction when all work completes. With this approach, transaction code is kept separate from data access code: the DAOs encapsulate the data access connections and are independent of transaction code. Connections are not passed to and from components: the DAO's method opens and closes the connection. If your transactional model becomes complex, you should consider using enterprise beans and leveraging the features of the EJB container. Handling SecurityAs noted with the application requirements, the Web site allows two types of users: anonymous and signed-on users. Anonymous users can browse the catalog, but only signed-on users can access the submit order functionality. The Web application requires user registration and sign on only when the user requests a protected page, which is a page that the application deems viewable by signed-on users only. The application supports self-registration, allowing users to create and manage their own accounts. The user is free to choose any user name, since the application does not perform any identity verification. Such flexibility is different from systems such as internal enterprise IT applications, which typically require an administrator to verify a user before creating an account. A key design choice was whether to manage security with the application or the container. The Adventure Builder Web application does not use the three J2EE container login mechanisms: HTTP basic authentication, SSL authentication, or form-based login. Instead, it manages user accounts as part of the application, representing users and their account information with a DAO and storing that information in a database. In this scenario, it is often preferable to have the application layer instead of the system layer manage users. The application handles security programmatically. It uses a servlet filter called SignOnFilter to intercept all requests and performs authentication. The SignonFilter uses the SignOnFacade to access the username and password data. There is also a DAO to interact with a database, retrieving and storing user sign on and account information. The DAO interface UserDAO has an implementation called PointbaseUserDAO Using a MVC FrameworkAnother key design choice is whether to use a framework, such as Struts or JavaServer Faces, for a model-view-controller application. We used our own Web application framework (WAF), which is a customizable model-view-controller framework for building applications. Since this application has no EJB tier, the WAF command action classes, which are regular Java objects, extend the WAF Action interface. In this application, the command handler classes in the Adventure Builder WAF are implemented in the Web tier. CommunicationBased on the communication requirements, the Adventure Builder application is designed with a Web service interaction using JAX-RPC. The Web Service Architecture document describes this in more detail. When a customer submits an order, the Adventure Builder customer Web application CheckOutHTMLAction command builds a purchase order XML document and uses JAX-RPC to send the purchase order to the Order Processing Center application. The Order Processing Center application has a Web service endpoint interface PurchaseOrderIntf that can be used for submitting orders and returning an order id that can later be used for order tracking. The order processing service is implemented with an EJB web service endpoint PoEndpointBean that contains the code to process the order. Adventure Builder Consumer Application Implementation
Adventure Builder uses the model-view- controller in
the design of the Web tier. The model-view-controller mechanism is
provided by the BluePrints Web Application Framework (WAF) which
is also used in the Java The WAF provides the model via JavaBeans components and JavaObjects in the HttpServletRequest and the HttpSession, the view is generated by JSP technology along with JavaServer Pages Standard Tag Libraries (JSTL), and the control logic including screen flow is performed using servlet technology. The WAF also provides a patterns based approach. Let's examine Adventure Builder's Web architecture and design to see how it addresses the application's motivating factors. Figure 3 shows a component diagram for the customer Web application architecture. Before reviewing this figure look at the corresponding pattern relationship in Figure 2: Pattern Architecture Figure 3: Adventure Builder Consumer Web Site ArchitectureBriefly, here is the flow of the application through the parts of Figure 3. A client initiates a request, which first passes through the TransactionFilter (intercepting filter pattern) that performs will start a transaction for specific requests and then through the SignOnFilter that provides a security check which protects specific URIs mapped to screens in the application based on information specified in the signon-config.xml file. All user requests that pass the SignOnFilter check flow through the front controller which is called MainServlet (front controller pattern). The MainServlet delegates the processing of the request to the application controller which is called RequestProcessor. A request is mapped to a specific class implementing the HTMLAction interface (command pattern) which in turn processes an HTTP request. The mappings for requests to actions are specfied in an XML file called mappings.xml which is located under the WEB-INF directory of a Web application. An HTMLAction may use the ServiceLocator (service locator pattern) to locate model facades (facade pattern) which provides the appropriate interface to resources such as a database via a DAO pattern or an EJB component. The customer component provides a facade in Adventure Builder shielding the developer from many of the details behind how the customer data is stored. The customer facade utilizes the service locator pattern to locate the appropriate DAO implementation and JDBC connection. An HTMLAction may perform business logic, update information in the HttpSession for future processing by other HTMLActions and or place data in the HttpServletRequest for display in the view (view helper pattern). Following request processing completes, the ScreenFlowManager (dispatcher view pattern). Adventure Builder implements the composite view pattern with a template mechanism that utlizises a servlet and a JSP page that aggregates component JSP pages. The TemplateServlet is mapped to all URIs ending in *.screen. The TemplateServlet will then look at the text preceeding the .screen and based on that text, map the request to data in a screen definitions file (screendefinitions_en_US for US English). Meta data is placed in the HttpServletRequest and the request is forwarded to a view template JSP page whichis also specified in the screen defintions file. The view template JSP page applies a template to correctly format the pages. The screen view may retrieve the response data from the view helper JavaBeans component. Generating the ViewThe Adventure Builder demo uses JSP 2.0 technology extensively to generate the view. The JSP 2.0 expresssion language (EL), simple tag handlers, classic tag handlers, as well as tag files are used. Let us look into detail how the different JSP technologies are used together to generate the view JSP 2.0 Expresson Language (EL)The EL is used extensively to access data maintained in components in the HttpServletRequest and HttpSession. The controller places or changes the state of objects in the application. The EL is used only to access the state of the data and generate a view.
EL functions provide users with a way to define functions accessible
from the EL. EL functions are defined in a TLD file like a custom tag
and
thus must be
declared using the
The EL was not designed to allow JSP developers to easily perform logic in JSP pages. While it is not impossible to preform business logic using a combination of EL and functions or possibly custom written functions, it is recommended that the EL be used for accessing data related to the presentation of the view. Simple TagA SimpleTag is a new type of custom tag that may be easily implemented by simply providing a class that implements the SimpleTag interface or extends the SimpleTagSupport class and implement adoTag method.
The DateSelectorTag implements
SimpleTagHandler interface and is used
to show a data entry component as a set of three combo boxes. This
component presents the
current data or may be set to a specific date.
Classic Custom TagsCustom tags that do not implement the SimpleTag interface are know as classic custom tags. There are cases when the classic tags should be used such as when a developer wants more control over the implementation of a tag handler. The tags used in Adventure Builder are part of the WAF and are used generally for generation where form data is determined dynamically at runtime. In order to avoid some very complex processing code we created some reusable form tags which are used throughout Adventure Builder. These include CheckboxTag, SelectTag, FormTag, and InputTag.Tag FilesJSP 2.0 technology provides the ability to reuse portions of presentation logic. Adventure Builder contains the tag file tabbed_view.tag which is a tag file to represent an adventure package. The image below shows the generated HTML a user of Adventure Builder will see when it is time to configure an adventure package.
While the graphic may look simple there is a great deal of presentation logic needed to generate the view in an interactive way. The following code is from the Adventure Package page of the Adventure Builder it uses a tag file to show a tabbed view of a customer's adventure package. |
<%@ taglib prefix="abtags" tagdir="/WEB-INF/tags" %> |
Notice that using a tag file is just like using any other custom tag in JSP. The difference here is that the directive for declaring the tag is a directory and the name of the tag corresponds to the file name of the tag file. When developing a tag file a tag file need only be written. TLD configuration files are not needed. The source which is written in JSP and in turn may utilize other tags is placed in the /WEB-INF/tags directory of the web application.
<%@ taglib prefix="c" uri="/WEB-INF/c.tld" %> |
Note that the content generated by the table view tag may need to be customized per application but overall the tag may be reused. Tag files allow a developer to reuse JSP content and is preferable to using a programmed custom tag when the content may need to be modified. This can be done by a developer with JSP knowledge and does not require a developer to recompile tag.
Prior to using the tag file, the logic displaying for each tab had to be repeated many times in a single file. Changing the look and feel of the tabbed pane was difficult and prone to errors in that a single change had to be repeated for each tab. We were able to reduce the complexity of the tabbed view in the Adventure Package display by converting the tabbed view into a reusable view component, otherwise known as a tag file.
Tag files are ideal for creating presentation-centric reusable components where there is more presentation than logic. In cases where there is more logic involved or the tag must interface with an application of other tags, a programmed custom tag should be considered.
JSTL 1.1 is integral for generating a view without the use of scriptlets or proprietary tags. Using JSTL, we were able to do most presentation view formatting neccessary for Adventure Builder.
<table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0"> |
<c:choose>
<c:when test="${j_signon == true}">
<td><a href="/blueprints/code/adventure/1.0/docs/signoff.do">
<strong class="banner_link">Sign Off</strong></a></td>
</c:when>
<c:otherwise>
<td><a href="/blueprints/code/adventure/1.0/docs/signon_welcome.screen">
<strong class="banner_link">Sign On</strong></a></td>
</c:otherwise>
</c:choose>
|
<c:url value="/adventure.screen" var="viewPackageURL"> |
<fmt:formatNumber value="${cartBean.total}" type="currency" />
|
<sql:query var="packages"> |
|
| ||||||||||||