Introduction

OLR is implemented using various third party application frameworks or software like the Enhydra Application Server to host the OLR application, Enhydra XMLC to generate Java wrappers for HTML documents and Apache Torque as a persistence layer and Java object model generation tool.

XML and RDF are used to describe and annotate courses. The cousrses can be viewed and authored via a HTML web user interface.

The following sections will describe how these tools are used within OLR and how a developer can extend the various parts of the OLR application like presentation, application and persistence/database layer.

Database and object model

The OLR database layer consists of a relational database model and a corresponding Java object model / persistence layer. Both parts are maintained using the Apache Torque Generator tool.

When we use the term Java object model, we mean a subset of Java classes. Instances of these classes persist as entries in tables in a (relational) database.

Doucmentation of the OLR database schema

Defining the database and Java object model

The relational database model and the Java object model are defined within a so called XML schema file. This schema file is read by the Torque Generator to create the relational database model (SQL DDL statements) and the Java object model (Java source code).

Thus, we only need to edit one file, the schema file, to generate the complete OLR database model and the the corresponding Java object model. Of course one needs to get familiar with the Torque database schema DTD.

The OLR schema file is located at OLR_HOME/src/sql/olr-schema.xml

Using Torque Generator

Once we have extended/changed the file olr-schema.xml we can start to generate SQL scripts for the database and tables as well as the Java source files, which form the OLR object model.

The OLR cvs repository contains a Torque Generator distribution, which we will use to execute changes in the olr-schema.xml file.

The torque Generator is located at OLR_HOME/tools/torque-gen-3.1 refered as TORQUE_GEN_DIR.

The generation processes we decsribe in the following as well as the used ant targets are also described on the Apache Torque Generator website.

The Apache Torque Tutorial and User Guide are good readings to get jump started with Apache Torque.

Generating SQL DDL statements

Make TORQUE_GEN_DIR your current working directory. The following command will store SQL statements to create database tables in the file OLR_HOME/src/sql/olr-schema.sql.

ant -f build-torque.xml sql

OLR also uses Torque's ID broker infrastructure to generate unique ids for primary keys in database tables. The ID broker relies on addional tables in our relational database. The SQL scripts used to create whats needed by the ID broker can be generated as follows.

The following command will store SQL statements to create database tables in the file OLR_HOME/src/sql/id-table-schema.sql.

ant -f build-torque.xml id-table-init-sql

OLR does not use generated ids for all tables. The olr-schema.xml reflects that i.e.

            <database defaultIdMethod="idbroker">
              ...              
              <table name="model_statement" idMethod="none">
                ...
              </table>
              ...
            </database>
          

The above olr-schema.xml snippet shows, that we use the ID broker by default. Some tables are marked as not using the ID broker.

Generating the Java object model

The following command will generate all needed Java source files. The sources are stored in OLR_HOME/src/java/olr/om.

ant -f build-torque.xml om

Usage of the Java object model

This section shows how the OLR Java object model can be used to query, retrieve and manipulate data objects. This is no complete documentation about the usage of the object model generated by Torque. Please see Writing a Sample Application and the Criteria howto on the Torque website for more detailed information.

Create, select and delete a user

This example shows how to create a new user in the OLR database using the Torque java object model. After the user was created we select the newly created user from database, output some user data and delete the user.

View the java source of this sample

RdfUser user = new RdfUser();

user.setFirstName("Bill");
user.setLastName("Gates");
user.setLogin("bgates");
user.setPassword("m--rosoft");

user.save();
            
// Select the user from db
user = RdfUserPeer.retrieveByPK(user.getPrimaryKey());                        
RdfUserPeer.doDelete(user);
          

The above example uses the classes RdfUser and RdfUserPeer. These classes were generated using the Torque generator. For each table in the OLR database a peer class and a data class is generated (and some others not discussed here). The data class (RdfUser), or better instances of it, reflect an entry/row of a database table with the same name as the model class (RdfUser). The peer class provides all kind of lookup and data/object manipulation methods. See the Torque tutorial for more details.

Assuming the current working directory is OLR_HOME/target this sample can be executed as follows.

ant torque-basics-sample

Doing a simple query using a Criteria object

The Torque peer classes provide many ways to specify a query. This example shows how to use the Torque Criteria class.

View the java source of this sample

Criteria criteria = new Criteria();
criteria.add(RdfGroupPeer.NAME, "Administrator");
List groups = RdfGroupPeer.doSelect(criteria);
            
RdfGroup group = (RdfGroup)groups.get(0);
            
System.out.println("Selected group " 
      + group.getName() 
      + " with id=" 
      + group.getId());
          

Assuming the current working directory is OLR_HOME/target this sample can be executed as follows.

ant criteria-sample

For more information whats possible using the Criteria class i.e. using joins, please see the Torque Citeria howto

Doing complex queries using SQL

This example shows how SQL queries can be used to retrieve data objects from Torque. This is sometimes useful for really complicated queries. However, we will demonstrate it using a simple join over the user and group table.

View the java source of this sample

            
String sql = "SELECT * FROM rdf_user, rdf_group "
    + "WHERE rdf_user.group_id=rdf_group.id "
    + "AND rdf_group.name='Administrator'";
            
List users = RdfUserPeer.populateObjects(RdfUserPeer.executeQuery(sql));
            
System.out.println("Administrators:\n");
            
for(int i=0; i<users.size(); i++)
    System.out.println(((RdfUser)users.get(i)).getFirstName());
          

Assuming the current working directory is OLR_HOME/target this sample can be executed as follows.

ant sql-sample

Retrieving foreign key collections

The Torque Generator generates methods for data classes, which can be used to retrieve a collection of all related objects. I.e. the class RdfGroup provides a method getRdfUsers(), which returns a List of RdfUser objects. This method is generated because the database schema defines a foreign key in table rdf_group, which references a primary key field in table rdf_user.

View the java source of this sample

RdfGroup group = ...retrieve a group
List members = group.getRdfUsers();
            
System.out.println("Members of group " 
	+ group.getName() + ":\n");
            
for(int i=0; i<members.size(); i++)
	System.out.println(((RdfUser)members.get(i)).getLogin());
          

Assuming the current working directory is OLR_HOME/target this sample can be executed as follows.

ant foreign-key-sample

Using transactions

Of course it is possible to isolate data/object manipulation within a transaction using Torque. All peer classes provide overloaded methods for data manipulation, where a java.sql.Connection object is passed addtionally. The following example shows how manipulations on a user and a group object are isolated.

View the java source of this sample

Connection connection = null;
        
try 
{
    connection = Transaction.begin(Torque.getDefaultDB());    
                        
    RdfGroup group = new RdfGroup();
    group.save(connection);
            
    RdfUser user = new RdfUser();
    user.setRdfGroup(group);
    user.save(connection);
            
    // Selecting the user/group from 
    // outside the transaction should not work
    try 
    {
        RdfUserPeer.retrieveByPK(user.getPrimaryKey());
        assert false;
    } 
    catch(Exception e) {}
            
    try 
    {
        RdfGroupPeer.retrieveByPK(group.getPrimaryKey());
        assert false;
    }
    catch(Exception e) {}
            
    // Selecting the user/group from 
    // inside the transaction should work
    assert (RdfUserPeer.retrieveByPK(user.getPrimaryKey(), connection) != null);
    assert (RdfGroupPeer.retrieveByPK(group.getPrimaryKey(), connection) != null);
            
    RdfUserPeer.doDelete(user, connection);
    RdfGroupPeer.doDelete(group, connection);
    Transaction.commit(connection);
}
catch(Exception e)
{
    try 
    {
        if(connection != null)
            Transaction.rollback(connection);
    }
    catch(Exception e2) { e.printStackTrace(); }
    e.printStackTrace();
}
          

Assuming the current working directory is OLR_HOME/target this sample can be executed as follows.

ant transaction-sample

Tricks

There is are some more useful things we can do with Torque when developing with OLR.

The following steps assume the current working directory is TORQUE_GEN_DIR. Database connection settings can be set in TORQUE_GEN_DIR/build.properties.

View a full list of Torque properties.

  • Dumping data from database into an XML data file
    ant -f build-torque.xml datadump
  • Creating SQl insert statements for a given XML data file
    ant -f build-torque.xml datadtd
    cp src/olr-default-all-data.xml ../../src/sql/olr-data.xml
    export ANT_OPTS="-Xmx512M -Xms128M -Xss32M"
    ant -f build-torque.xml datasql
    
    The third line is necessary, because I investigated an OutOfMemoryError during execution of the forth line.
  • Creating a Torque database schema file from a given database
    ant -f build-torque.xml jdbc

Presentation layer

OLR provides a HTML web user interface (ui) to author and read courses. The single screens of the ui are defined in various HTML pages located in the directory OLR_HOME/src/resources.

During a user session those screens are populated by the application layer with data from the underlying database(s). Thus the application layer needs to access and modify the internal structure of the HTML pages.

OLR uses Enhydra XMLC to generate a Java class (XMLC object) for each HTML page. These classes are used by the application layer to alter the internal structure of the HTML page at runtime. The OLR build system (Maven) invokes the Enhydra XML compiler (XMLC) and places all generated Java sources in the directory OLR_HOME/target/src/xmlc and belong to the package olr.presentation. The class and file names of the generated sources are the same as the names of the HTML pages, but the filename extension is of course .java. These sources are currently not stored in CVS.

Contract between presentation and application layer

The only contract between the presentation and application layer is to use id and class attributes for HTML elements, which should be accessible via the XMLC objects. The XMLC objects will then provide methods to access and alter the HTML structur using the DOM API as well as element access methods generated by XMLC.

Following the above implementation pattern, is is possible to design the web ui independent of the application layer as long as the id and class attributes are defined.

Changing HTML

If the HTML sources in OLR_HOME/src/resources have changed or if there are new sources, the XMLC classes need to be regenerated and recompiled and the OLR has to be restarted. To generate and compile the XMLC Java sources simply invoke maven as follows.

maven

XMLC example

The following example is taken from the OLR application and will show basic usage of XMLC in OLR and how the proxy classes are used to alter the structure of HTML pages.

The HTML page
          TODO
        
The Java source snippet
          TODO
        

Application layer

The Java package olr.presentation contains all application/controller classes. These classes manipulate the HTML pages via the XMLC objects. A typical usecase is to receive form data from a web browser, evaluate that data, manipulate HTML structure and send back a page depending on the evaluation result. During all those actions the persistence layer may be used to retrieve and manipulate data objects.

OLR follows a simple naming convention for presentaion objects (HTML and XMLC objects) and application objects. Lets say we have a login page defined in OLR_HOME/src/resources/Login.html, then there will also be a Java class olr.presentation.Login.java and a XMLC class olr.presentation.LoginHTML.java.