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.
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
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
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 atOLR_HOME/tools/torque-gen-3.1
refered asTORQUE_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.
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.
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
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
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.
ant -f build-torque.xml datadump
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
ant -f build-torque.xml jdbc
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.
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.
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
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 pageTODO
TODO
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
.