In this tutorial you will learn how to use Kodo's reverse mapping tool to reverse-engineer persistent classes from a database schema.
You run a shop that sells magazines. You store information about your inventory in a relational database with the following schema:
-- Holds information on available magazines CREATE TABLE MAGAZINE ( ISBN VARCHAR(8) NOT NULL, ISSUE INTEGER NOT NULL, NAME VARCHAR(255), PUBLISHER_NAME VARCHAR(255) PRICE FLOAT NOT NULL, PRIMARY KEY (ISBN, ISSUE) FOREIGN KEY (PUBLISHER_NAME) REFERENCES PUBLISHER (NAME) ); -- Holds information on magazine articles CREATE TABLE ARTICLE ( TITLE VARCHAR(255) NOT NULL, AUTHOR_NAME VARCHAR(128), PRIMARY KEY (TITLE) ); -- Join table linking magazines and articles CREATE TABLE MAGAZINE_ARTICLES ( MAGAZINE_ISBN VARCHAR(8), MAGAZINE_ISSUE INTEGER, ARTICLE_TITLE VARCHAR(255), FOREIGN KEY (MAGAZINE_ISBN, MAGAZINE_ISSUE) REFERENCES MAGAZINE (ISBN, ISSUE), FOREIGN KEY (ARTICLE_TITLE) REFERENCES ARTICLE (TITLE) ); -- Each magazine has a 1-1 relation to its publisher CREATE TABLE PUBLISHER ( NAME VARCHAR(255) NOT NULL, REVENUE FLOAT NOT NULL, PRIMARY KEY (NAME) );
You've decided to write an application that will let you query your database through JDO.
If you haven't already, follow the instructions in README.txt. This will ensure
CLASSPATH and other environmental variables
are set up correctly. Once you've completed the installation
instructions, change into the
The tutorial uses the following files:
files make up a Hypersonic file-based database with the
schema outlined above. The database is already populated
with lots of magazine data representing your shop's
Uses JDO to execute user-supplied query strings and output
the matching persistent objects. This class relies on
persistent classes that we haven't generated yet, so it
won't compile immediately.
Properties file containing Kodo-specific and standard JDO
For this tutorial, make sure the following properties are set to the values below:
javax.jdo.option.ConnectionURL: jdbc:hsqldb:reversetutorial_database javax.jdo.option.ConnectionDriverName: org.hsqldb.jdbcDriver javax.jdo.option.ConnectionUserName: sa javax.jdo.option.ConnectionPassword:
solutions: Contains the
complete solutions to this tutorial, including all
java: Runs main methods in specified Java classes.
that can be executed by java.
kodoc: Runs the Kodo enhancer against the specified classes. More information is available in Section 5.2, “Enhancement” of the Reference Guide.
Now it's time to turn your magazine database into persistent JDO classes mapped to each existing table. To accomplish this, we'll use Kodo's reverse mapping tools.
First, make sure that you are in the
reversetutorial/jdo directory and that
you've made the appropriate modifications to your
jdo.properties file, as described
in the previous section.
Now that we have our environment set up correctly, we're going to dump our existing schema to an XML document. This step is not strictly necessary for Hypersonic SQL, which provides good database metadata. Some databases, however, have faulty JDBC drivers, and Kodo is unable to gather enough information about the existing schema to create a good object model from it. In these cases, it is useful to dump the schema to XML, then modify the XML by hand to correct any errors introduced by the JDBC driver. If your schema doesn't use foreign key constraints, you may also want to add logical foreign keys to the XML file so that Kodo can create the corresponding relations between the persistent classes it generates.
To perform the schema-to-XML conversion, we're going to use the
schema tool, which can be invoked via the included
schematool shell script.
-p option points the tool at your
jdo.properties configuration file.
-a denotes the tool's action.
-f flag tells the
tool what to name the XML file it creates:
schematool -p jdo.properties -a reflect -f schema.xml
The schema tool is described in detail in Section 4.14, “Schema Tool” of the Reference Guide.
All Kodo JDO tools look for default configuration in
a resource called
schema.xml XML file created
by the schema tool. As you can see, it contains a complete
representation of the schema for your magazine database. For
the curious, this XML format is documented in
Section 4.15, “XML Schema Format” of the Reference Guide.
Typically, JDO stores persistence and mapping metadata together
in the same file. As shop owner, you've decided that you want
to keep your mapping metadata separate from your persistence
metadata. JDO supports separating object-relational mapping
from persistence metadata through the
javax.jdo.option.Mapping property. This
property sets a logical name for your mappings. When it is
set, JDO looks for mapping metadata in special mapping files
suffixed with this name. Using the
javax.jdo.option.Mapping property, you can separate
concerns and even define multiple mappings for the same
classes. You have chosen
hsql as the logical
name for your mappings to the supplied HSQL database.
Add the following line to the
Run the reverse mapping tool on the schema file.
(If you do not supply the schema file to reverse map, the tool
will run directly against the schema in the database). The
tool can be run via the included
reversemappingtool script. Use the
-pkg flag to control the package name of
the generated classes.
reversemappingtool -p jdo.properties -pkg reversetutorial.jdo schema.xml
The reverse mapping tool has many options and customization hooks. For a complete treatment of the tool, see Section 7.2, “Reverse Mapping” of the Reference Guide.
Running the reverse mapping tool will generate
files for each generated class,
files for corresponding JDO application identity
package.jdo file containing
persistence metadata, and a
package-hsql.orm file containing
object-relational mapping metadata.
Chapter 5, Metadata and
Chapter 15, Mapping Metadata of the JDO Overview
discuss JDO persistence and mapping metadata, respectively.
Examine the generated persistent classes. Notice that the reverse mapping tool has used column and foreign key data to create the appropriate persistent fields and relations between classes. Notice, too, that due to the transparency of JDO, the generated code is vanilla Java, with no trace of JDO-specific functionality.
MagazineId, the generated
application identity class for
Note that it satisfies all of the requirements for application
identity classes mandated by the JDO specification, including
contracts. The other generated classes use
JDO's single field identity, a special case of application
identity for classes with only one primary key field.
Section 4.5, “JDO Identity” explains JDO
Finally, examine the
metadata file and
file. The former contains the necessary standard persistence
metadata, while the latter maps the generated classes and
their fields to the existing schema.
Compile the generated classes:
The reverse mapping tool has now created a complete JDO object model for your magazine shop's existing relational model. From now on, you can treat the generated classes just like any other JDO class. And that means you have to complete one additional step before you can use the classes for persistence: enhancement.
kodoc -p jdo.properties package.jdo
This step runs the Kodo JDO enhancer on the
package.jdo file mentioned above. The Kodo
enhancer will examine the file's metadata and enhance all listed
classes appropriately. See Section 5.2, “Enhancement” in
the Reference Guide for more information on the enhancer, including
how to use Kodo's automatic runtime enhancement.
Congratulations! You are now ready to use JDO to access your magazine data.
reversetutorial.jdo.Finder class lets you
run queries in JDOQL (JDO's Java-centric query syntax) against the
java reversetutorial.jdo.Finder <jdoql-query>
JDOQL is discussed in Chapter 11, Query of the
JDO Overview. JDOQL looks exactly like Java boolean expressions.
To find magazines matching a set of criteria in JDOQL, just specify
conditions on the
class' persistent fields. Some examples of valid JDOQL queries for
java reversetutorial.jdo.Finder "true" // use this to list all the magazines java reversetutorial.jdo.Finder "price < 5.0" java reversetutorial.jdo.Finder "name == 'Vogue' || issue > 1000" java reversetutorial.jdo.Finder "name.startsWith('V')"
To traverse object relations, just use Java's dot syntax:
java reversetutorial.jdo.Finder "publisher.name == 'Adventure' || publisher.revenue > 1000000"
To traverse collection relations, you have to use JDOQL variables.
Variables are just placeholders for any member of a collection. For
example, in the following query,
art is a variable:
java reversetutorial.jdo.Finder "articles.contains(art) && art.title.startsWith('JDO')"
The above query is equivalent to "find all magazines that have an article whose title starts with 'JDO'". For example, to find all magazines whose publisher published an article about "Next Gen" in any of its magazines:
java reversetutorial.jdo.Finder "publisher.magazines.contains(mag) && mag.articles.contains(art) && art.title.startsWith('Next Gen')"
Have fun experimenting with additional queries.
Remember to erase the