David Moskowitz, President, Infoblazer LLC.
September 2009
© David Moskowitz, 2009. All Rights Reserved.
Introduction
XX Automation provides an application development framework that requires little or no procedural coding to handle typical application tasks. Instead, the application is specified using XML configuration and a Java Object Model. XSL transformations are applied to generate the view content, while CSS is used for presentation and formatting. This approach generally leads to a simpler and more elegant solution that a purely procedural approach. Where the applications needs more than simple CRUD, additional business logic can be easily incorporated into the process.
XX automation uses Hibernate as an object-database mapping layer. On of the main tasks in developing an XX automation application is to develop this Hibernate layer. The Hibernate layer includes the Java object model and the Hibernate configuration files needed to map this model to a relational database. One approach to this task is to annotate the Java model classes using XDoclet tags and automatically generate the Hibernate mapping files using Apache Ant. In addition, Hibernate includes tools that can be used to forward engineer a database (DDL) from Hibernate mapping files. This approach is independent from the XX framework. XX automation simply requires the Hibernate model to be in place.
XX Automation builds upon the XX Foundation. In the Foundation layer, implementation functions are written by the developer that returns XML. XSL transformations are applied to the XML results before display. (See the XX Foundation tutorial or additional XX documentation for more information).In XX automation, the implementation functions are provided for standard CRUD (Create, Retrieve, Update, Delete) operations.
It is the author’s belief that 80% of typical web application development relates to CRUD operations. XX Automation supports these standard operations. Custom, developer-implemented, operations can also be specified. These custom operations can extend the functionality of the standard CRUD operation to take advantage of XX persistence even when a custom implementation is needed.
Developing the guestbook
In order to demonstrate an implementation of the XX framework, a very simple online guestbook application was developed. This application allows web users to leave and view comments posted on a web site.
The complete source code for this tutorial is available as a WAR distribution at Sourceforge.net.. Installation instructions are also included in this distribution. Also, it is recommended that you read the XX foundation tutorial first, as that provides as basic for XX automation.
Identify Use Cases
The first step of the application development will be to identify the use cases that will be implemented. This tutorial will discuss the following guestbook use cases, representing a small subset of the actual guestbook application. The full application is available online and in distribution format.
- Add Comment– Enter a message in the guestbook.
- List Comments– List messages. Includes searching and paging functionality.
- View Organization List– List organizations
- View Organization– View a single organization
- Save Organization– Save a single organization
- View User List– List users
- View Page Notes– View page design notes. Page specific.
Here is a UML Diagram for these Use Cases.
We’ve added one actor to our Use Case diagram: the User. At this point, we have only one type of user, so security and permissions will be ignored for now. We also don’t have any authentication (log in) use cases, so we can assume that all use cases are accessible to the User without the need to log in to the system. Also, note the View Page Notes use case is included in several of the other use cases and is not accessible independently.
Create Object Model
Based on the use cases identified, we create an object oriented class model. In this simple scenario, we only need one or at most two objects, a Message object and possible a Contact object. To make things a little more interesting, we’ll add some additional classes that will serve to illustrate common programming techniques. The diagram below shows the initial object model.
In the model, a Message can exist without being linked to a Contact. This allows for anonymous message posting.
We include some additional common class types
- Organization, linked to the contact
- Organizationtype, describing the Organization
- Userrole, indicating the Contact’s security permissions in the application.
We can then create the Java entity model required by the XX Automation Framework. Note that XX contains a set of basic, commonly used, entity types and in many cases the application can simply use these. In this case, we’ll create a Contact object and Message Object.
To create these two objects (and any XX automation entity) we need to extend the XX Framework class org.xxframework.basetypes.BaseRecord. For certain objects, it is possible to extend other XX classes. For example, most applications may need a more elaborate User object than the basic XX version provides. In the guestbook tutorial, the Contact class extends org.xxframework.basetypes.BasePerson.
Here are the Java classes we created.
Contact Class
Here is the signature for the Contact class.
public class Contact extends org.xxframework.basetypes.BasePerson implements Serializable { … getters and Setters here… } |
The rest of the class simply includes getter and setter values for class attributes.
Note that the contact class extends the framework base class org.xxframework.basetypes.BasePerson, which contains common person-related.
The Contact class must also implement Serializable interface, to be compatible with Hibernate. The rest of the class contains standard attributes along with getter and setter methods.
Message Class
Here is the signature for the Message class
public class Message extends BaseRecord implements Serializable { … Getters and Setters here …. public String getShortmessage() { if (message.length() > 100) return message.substring(0, 100); else return message; } } |
Since this class does not build off any other XX base classes, it must at least inherit from the BaseRecord class. All XX entity classes must do this.
Note, the Message class needs to implement the Serializable interface to conform to Hibernate conventions. Also, we can use the full capabilities of Java to add additional methods, such as getShortmessage, that don’t correspond to a DB field or aren’t involved in a Hibernate mapping. These fields will however, be available to Castor for inclusion in the XML output and subsequent display.
Also, note the inclusion of the addedbyuser attribute, as shown in the UML class diagram. This field will be used to store the System User associated with the Message, generally representing the logged in user. For this example, we won’t join Message to Contact. This will be used to illustrate implementation of simple table operations with no related tables involved. Other classes will illustrate techniques in the case of related object hierarchies.
Spring Configuration
The XX Foundation Tutorial described the necessary components for a simple non-database XX application. If we want to incorporate Spring persistence, we need additional configurations and components, as does any Spring database application.
Web.xml
The following elements must be added to web.xml to enable Hibernate
<filter> <filter-name>hibernateFilter</filter-name> <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class> |
applicationContext.xml
<?xml version=”1.0″ encoding=”UTF-8″?> <beans xmlns=“http://www.springframework.org/schema/beans” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:tx=“http://www.springframework.org/schema/tx” xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd”> <tx:annotation-driven/> <bean id=“global” class=“org.xxframework.spring.config.Global” scope=“singleton”> <bean id=“viewResolver” class=“org.springframework.web.servlet.view.InternalResourceViewResolver”> <!–Utilities —> <!– Framework DAO classes —> <bean id=“baseDAO” class=“org.xxframework.dao.BaseDAOImpl”> <bean id=“loginDAO” class=“org.xxframework.dao.LoginDAOImpl”> <bean id=“recordControl” class=“org.xxframework.control.RecordControl” scope=“prototype”> <bean id=“typeControl” class=“org.xxframework.control.TypeControl” scope=“prototype”> <bean id=“login” class=“org.xxframework.control.Login”> <bean id=“transactionManager” class=“org.springframework.orm.hibernate3.HibernateTransactionManager”> <property name=“hibernateProperties”> <!– Begin custom controllers —> <bean id=“userControl” class=“org.xxframework.guestbook.control.UserControl” scope=“prototype”> <bean id=“userDAO” class=“org.xxframework.guestbook.dao.UserDaoImpl”> |
The only elements in the above file that will need modification are the hibernate configuration sections and any custom bean definitions. The rest are standard bean definitions that support the framework. You will only need to add to this if you require custom code. In the guestbook application, there is one additional control class, and a related DAO. These classes will be discussed below.
From the class model, we can generate a database schema. For the tutorial, we are using MYSQL 4.1.
Implementation
With the Use Cases specified and the object model built, we can begin the actual implementation.
List Guestbook
The following diagram shows the List Guestbook page, as implemented.
Let’s first concentrate on the center portion of the screen, which contains the data specific to list messages operation. Additional page elements, such as the menu and login form will be discussed below.
We have four components or sections directly related to the List Guestbook page. Each of these components will be translated into an XX class.
The classes/portal components are the following
Class | Description |
1 | HTML form to add a message |
2 | Message Filter section |
3 | Message List section |
99 | Design notes section |
Here is the XX config file. The config file specifies each of the XX implementation class, the resulting JSP page, as well as other XX configuration elements.
<class id=”1“ scope=”session“ use=”xsl“ applyxsl=”true“> <classname>recordControl</classname> <method>get</method> <hb_classname>org.xxframework.searchfilter.Dummy</hb_classname> <xsl_file>AddMessage.xsl</xsl_file> </class> <class id=”2“ scope=”page“ applyxsl=”true“ use=”xsl“> <classname> recordControl </classname> <method>get</method> <hb_classname>org.xxframework.searchfilter.GuestbookFilter</hb_classname> <xsl_file>ListGuestbookFilter.xsl</xsl_file> <cache_context use=”string“/> </class> <class id=”3“ scope=”application“ applyxsl=”true“ use=”xsl“ timeout=”20000“> <classname> recordControl </classname> <method>list</method> <hb_classname>org.xxframework.guestbook.entity.Message</hb_classname> <xsl_file>ListGuestbook.xsl</xsl_file> </class>
<endpoint>[xmlroot]/../../ListGuestbookNotes.html</endpoint> <cache_context use=”string“> </cache_context> </class> |
We will discuss Class 3 in more detail first, as that is the most involved.
Here is the relevant potion of the XX config file with line numbers
1 | <class id=”3“ scope=”application“ applyxsl=”true“ use=”xsl“ > |
2 | <classname> recordControl </classname> |
3 | <method>list</method> |
4 | <hb_classname>org.xxframework.guestbook.entity.Message</hb_classname> |
5 | <xsl_file>ListGuestbook.xsl</xsl_file> |
6 | <security secure=”false“/> |
7 | </class> |
Line 1: id is the identifier to the particular class. It must be unique within the config file and will correspond to a section in the JSP file.
Caching scope is set to application level, meaning the page will be full cached once generated. Also, the XML results will be transformed using XSL.
Line2– specified the Spring bean, as defined in applicationContext.xml, that will be responsible for returning XML data to the framework. In this case, we are using the default XX framework implementation class. This class will always be used for XX automation, unless the developer provides a custom implementation..
Line3– the method to be called in the implementation class will be “listdata”.
Line4 – the entity class that will be involved in the data related operations.
So from the preceding configuration, the framework will perform a list operation on the Message class. This will effectively return a set of all Message objects in the database. Filters, maximum returned number of records, and other factors may effect which messages are returned.
The set of Message returned will be converted to XML, using the castor mapping specified in “message.list.castor.xml”. The mapping file name is set by convention and cannot currently be overridden.
Line 5– The transformation ListGuestbook.xsl will be applied to the XML returned from the list application.
Line 6 – No security will be applied to this function. This page will be available to all users, whether they are logged in or not.
The only additional piece to look at is the XSL transformation, ListGuestbook.xsl.
First, we can look at the XML that would be passed into the transformation.
<?xml version=”1.0″ encoding=”UTF-8″?> <root> <list_results class=”org.xxframework.guestbook.entity.Message“ edit=”” short_class=”Message“> <message> <id>2</id> <author>dave</author> <title>Please check out the new Forum</title> <message>Click the link on the left.</message> <dateadded>2006-01-16T16:13:58.000-05:00</dateadded> <shortmessage>Click the link on the left.</shortmessage> </message> <message> <id>1</id> <author>dave</author> <title>Hello World</title> <message>Hello.This is the first message in the guestbook.</message> <dateadded>2006-01-16T16:13:20.000-05:00</dateadded> <shortmessage>Hello.This is the first message in the guestbook.</shortmessage> </message> </list_results> <request> <sort> <dateadded>desc</dateadded> </sort> <filter> <title/> <author/> <message/> </filter> <start>1</start> <recordcount>50</recordcount> <total_records>2</total_records> </request> <select_lists/> <security secure=”false“/> <system_user> <user> <id>1</id> <firstname>David</firstname> <lastname>Moskowitz</lastname> <userid>dave</userid> <fullname>David Moskowitz</fullname> <password>*******</password> <userrole> <id>1</id> <typename>Administrator</typename> </userrole> </user> </system_user> </root> |
Without getting into too much detail at this point, the XML is taken directly from the Message class representation, as generated by the Castor mapping file or, if a mapping doesn’t exist, the default Castor mapping behavior. The set of message elements are wrapped in a “list_results” element.
The request element contains the original web request that requested the current operation. In other words, the XX framework read the request and produced the XML above. Note the filtering and sorting related elements. These are passed in form the “guestbook search box”. Filtering and sorting will be discussed later in this document.
The XSL file used is shown below. Note, in keeping with a CSS oriented approach to separating content from presentation, the XSL transformation simply provides the content needed for the resulting page. Presentation related elements or attributes should be eliminated or limited. Elements should have content related meaning, and not be included to ultimately signify presentational attributes when transformed using CSS. This goal is not always full realizable, but should be worked towards.
<?xml version=”1.0″ encoding=”UTF-8″?> <xsl:stylesheet version=”1.0“ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform“ xmlns:fo=”http://www.w3.org/1999/XSL/Format“> <xsl:output method=”html“/> <xsl:include href=”includes.xsl“/> <xsl:template match=”/root“> <xsl:apply-templates select=”list_results“/> </xsl:template> <xsl:template match=”list_results“> <div id=”messages“> <div> <h2>Guestbook Entries</h2> <div class=”record_range“> <xsl:call-template name=”display_record_range“> <xsl:with-param name=”count“> <xsl:value-of select=”count(message)“/> </xsl:with-param> </xsl:call-template> </div> <xsl:call-template name=”record_navigation_link“> <xsl:with-param name=”listpage“>/guestbook/ListGuestbook?sort/dateadded=desc</xsl:with-param> </xsl:call-template> </div> <table summary=”XX Framework Guestbook Entries“ class=”datatable“ id=”messages“> <thead> <tr> <th id=”id“/> <th abbr=”Posted“ id=”posted“>Posted On</th> <th id=”author“>Author</th> <th id=”title“>Title</th> </tr> </thead> <tbody> <xsl:apply-templates select=”message“/> </tbody> </table> </div> </xsl:template> <xsl:template match=”message“> <input type=”hidden“ name=”id“> <xsl:attribute name=”value“><xsl:value-of select=”id“/></xsl:attribute> </input> <tr> <th headers=”id“> <xsl:attribute name=”id“><xsl:value-of select=”id“/></xsl:attribute> <a> <xsl:attribute name=”href“>/guestbook/ShowMessage?id=<xsl:value-of select=”id“/></xsl:attribute> <xsl:value-of select=”id“/> </a> </th> <td> <xsl:attribute name=”headers“><xsl:value-of select=”id“/> posted</xsl:attribute> <xsl:call-template name=”format-date-time“> <xsl:with-param name=”xsd-date-time“ select=”dateadded“/> <xsl:with-param name=”format“ select=”‘%m/%e/%Y %i:%M %P’“/> </xsl:call-template> </td> <td> <xsl:attribute name=”headers“><xsl:value-of select=”id“/> author</xsl:attribute> <xsl:value-of select=”author“/> </td> <td> <xsl:attribute name=”headers“><xsl:value-of select=”id“/> title</xsl:attribute> <xsl:value-of select=”title“/> </td> </tr> <tr class=”row_caption“> <td/> <td colspan=”3“> <xsl:attribute name=”headers“><xsl:value-of select=”id“/></xsl:attribute> <xsl:value-of select=”shortmessage“/> <xsl:if test=”string-length(shortmessage)= 100“> </xsl:if> </td> </tr> </xsl:template> </xsl:stylesheet> |
JSP
XX uses JSP to ultimately display dynamic information to the user. However, since most of the view creation logic is handled in XSL and CSS, the JSP is generally a very light page wrapper, with little functional logic.
In the guestbook tutorial, A single JSP page is used to display the results for all the guestbook use cases. Here are the main elements of the page. The actual source code can be seen in the tutorial distribution.
Let’s look at this JSP page in detail.
The JSP page contains static information, fixed dynamic components that are used across all pages, and XX supplied data for this particular use case.
<%@ page language=“java” import=“java.util.*” %> <META HTTP-EQUIV=“CACHE-CONTROL” CONTENT=“NO-CACHE”> <META HTTP-EQUIV=“PRAGMA” CONTENT=“NO-CACHE”> <html> <head> <%@ include file=“../../inc/page_headers.jsp” %> <%@ include file=“../../inc/xx_functions.jsp” %> <title><%= getTitle(request.getAttribute(“xx_title”), “XX Framework Demo Application”)%> </title> <meta http-equiv=“Content-Type” content=“text/html; charset=iso-8859-1”/> <link href=“css/style.css” rel=“stylesheet” type=“text/css”/> <link href=“css/form.css” rel=“stylesheet” type=“text/css”/> <link href=“css/form_position.css” rel=“stylesheet” type=“text/css”/> <link href=“css/guestbook.css” rel=“stylesheet” type=“text/css”/> <link href=“css/guestbook_position.css” rel=“stylesheet” type=“text/css”/> <link href=“css/position.css” rel=“stylesheet” type=“text/css”/> <jsp:include page=“scripts.html”></jsp:include> </head> <body> <jsp:include page=“../../loginmenu.xx?xx_nameoverride=loginmenu.xx”/> <div id=“main_contents”>
|
The screenshot above showed the various components of the List Guestbook page. We’ve already discussed the message related portions. Ignoring the headers and top menu, since they are static, and specific to the xxframework.org site, we can identify several additional sections
- Side Menu
- Login Form
Also note the inclusion of two other pages using the jsp:include tag; loginmenu and mainmenu. This is the equivalent of a server-side include, but using an XX generated page. The xx_nameoveride attribute is necessary when including another XX page in this manner. Other than that addition, the include should work as expected. These types of includes are useful for data that will be used in most of an applications pages. Alternatively, you could include the page in each relevant XX config file, but that would be repetitive and therefore more difficult to alter.
Side Menu
Lets examine the side menu first as it is simply static content. We can use the jsp:include tag to include an HTML file. This file could be specified as part of the XX Config file, but then it would need to be included in every XX configuration. It is much simpler to move this recurring component into a JSP page.
Here is the HTML for this menu component.
<div class=”headbox“> XX Demonstration </div> <ul> <li> <a href=”/guestbook/Home“ class=”leftmenu“>Overview</a> </li> </ul> <div class=”headbox“> XX Foundation </div> <ul> <li> <a href=”/guestbook/HelloWorld“ class=”leftmenu“>Hello World</a> </li> <li> <a href=”/guestbook/HelloWorldWeb“ class=”leftmenu“>Hello World Web </a> </li> <li> <a href=”/guestbook/HelloWorldFile“ class=”leftmenu“>Hello World File </a> </li> <li> <a href=”/guestbook/HelloWorldXML“ class=”leftmenu“>Hello World XML/XSL </a> </li> </ul> <div class=”headbox“> XX Automation </div> <ul> <li> <a href=”/guestbook/ListGuestbook?sort/dateadded=desc“ class=”leftmenu“>Guestbook Application</a> </li> <li> <a href=”/guestbook/ListUsers“ class=”leftmenu“>Users</a> </li> <li> <a href=”/guestbook/ListOrganizations“ class=”leftmenu“>Organizations</a> </li> <li> <a href=”/guestbook/ListUserrole“ class=”leftmenu“>User Roles</a> </li> <li> <a href=”/guestbook/ListOrganizationtype“ class=”leftmenu“>Organization Types</a> </li> </ul> |
What’s missing from this static HTML is formatting. That is handled independently by a CSS stylesheet. Rollover functionality can also be specified in CSS. This is a refreshing simplification from typical presentation–heavy, JavaScript laden rollover HTML commonly seen. Since CSS is not the focus of this tutorial, the CSS stylesheet is not show, but is included in the tutorial distribution.
Login Menu
The login box is not static HTML, since the login fields are only displayed if the use has not already logged in. If the use is logged in, a welcome message and profile link is displayed.
This component is implemented using XX functionality.
The JSP command
<jsp:include page=“../../loginmenu.xx?xx_nameoverride=loginmenu.xx”/>
is used to incorporate this functionality. Since the target of the include is not static HTML, this command essentially calls the loginform servlet and the results are passed into the JSP page. The same results could be demonstrated by calling “loginform” directly as a URL.
Lets look in more detail at this servlet.
The login form is implemented as a standard XX servlet. We will just look at the config file at this point.
<xx_config newthread=“false” usepool=“false” poolcheck=“10000”> <classes> <class id=“1” scope=“session” cache=“disk” applyxsl=“true” use=“xsl”> <classname>recordControl</classname> <method>list</method> <xsl_file>loginmenu.xsl</xsl_file> </class> </classes> <jsp>xx_empty.jsp</jsp> </xx_config> |
A further description of this config file is provided later, but note a different JSP file is specified than the main page. This JPS, xx_empty.jsp, is essentially blank, except for the necessary code to include the XX content, as main.jsp contained surrounding HTML data.
This JSP page is very reusable. In fact, this page is used for the entire guestbook application. This reuse is made possible by using CSS positioning. In a table oriented approach, the page layout is fixed, necessitating a separate JSP for each layout. While it is certainly possible to reuse table oriented JSP pages if the layouts are similar, a CSS approach will yield the most flexible result.
List Organizations
Looking at the screen print for this use case
<xx_config> <classes> <class id=“1” scope=“page” applyxsl=“true” use=“xsl”> <classname>recordControl</classname> <method>list</method> <hb_classname>org.xxframework.guestbook.entity.Organization</hb_classname> <xsl_file>listOrganizations.xsl</xsl_file> <security secure=“false”/> </class> <class id=“99” scope=“application” cache=“disk” use=“file” applyxsl=“false”> <endpoint>[xmlroot]/../../ListOrganizationsNotes.html</endpoint> <cache_context use=“string”/> </class> </classes> <jsp>main.jsp</jsp> <title>Organization List</title> </xx_config> |
Looking at the config file and the display, No XSL File is used. The system will try to apply a default display.
Depends on certain naming conventions in place in such an example
Background in JSP, via other servlets.
Show Organization
The show message use case allows the user to click on a guestbook entry from the message list and see a detail screen for that particular message. In our case, the only difference between the list and show message displays is that the list will display the short message while the show will display the full guestbook message.
Config File
Here is the XX Config file.
<xx_config> <classes> <class id=“1” use=“xsl” scope=“page” applyxsl=“true” master=“true”> <classname>recordControl</classname> <method>get</method> <hb_classname>org.xxframework.guestbook.entity.Organization</hb_classname> <xsl_file>ShowOrganization.xsl</xsl_file> <security secure=“true”> <role name=“Administrator” mode=“any”/> <role name=“*” mode=“any”/> </security> </class> <class id=“2” scope=“application” cache=“disk” applyxsl=“true” use=“xsl” detail=“true”> <classname>recordControl</classname> <method>list</method> <hb_classname>org.xxframework.guestbook.entity.Contact</hb_classname> <xsl_file>ListUsers.xsl</xsl_file> <security secure=“false”> </security> </class> <class id=“99” scope=“application” cache=“disk” use=“file” applyxsl=“false”> <endpoint>[xmlroot]/../../ShowOrganizationNotes.html</endpoint> <cache_context use=“string”> </cache_context> </class> </classes> <jsp>main.jsp</jsp> </xx_config> |
Save Organization
This use case illustrates a Set (or Update in CRUD terminology) operation. The config file is similar to the earlier examples, with the method set to “set”. Error handling and caching clearing are generally more applicable to a set operation.
Here is the XX Config file
<xx_config> <classes> <class id=“5” use=“xsl” scope=“page” applyxsl=“true”> <classname>recordControl</classname> <method>set</method> <hb_classname>org.xxframework.guestbook.entity.Organization</hb_classname> <error_pattern><xx_error</error_pattern> <error_jsp>main.jsp</error_jsp> <error_xsl>reply.xsl</error_xsl> <security secure=“true”> <role name=“Administrator” mode=“any”/> <role name=“*” mode=“edit”/> </security> <cache_control> <cached_page name=“ListOrganizations.xml”/> <cached_page name=“ShowOrganization.xml”> |
This configuration is similar to those discussed already. However, as an Update operation, several new elements are present.
Cache Clearing
The cache_control element is used to clear specific cached data. This is generally used only on a data update operation. The cached page is referenced by the name of the XX config file and, optionally, a class id and other indications.
Error control
On an error, a different JSP and XSL transformation may be used.
While not a new element, note the last JSP element. On a retrieve operation , this will typiucally be a .jsp page. In this case, on a successful update to the organization, control is paged to the ShowOrganization page, essentially redisplaying the organization under operation. This is a design decision and is not required by XX. Instead an operation status page could be used.
Crud Mapping
It is important to understand how HTML form data is mapped to the XX Crud implementation layer and eventually through Hibernate and into the database.
The following screen shot shows the data entry component of the Organization display in edit mode.
Here is the HTML behind the screen is the following, again, without some extraneous HTML:
<form xmlns:fo=”http://www.w3.org/1999/XSL/Format” class=”dataentry” name=”SetOrganization” action=”SetOrganization” method=”POST”> <input name=”organization/id“ type=”hidden” value=”1″/> <div><label for=”name”>Name</label> <input xmlns:dt=”http://xsltsl.org/date-time” xmlns:str=”http://xsltsl.org/string” size=”30″ name=”organization/organizationname“ value=”Microsoft” id=”name” type=”text”/> </div> <div><label for=”organization_type”>Type :</label> <select size=”1″ name=”organization/organizationtype/id”> <option value=””/> <option value=”2″ selected=”true”>Corporation</option> <option value=”1″>LLC</option> <option value=”3″>Non-Profit</option> </select> </div> |
HTML to XML mapping is done by the HTML field names. The relevant field names are highlighted.
Upon submission, XX parsers the web request and form variables, and passes the following XML to the XX handler function.
<root sid=”CDDEFBDC1767E710E55CEBE4F580F8C4“> <request> <organization> <id>1</id> <organizationname>Microsoft</organizationname> <organizationtype> <id>1</id> </organizationtype> </organization> </request> <Initialization> <Init-params> <configFile>SetOrganization.xml</configFile> </Init-params> <Env-params> <Devel>true</Devel> <hibernate_config_file>/org/xxframework/website/entity/hibernate.cfg.xml</hibernate_config_file> <xml_path>C:\projects\xxguestbook\WebRoot\WEB-INF\xml\</xml_path> </Env-params> </Initialization> <Url-params/> </root> |
The organization specific data is contained in the organization element. Additional XML is wrapped around this element.
The organization element is converted (unmarshalled to be specific), via Castor, into an instance of an Organization class, then Saved to disk.
Additional automation components
Select List Population
The Organization page screenshot above, and related HTML, shows a select list used to display choices for organization type. While this data can certainly be hard coded into the HTML, XX also provides an automated select list facility.
![]() ![]() |
Select lists are defined in the XX_References.xml file. An example of this file, related to the organization type list is show below.
<!DOCTYPE references SYSTEM “http://www.infoblazer.com/dtd/xx_references.dtd”> <references> |
Select lists are generated based on the class (referenced by hb_classname in the XX config file). In this example, for a get operation in edit mode, a select list of OrganizationType objects in includes in the resulting XML. The field value and display value are also specified.
When a select list is specified in this manner, additional XML is included in the XML result of the operation. The values are then available to the XSL transformation. XX contains
<select_lists> <Organizationtype_list add_blank=”true“> <organizationtype display_value=”LLC“ id_value=”1“ id_field=”id“> <typename>LLC</typename> <id>1</id> </organizationtype> <organizationtype display_value=”Corporation“ id_value=”2“ id_field=”id“> <typename>Corporation</typename> <id>2</id> </organizationtype> <organizationtype display_value=”Non-Profit“ id_value=”3“ id_field=”id“> <typename>Non-Profit</typename> <id>3</id> </organizationtype> </Organizationtype_list> </select_lists> |
XSL templates to build HTML select lists from this type of XML.
Filtering
Filtering in XX can be accomplished by adding filter elements to the URL, either as part of a Get request or as fields in a submission form.
The list guestbook screen also includes a search/filter box, as shown below.
The HTML for the filter section of the page is show below.
<form class=”dataentry” name=”ListGuestbook” method=”post” action=”ListGuestbook”> <input value=”desc” name=”sort/dateadded” type=”hidden”/> <h2>Guestbook Search</h2> <div> <label for=”author”>Author</label> <input size=”30″ name=”filter/author” value=”” id=”author” type=”text”/> </div> <div> <label for=”title”> Title</label> <input size=”30″ name=”filter/title” value=”” id=”title” type=”text”/> </div> <div> <label for=”message”>Message</label> <input size=”30″ name=”filter/message” value=”” id=”message” type=”text”/> </div> <div> <label for=”recordcount”>Rows/Page</label> <input size=”30″ name=”recordcount” value=”50″ id=”recordcount” type=”text”/> </div> <div> <label for=”start”>Start Row</label> <input size=”30″ name=”start” value=”” id=”start” type=”text”/> </div> </form> |
As discussed above, upon form submission, XX parses the HTML fields, based on the field names, into an XML structure. By specifying naming as shown above, a filter element is created, which serves to filter the results of the form action. Two additional fields, “Recordcount” and “start” can be included to specify for paging, or can be hidden from user and function behind the scenes.
Caching
One of the advantages to the “portal” approach to page design is that individual sections can be cached independently. This is useful in an application like the guestbook, where sections of the page, such as the menu or login form, change infrequently.
Caching is specified in the XX config file.
The scope attribute of the class determines if a class if cached. Setting the scope to “application” or “session’ will cause caching to occur. An additional optional element within the class, the “cache_context” can further determine how a page is cached.
The following example comes from the list users componet of the Show Organization page. The relevant class component is shown.
<class id=”2“ scope=”application“ applyxsl=”true“ use=”xsl“> <classname>org.xxframework.control.RecordControl</classname> <method>list</method> <hb_classname etail=”true“>org.xxframework.guestbook.entity.Contact</hb_classname> <xsl_file>ListUsers.xsl</xsl_file> <security secure=”false“/> </class> |
In this example, the XML result is cached at the application level, based on the URL context, in this case, a call to display a particular organization. XX will cache based on the URL context by default. An additional cache_context element can be included to further control how caching occurs. See the reference document for more information on this element.
Cache Clearing
Cache can be cleared using a timeout approach, or based on certain events. Most typically, a cache will be cleared when an update operation is performed.
Cache clearing is accomplished by adding a cache_control element to the XX Config file.
In the example below, upon successful completion of the specified Set operation, the cache associated it the XX Config file editaccount.xml is cleared. In the case were editaccount.xml included multiple classes, all caches for those classes will be cleared. It is also possible to specify particular class caches to clear. See the reference document for additional information.
<xx_config> <classes> <class id=“1” scope=“page” applyxsl=“true” use=“xsl”> <classname>recordControl</classname> <method>set</method> <hb_classname>org.xxframework.petstore.entity.Useraccount</hb_classname> <error_pattern><xx_error</error_pattern> <error_jsp>main.jsp</error_jsp> <error_xsl>reply.xsl</error_xsl> <cache_control> <cached_page name=“editaccount.xml”/> </cache_control> </class> </classes> <jsp>EditAccount</jsp> <title>Account Detail</title> </xx_config> |
Optimizing the application
To optimize the application, we need to fine tune the Castor mapping files. Every list and get operation will produce XML. We can examine the XML produced by looking at the “response_.xml” files that are automatically generated when the devel flag in web.xml is set to true.
To do this, we load these files into a text editor, such as Altova’s XML Spy, and watch the results when testing each list and get operation. It is recommended to use a text editor that automatically loads changed files as that will streamline the process.
As the files are examined, fine tune the castor mapping files buy adding or removing field that are needed or not needed. This will greatly decrease database access and transformation time when coupled with Hibernate Lazy loading/
Castor Mapping Files
We will use the Show User use case as an example. We first look at the default XML generated when no castor mapping files is used.
<?xml version=”1.0″ encoding=”UTF-8″?> <root edit=”” mode=”edit“ class=”org.xxframework.guestbook.entity.Contact“ child_id=”” short_class=”Contact“> <contact xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance“ xsi:type=”java:org.xxframework.guestbook.entity.Contact“> <organization> <organizationtype> <typename>Corporation</typename> <description/> <addedbyname>David Moskowitz</addedbyname> <dateadded>2006-01-12T13:54:28.000-05:00</dateadded> <id>2</id> </organizationtype> <contacts xsi:type=”java:org.xxframework.guestbook.entity.Contact“> <userid>User</userid> <password> Userpwd</password> <userrole> <typename>Administrator</typename> <description>Do not delete</description> <modifiedbyname>David Moskowitz</modifiedbyname> <addedbyname>1</addedbyname> <datemodified>2005-07-26T14:16:17.000-04:00</datemodified> <dateadded>2005-03-02T15:50:15.000-05:00</dateadded> <id>1</id> </userrole> <fullname>test user</fullname> <lastname>user</lastname> <firstname>test</firstname> <city/> <email/> <addedbyname>David Moskowitz</addedbyname> <dateadded>2006-01-13T10:06:07.000-05:00</dateadded> <id>8</id> </contacts> <organizationname>Microsoft</organizationname> <modifiedbyname>David Moskowitz</modifiedbyname> <datemodified>2006-02-03T13:51:45.000-05:00</datemodified> <id>1</id> </organization> <userid>dave</userid> <password>password</password> <userrole> <typename>Administrator</typename> <description>Do not delete</description> <modifiedbyname>David Moskowitz</modifiedbyname> <addedbyname>1</addedbyname> <datemodified>2005-07-26T14:16:17.000-04:00</datemodified> <dateadded>2005-03-02T15:50:15.000-05:00</dateadded> <id>1</id> </userrole> <fullname>David Moskowitz</fullname> <lastname>Moskowitz</lastname> <firstname>David</firstname> <city>941</city> <email>dave@infoblazer.com</email> <modifiedbyname>David Moskowitz</modifiedbyname> <datemodified>2006-02-03T13:16:08.000-05:00</datemodified> <id>1</id> </contact> <request> <id>1</id> </request> <select_lists/> <one-to-many/> <system_user> <user> <id>1</id> <firstname>David</firstname> <lastname>Moskowitz</lastname> <userid>dave</userid> <fullname>David Moskowitz</fullname> <password> password </password> <userrole> <id>1</id> <typename>Administrator</typename> </userrole> </user> </system_user> </root> |
Note in particular that the contact’s organization and User role attributes are expanded completely. Since the Organization object, contains a embedded set of Contacts, in a real world application, this XML would be prohibitive long, since every contact for that organization would be included in the single contact XML document. In this case, there is only one contact for the organization in the sample application.
Now using the following mapping file to specify the particular elements we want in our XML result. In this case, we only want certain fields from the Contact and related Organization and Userrole table.
<!DOCTYPE mapping PUBLIC “-//EXOLAB/Castor Mapping DTD Version 1.0//EN” “http://castor.org/mapping.dtd”> <mapping> <class name=”org.xxframework.guestbook.entity.Contact“ auto-complete=”false“> <field name=”id“/> <field name=”firstname“/> <field name=”lastname“/> <field name=”fullname“/> <field name=”userid“/> <field name=”password“/> <field name=”email“/> <field name=”city“/> <field name=”dateadded“/> <field name=”datemodified“/> <field name=”modifiedby“/> <field name=”modifiedbyname“/> <field name=”addedby“/> <field name=”addedbyname“/> <field name=”middleinitial“/> <field name=”organization“/> <field name=”userrole“/> </class> <class name=”org.xxframework.basetypes.Userrole“ auto-complete=”false“> <field name=”id“/> <field name=”typename“/> </class> <class name=”org.xxframework.guestbook.entity.Organization“ auto-complete=”false“> <field name=”id“/> <field name=”organizationname“/> </class> </mapping> |
Incorporating this mapping file will produced a cleaner XML document.
<root edit=”” mode=”edit“ class=”org.xxframework.guestbook.entity.Contact“ child_id=”” short_class=”Contact“> <contact> <id>1</id> <firstname>David</firstname> <lastname>Moskowitz</lastname> <fullname>David Moskowitz</fullname> <userid>dave</userid> <password>password</password> <email>dave@infoblazer.com</email> <city>941</city> <datemodified>2006-02-03T13:16:08.000-05:00</datemodified> <modifiedbyname>David Moskowitz</modifiedbyname> <organization> <id>1</id> <organizationname>Microsoft</organizationname> </organization> <userrole> <id>1</id> <typename>Administrator</typename> </userrole> </contact> <request> <id>1</id> </request> <select_lists/> <one-to-many/> <system_user> <user> <id>1</id> <firstname>David</firstname> <lastname>Moskowitz</lastname> <userid>dave</userid> <fullname>David Moskowitz</fullname> <password>password</password> <userrole> <id>1</id> <typename>Administrator</typename> </userrole> </user> </system_user> </root> |
Notice that only those fields specified in the mapping occur in the XML. There is also a corresponding decrease in the SQL select statements executed against the database.
This mapping only affects the Contact element and has no effect on the system user or user elements.
Completing the Application
The complete guestbook sample application will include a Contact object as well as related objects.
The complete entity class diagram is as follows
Note we are not linking Message to Contact in this simple scenario. This allows for anonymous or non-registered users to post messages. This is for the sake of keeping the tutorial example as simple as possible.
Most of these classes inherit attributes of base classes in the XX Framework.
It should also be noted that Userrole is a part of the XX framework and is used directly, without subclassing. The full Object model is the following
You may have noticed the inclusion of additional attributes in the Contact.hbm.xml file that are not part of the Contact class itself. This is done since Contact inherits certain attributes from BaseRecord., such as addedbyuser in Message, as well as automatically adding “added by” and “modified by” attributes to the database. Note that these two attributes are defined in BaseRecord, therefore all XX derived classes will inherit these attributes. Each Database table and corresponding mapping should include these two attributes if they are desired. These attributes don’t need to be specified in Contact.java, but should be specified in the Hibernate mapping file to map to the corresponding database table.
This completes the foundation of the application. Next we need to implement the use cases through Java servlets.
The actual guestbook application will have additional Use Cases. Here is the complete use case diagram for the guestbook application.
Data Type Maintenance
Certain of the operations listed in the use case diagram above are provided by XX as part of the “type” maintenance system. These include
- ListType – preconfigured XX page, part of the “type” editing utility
- ListUserrole – preconfigured XX page, part of the “type” editing utility. Lists user roles for view and editing.
- LisOrganizationtype – Similar to ListUserrole, part of the “type” editing utility. Lists organization types for view and editing
- SaveType – preconfigured XX page, part of the “type” editing utility
An example of editing the organization type is show below.
These data type editing components can be easily incorporated into an XX application to provide maintenance of XX specified Java classes.
Conclusion
The goal of XX automation is to specify as much of the application as possible in XML or XSL. The complete guestbook demonstration application contains only one Java function: to check for duplicate User ID upon user registration. We could have left this validation to the database, but the resulting error message could be difficult to trap and might not be that friendly. Even so, the custom registration function can extend the CRUD handler’s update function, so only the additional validation check needs to be performed.
For more information on XX, please see the online XX documentation at http://www.xxframework.org.