XX Automation Tutorial
David Moskowitz, President, Infoblazer LLC.
January 2006
© David Moskowitz, 2006. All Rights Reserved.
XX Automation provides an application development framework requiring little or no procedural coding to handle typical application tasks. Instead, the application is specified using XML configuration, XSL transformation, and a Java Object Model.
In order to demonstrate an implementation of the XX framework, a very simple online guestbook application will be developed. This application will allow web users to leave and view comments posted on a web site.
The guestbook tutorial is running live on the XXframework.org web site. The complete source code for this tutorial is available on http://www.xxframework.org/downloads.shtml.
Prior to the steps in this tutorial, the XX framework and related class libraries must be installed. Please see the installation document on the XX Framework web site further information. Also, it is recommended that you read the XX foundation tutorial first, as that provides as basic for XX automation.
The first step of the application development will be to identify the use cases that will be implemented. Since this is an example, we’ll create a very simple application with only three use cases. Additional related use cases will be added later. The initial use cases are are:
List Comments – Display a list of comments, possibly filtered, sorted, and with record navigation.
View Comments - Display a single comment entry
Add Comment – Post a comment to the guestbook.
Here is a UML Diagram

We add one actor to our application, the User. At this point, we have only one class 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 the three use cases are accessible to the User without the need to log in to the system.
Create Objects
Based on the use cases identified, we create an object oriented 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
An Organization linked to the contact
An Organizationtype, describing the Organization
A 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/Hibernate entity) we need to extend the BaseRecord class, which is part of the XX framework. 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, so we can extend User and create a custom application Contact class.
Here are the Java classes we created.

Contact Class
Here is the class definition for Contact
|
package org.xxframework.guestbook.entity;
import java.io.Serializable;
import org.xxframework.basetypes.Userrole;
public class Contact extends org.xxframework.basetypes.BasePerson implements Serializable { private static final long serialVersionUID = 1L; private Organization organization ; private java.lang.String userid; private java.lang.String password; private Userrole userrole; public Contact() { super(); }
public Contact(Integer id) { this.id= id; }
/** * @param organization The organization to set. */ public void setOrganization(Organization organization) { this.organization = organization; }
/** * @return Returns the organization. */ public Organization getOrganization() { return organization; }
/** * @return Returns the password. */ public java.lang.String getPassword() { return password; }
/** * @param password The password to set. */ public void setPassword(java.lang.String password) { this.password = password; }
/** * @return Returns the userid. */ public java.lang.String getUserid() { return userid; }
/** * @param userid The userid to set. */ public void setUserid(java.lang.String userid) { this.userid = userid; }
/** * @return Returns the userrole. */ public Userrole getUserrole() { return userrole; }
/** * @param userrole The userrole to set. */ public void setUserrole(Userrole userrole) { this.userrole = userrole; }
} |
Note that the contact class extends the framework base class [ org.xxframework.basetypes.BasePerson] which contains common person related.
The Contact class myst also implement Serializable interface, to be compatible with Hibernate. The rest of the class contains standard attributes along with getter and setter methods.
See the complete XX class model or source code for further details
Message Class
Here is the class definition for Message
|
package org.xxframework.guestbook.entity;
import java.io.Serializable;
import org.xxframework.basetypes.*;
/** * Guestbook Tutorial Message Class Entity * * @author David Moskowitz * @version 1.0 */ public class Message extends BaseRecord implements Serializable { String author;
private String title;
private Contact addedbyuser;
private String message;
private static final long serialVersionUID = 1L;
public Message() { }
public Message(Integer id) { this.setId(id); }
/** * * @return Returns the author. * */ public String getAuthor() { return author; }
/** * * @param author * The author to set. * */ public void setAuthor(String author) { this.author = author; }
/** * * @return Returns the message. * */ public String getMessage() { return message; }
/** * @return Returns the message. */ public String getShortmessage() { if (message.length() > 100) return message.substring(0, 100); else return message; }
/** * * @param message * The message to set. * */ public void setMessage(String message) { this.message = message; }
/** * * @return Returns the title. * */ public String getTitle() { return title; }
/** * * @param title * The title to set. * */ public void setTitle(String title) { this.title = title; }
/** * @return Returns the addedbyuser. */ public Contact getAddedbyuser() { return addedbyuser; }
/** * @param addedbyuser * The addedbyuser to set. */ public void setAddedbyuser(Contact addedbyuser) { this.addedbyuser = addedbyuser; }
} |
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 object needs to implement the Serializable interface to confirm 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 involved in a Hibernate mapping. These fields will however, be available to Castor for inclusion in the XML output.
Also, note the inclusion of the addedbyuser attribute. This field will be used to store the System User associated with the Message. 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.
Here is the Hibernate config file. Remember, It’s location within the Java package hierarchy is specified in the applicatin’s web.xml file.
|
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"> <hibernate-configuration> <session-factory> <!-- properties --> <!-- <property name="connection.url">jdbc:mysql://localhost:3306/orgxxfra_guestbook?autoReconnect=true</property>--> <property name="connection.url">jdbc:mysql://localhost:3306/guestbook</property>
<property name="connection.username">guestbook_user</property> <property name="connection.password">password</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property> <property name="cglib.use_reflection_optimizer">false</property> <property name="show_sql">true</property> <property name="show_sql">false</property> <!-- mapping files --> <mapping resource="org/xxframework/website/entity/Message.hbm.xml"/> <mapping resource="org/xxframework/website/entity/Contact.hbm.xml"/> <mapping resource="org/xxframework/website/entity/Baseperson.hbm.xml"/> <mapping resource="org/xxframework/website/entity/Userrole.hbm.xml"/> <mapping resource="org/xxframework/website/entity/Organization.hbm.xml"/> <mapping resource="org/xxframework/website/entity/Organizationtype.hbm.xml"/> </session-factory> </hibernate-configuration>
|
Here is the database, implemented in MYSQL 4.1.

And finally, Here is the hibernate mapping to link the Java Message classes to the database. Note that we don’t need to include the addbyuser attribute. We can add that in to the database at a later date when we want to expand the implementation. The mappings for the other classes are available in the source code for this tutorial
|
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping package="org.xxframework.guestbook.entity"> <class name="Message" table="messages"> <id name="id" column="id" type="integer"> <generator class="increment"/> </id> <property name="title" column="Title" type="java.lang.String"/> <property name="message" column="Message" type="java.lang.String"/> <property name="author" column="Author" type="java.lang.String"/> <property name="dateadded" column="dateAdded" type="timestamp"/> <property name="datemodified" column="dateModified" type="timestamp"/> <property name="modifiedbyname" column="lastModifiedBy" type="java.lang.String"/> <property name="addedbyname" column="addedBy" type="java.lang.String"/> </class> </hibernate-mapping>
|
Use Case implementation
Here are the use cases related to the message operations
ListGuestbook – list guestbook entries
SetMessage – save a guestbook entry
ShowMessage – display a single guestbook entry
XX Collaboration Diagrams and implementation
Each of the use cases below generates a single web page. The structure web page for ListGuestbook is the following format:

The JSP page contains a portal type framework with 5 slots for results shown in bold. Here is the code for the JSP page. In a production application, we would probably add a good deal more HTML design elements around the dynamic JSP portions. We could build this page using Table based formatting or CSS positioning.
If table based formatting is chosen, the layout would be similar to the following
ListGuestbook JSP wrapper
|
<%@ page language="java" import="java.util.*" %> <html> <head> <%! public String xxOutput(Object s){ String result = ""; if (s!=null) result=(String)s; return (result); } %> </head> <body> <h2><a href="/guestbook/Home">XX Framework</a></h2> <table width="800" border="1"> <tr> <td valign="top"><table width="200" border="1"> <tr> <td><%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_1")) %></td> </tr> <tr> <td><%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_2")) %></td> </tr> </table> </td> <td><table width="600" border="1"> <tr> <td><%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_3")) %></td> </tr> <tr> <td><%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_4")) %></td> </tr> <tr> <td><%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_5")) %> </td> </tr> </table> </td> </tr> </table> </body> </html> |
However, we recommend CSS based formatting and position. Therefore the JSP page wrapper is the following. Note
|
<%@ page language="java" import="java.util.*" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" dir="ltr"> <html> <title>XX Framework</title> <link href="/e2.css" rel="stylesheet" type="text/css"> <head> <%! public String xxOutput(Object s){ String result = ""; if (s!=null) result=(String)s; return (result); }
%> <jsp:include page="scripts.html"></jsp:include> </head> <body> <h2><a href="/guestbook/Home">XX Framework</a></h2> <div id="mainmenu"> <div> <%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_1")) %> </div> <div> <%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_2")) %> </div> </div> <div id="main_contents"> <div> <%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_3")) %> </div> <div> <%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_4")) %> </div> <div> <%= xxOutput(request.getAttribute("html_"+(String)request.getAttribute("configfile")+"_5")) %> </div> </div>
</html> |
Note that the live production version includes additional page content, such as headers and menus. The actual CSS layout is available in the source code to this demo.
The collaboration diagram, as well as the XX config file, indicate which components are used to generate the corresponding portal slot.
Here is the XX config file
|
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xx_config SYSTEM "http://www.xxframework.org/dtd/xx_config.dtd"> <xx_config usepool="false" newthread="false"> <classes> <class id="3" scope="page" use="xsl" applyxsl="true"> <classname>org.xxframework.control.RecordControl</classname> <method>get</method> <hb_classname>org.xxframework.searchfilter.Dummy</hb_classname> <xsl_file>AddMessage.xsl</xsl_file> <security secure="false"> </security> </class> <class id="4" scope="page" applyxsl="true" use="xsl"> <classname>org.xxframework.control.RecordControl</classname> <method>get</method> <hb_classname>org.xxframework.searchfilter.GuestbookFilter</hb_classname> <xsl_file>ListGuestbookFilter.xsl</xsl_file> <security secure="false"> </security> </class> <class id="5" scope="page" applyxsl="true" use="xsl"> <classname>org.xxframework.control.RecordControl</classname> <method>list</method> <hb_classname>org.xxframework.guestbook.entity.Message</hb_classname> <xsl_file>ListGuestbook.xsl</xsl_file> <security secure="false"> </security> </class> <class id="1" scope="page" applyxsl="true" use="xsl"> <classname>org.xxframework.control.RecordControl</classname> <method>list</method> <xsl_file>mainmenu.xsl</xsl_file> <security secure="false">
</security> </class> <class id="2" scope="page" use="file" applyxsl="false"> <endpoint>[xmlroot]/../../guestbookmenu.html</endpoint> <security secure="false"> </security> </class> </classes> <jsp>searchlist.jsp</jsp> </xx_config>
|
The XX Config file can be mapped visually, using a UML Collaboration diagram.

The classes and portal components are the following
|
Class |
Description |
|
1 |
The login/Logout section |
|
2 |
The main menu. Static HTML |
|
3 |
HTML form to add a message |
|
4 |
Message Filter section |
|
5 |
Message List section |
We will discuss Class 5 in more detail as that is the most involved.
Here is the relevant potion of the XX config file with line numbers
|
1 |
<class id="5" scope="page" applyxsl="true" use="xsl">
|
|
2 |
<classname>org.xxframework.control.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 |
</security> |
|
8 |
</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.
Scope sets caching off. The XML results will be transformed.
Line2- specified the class that will be responsible for returning XML data to the framework. In this case, we are using the default XX framework implementation class.
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”.
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>
|