text: Castor is a multifaceted software tool being developed under the auspices of exolab.org, an informal organization involved in the development of open source, enterprise software projects based on Java and XML.
  The primary function of Castor is to perform data binding. Data binding is a process that facilitates the representation of one data model in another. For example, an XML data model, described by an XML schema document, can be approximately represented by Java classes. Castor helps by generating these classes from the XML schema document. Object instances of these classes are then able to store XML document data, so long as such documents conform to the XML schema.
  Such binding works both ways, of course: object instances of the generated classes can be easily transformed back into XML documents through a process known as marshalling. Castor's marshalling engine can introspect the Java data objects and generate corresponding XML document elements. Such marshalling can be refined through the use of user-defined mapping files, which Castor also supports.
  While XML data binding is very useful, this article will focus on another aspect of Castor: data binding of Java objects to tables, columns, and rows in a SQL database. This functionality falls under the heading of Castor JDO. The intent of the Java Data Objects (JDO) standard is to transparently persist Java objects. Although similar in name and intent to Sun's efforts, Castor JDO was developed largely independently of Sun's efforts, but aims roughly in the same direction. Be that as it may, the two technologies have different feature sets, and should not be assumed to be interoperable.
  Castor is able to employ a mapping file as a simple way to bind Java objects to SQL database tables. Instead of writing complex procedural code in Java to manage the database queries and updates via JDBC, Castor hides this complexity by using the mapping file entries and transparently performing the proper queries and updates in the background. This declarative mechanism of descibing how the objects and the database are linked makes maintenance easier, because mapping files are relatively easy to understand and can be changed without recompiling code. It's also much simpler in that it operates at a higher level of abstraction than functionally equivalent JDBC mechanisms allow.
  Unlike Castor's XML marshalling -- where there is a default mapping of a Java object to XML elements and attributes -- no default mapping exists for binding Java objects to SQL database tables: you must use a mapping file to enable this functionality. The mapping file contains explicit information on how Castor should represent a set of Java objects in a relational database.
  Mapping files are written in XML, and can be validated against either a DTD or an XML schema supplied by the Castor group. This type of validation will catch syntax errors, but it does take some practice to understand the concepts behind mapping files and understanding Castor's JDO behavior. If Castor JDO appears not to be storing data in the database, it's likely due to missing entries in an otherwise syntactically valid mapping file.
  Before going into the details of mapping, let's first present an overview
  of the mapping elements. For every Java class whose instances are to be
  stored in the database, a
  class element is required in the
  mapping file. These class elements reside one level below
  the
  mapping root element:
  <mapping> <description>Optional description of mapping file</description> <!-- you can include other mapping files --> <include href="other/mapping_file.xml"/> <class name="Class1" map- <description>Optional description of this class mapping</description> <field name="field> <!-- mapping of a class data member --> <sql> ... </sql> <!-- maps Java field to database column --> </field> <field> ... </field> ... </class> <class name="Class2" map- ... </class> </mapping>
  For each class to be mapped to a database table (the
  map-to attribute indicates which table), the data members of
  the class to be persisted (referred to as fields by Castor) will
  have corresponding field elements. Each field element in turn has a
  sql child
  element, which describes how such fields are stored in the database.
  Once a mapping has been established, Castor takes care of the queries and updates that are needed to fetch and store data as Java objects. It also handles conversions between SQL and Java datatypes seamlessly.
  A mapping file is written from the point of view of the Java class and describes how the properties of each object are to be stored in database tables, columns, and rows. These class properties are referred to as fields in the mapping file.
  The general rules for mapping Java objects to database tables are:
  get/setmethods.
  Castor uses the XML-format mapping file to determine:
  Every element and attribute of a primitive type in Java (
  int,
  boolean,
  double, etc.) can be mapped to a table column that is of a comparable SQL
  type. Some nonprimitive types (classes), such as
  java.lang.String,
  java.sql.Date,
  java.lang.Long, etc., can be mapped to a single table column, as
  well. All other Java classes must have a class element definition in
  the mapping file to be persisted in a database.
  Remember, Castor will not introspect a class and apply a set of default rules to guess the fields and attempt to persist them. This is different behavior from that of the XML marshaller.
  There may be cases where a class instance only exists as a member of a containing parent object (in other words, it makes an appearance only as a child of some other object). The mapping file conveniently allows such dependent objects to be denoted as such. The advantages of recording dependencies in the mapping file will be explained later.
  When reconstructing an object from a SQL database, Castor uses the mapping information to determine where the class' data members are stored in the database.
  It is possible to set up the mapping file so that an object doesn't have
  to be pulled from the database in its entirety, but can be lazily fetched.
  This means that certain members of the class instance will only be retrieved
  when the appropriate
  get method is called. The result is that large
  objects can be fetched incrementally -- avoiding the performance hit of
  fetching a load of data from the database that might not be needed by the
  program at that time.
  We're now ready to start in on the mechanics of how a set of Java objects are mapped to a SQL database. For this example, we assume the following environment:
  The main variable here is the database. Not all databases support the same features, and some support similar features differently. I will point out cases where the examples show a Postgres-specific way of doing things..
  There are two basic ways of binding the properties of a class to columns
  in a SQL table. The first method is to use public class methods to access the
  properties. By default, Castor uses this type of access, inferring the name
  of the public
  accessor/mutator methods from the name of the field being
  mapped. As was shown earlier, if the field name is
  id, then the
  accessor method is assumed to be
  getId().
  What if the method names are different from what Castor assumes? In that case, you have to inform Castor of the proper methods by specifying them in the field mapping element:
  <class name="ShippingLine" identity="id"> <map-to <field name="id" type="integer" key- <sql name="id" type="integer"/> </field> <field name="name" type="string" required="true"> <sql name="name" type="varchar"/> </field> </class>
  Normally, Castor would be looking for the Java bean methods
  getId() and
  setId() associated with the
  id
  property. The class author (me) prefers to capitalize both letters of
  ID when
  it occurs in method names. Because the capitalization is different from what
  Castor would expect, the method names must be given explicitly in the mapping
  file.
  A second way to bind a class property to a SQL table column is to access the class data member directly, rather than through methods. The data member must be public for this mechanism to work. To specify direct access, the following attribute of the field element is used:
  <class name="ShippingLine" identity="id"> <map-to <field name="_id"type="integer" key- <sql name="id" type="integer"/> </field> <field name="name" type="string" required="true"> <sql name="name" type="varchar"/> </field> </class>
  By accessing the data member directly in this way, you can reduce the
  number of public methods in the class definition. Notice that I've had to add
  the underscore character, since I'm now referring to the name of the data
  member directly, and it has an underscore in its name. The drawback to this
  mechanism is that, because of the need for a public data member, I
  consequently allow direct access by outside class methods in the application.
  In any case, you really don't have much protection from the wicked, but at
  least with public
  get/set methods you can deprecate their use where advisable
  through Javadoc comments.
  In Java, a class definition can extend another (base) class' definition through type-derivation. The new class will inherit all of the data members and methods of the base class, plus it might add a few of its own.
  In the case where only the extended class is stored in the database, the mapping file entry for that class will be the same as for any other class; however, if the base class is by itself persisted in the database already, then there will be an entry in the Castor mapping file for that class. It would be silly to have to copy all of those field mappings for the base class in the new mapping entry of the derived class. It would also be a maintenance worry: the derived class definition may change, and you'd wind up with two mapping entries to update.
  Better would be to store the new data members of the extended class in a
  new table in the database using a new mapping, and store the existing members
  of the base class in the table already set aside for it. Then Castor can
  perform a
  join operation between the two tables, generating a row that has
  all of the values of the data members (both inherited and new) for the extended
  class. Two joined table rows form one class instance.
  extendsAttribute
  A mapping for a class extends another class mapping through use of the
  extends attribute. Let's say I want to subtype the
  ship
  class so that there are cargo ships and passenger ships. I then have the
  following Java classes:
  public class Ship { String name; String registry; public Ship() { ... } //getters/setters... } public class CargoShip extends Ship { int cargoTonnage; public CargoShip() { ... } //getters/setters... } public class OilTanker extends Ship { int barrels; public OilTanker() { ... } //getters/setters... }
  To store these new classes, I can map them as follows:
  <class name="Ship" identity="registry name"> <map-to <field name="name" type="string" required="true"> <sql name="name" type="varchar"/> </field> <field name="registry" type="string" required="true"> <sql name="registry" type="varchar"/> </field> <!-- rest offields mapped here --> </class> <class name="CargoShip" extends="ship" identity="id" key- <description>Cargo is measured in net tonnage</description> <map-to <field name="id" type="integer"> <sql name="id" type="integer" /> </field> <field name="cargoTonnage" type="integer"> <sql name="cargo_tonnage" type="integer"/> </field> </class> <class name="OilTanker" extends="ship" identity="id" key- <description>Oil is measured in barrels</description> <map-to <field name="id" type="integer"> <sql name="id" type="integer" /> </field> <field name="barrels" type="integer"> <sql name="barrels" type="integer"/> </field> </class>
  Because new tables are required to store the additional data members of
  the extended classes, each extended class must have its own
  id, in addition to
  the identifying
  name/registry it already inherits from the base
  Ship class.
  If we were dealing only with Java classes, having these extra identifiers in
  the extended classes would be silly. But since we store the extended class
  data in two relational tables, each row in the second (extension) table must
  have a unique identifier; otherwise, the table would not be in First Normal
  Form (where each row must be distinct). The unique identifer in each row
  ensures that such is the case.
  There can be cases where you might not want to create a new database table for each class to be persisted. It's possible in Castor to store data from a parent object and its child in one table.
  The ships of the line, in addition to ferrying ubiquitous shipping containers across the seas, have to transport an odd-sized crate now and then. The dimensions of each crate are maintained in the database. The unit of measure of a dimension might be in either meters or feet.
  public class Dimension { public double measurement; public UOMType uom; } public class UOMType { private static String _feet = "ft"; private static String _meters = "m"; private String _unit; public static UOMType FEET = new UOMType( _feet ); public static UOMType METERS = new UOMType( _meters ); private UOMType( String type ) { _unit = type;} public void setUnit( String type ) {_unit = type; } public String getUnit() {return _unit;} }
  The last class maintains public instances that denote two types of
  measurement. Each
  Dimension instance will refer to one of
  these
  UOMType objects. Since
  UOMType is a separate class
  from
  Dimension, it would seem that
  I'd have to have two class descriptions in the Castor mapping file. That's
  overkill for the tiny
  UOMType class, with its single primitive value.
  An alternative approach is to store
  UOMType data in the same table that
  contains the
  Dimension rows. To accomplish this, I use a dot path in the
  class mapping for
  Dimension, like so:
  <mapping> <!-- Mapping for class Dimension --> <class name="Dimension" identity="id"> <map-to <field name="id" type="integer"> <sql name="id" type="integer"/> </field> <field name="measurement" type="double"> <sql name="measurement" type="decimal"/> </field> <field name="uom.unit" type="string"> <sql name="uom" type="varchar"/> </field> </class> </mapping>
  A dot path denotes data that is nested at a lower level in a container
  class than the class that is being mapped. By referring to nested data in
  this way, both the
  Dimension class data and the
  UOMType class data are stored
  in one table. With this approach, it's easy to look at the database row
  values and see what is being measured..
  The storing of class instances in the relational database is straightforward, thanks to the JDO mapping file and Castor's support of Object Query Language (OQL). OQL is a query language developed by the Object Database Management Group (ODMG), a consortium of object database vendors and users. OQL is a lot like SQL with objects thrown in.
  Unlike SQL, where a myriad of statements must be used to store even a simple Java object (and requiring an inate understanding by the programmer as to how each object is mapped to the various database tables), OQL can store entire hierarchies of objects in a single statement.
  Castor relies primarily on connection information in the database.xml file. To make the connection, first a JDO instance is created using a default constructor. The JDO is then configured with the database name to open and provide the location of the database.xml file. A database.xml file may contain connection information for more than one database, hence the need to specify a database name.
  Optionally, database log information can be sent to an output stream of your choosing. The log information is useful for debugging, since it records all SQL commands and return statuses that Castor sends to and receives from the database during transaction commits.
  package com.example.shipping; import org.exolab.castor.jdo.*; import java.io.PrintWriter; import java.io.ByteArrayOutputStream; class PersistenceFactory { private static String _databaseName = "shippingDB"; private static String _databaseConfiguration = "d:/shipping/database.xml"; public PersistenceFactory() throws PersistenceException { super(); _jdoLogWriter = new PrintWriter(new ByteArrayOutputStream(400)); open(); } private void open() throws PersistenceException { JDO jdo; // Define the JDO object jdo = new JDO(); jdo.setLogWriter(_jdoLogWriter); jdo.setDatabaseName(_databaseName); jdo.setConfiguration(_databaseConfiguration); // Obtain a new database _db = jdo.getDatabase(); } // other persistence methods... }
  The core of the connection procedure is highlighted above. Once the
  connection is made, all subsequent database transaction go through Castor's
  Database class instance.
  As mentioned earlier, Castor uses OQL to store and retrieve data from the database. OQL is an object-oriented extension of SQL, so it is possible to use SQL commands, although for object manipulation, it's not the preferred choice.
  Before doing anything with the database, you must first start a
  transaction using the
  begin() method of
  org.exolab.castor.jdo.Database.
  Changes are not made to the database until the transaction is committed using
  the
  commit() method. Both methods' calls are highlighted below:
  public void store(Object obj, boolean create) throws PersistStoreException { try { _db.begin(); if (create) { _db.create(obj); } else { _db.update(obj); } _db.commit(); } catch (ClassNotPersistenceCapableException ex) { throw new PersistStoreException(ex.toString()); } catch (DuplicateIdentityException ex) { throw new PersistStoreException(ex.toString()); } catch (TransactionNotInProgressException ex) { throw new PersistStoreException(ex.toString()); } catch (TransactionAbortedException ex) { throw new PersistStoreException(ex.toString()); } catch (PersistenceException ex) { throw new PersistStoreException(ex.toString()); } }
  Once a transaction is started, you may save a new object in the database
  or, if changes were made to an object previously fetched from the database
  (as it could have been from a prior transaction), you may "update" it. If the
  Database
  create() method is called, then an object with the same identifier
  must not already exist in the database, or an exception will occur. Updates,
  on the other hand, require that the object be in the database, inasmuch as it
  has the same identifier.
  Dependent objects are not created or updated directly, as you may recall. What counts is whether the master object exists previously in the database or not.
  In the code above, I've elected to collapse all of the possible exceptions
  that Castor can throw during the transaction into one exception that I've
  defined. I'm assuming that any exception that gets thrown here is essentially
  fatal, but another (more clever?) person might be able to program a recovery
  under certain circumstances. Also, while having
  the transaction
  begin/commit calls inside of this one method simplifies the
  storage and update of single objects, you would normally want to commit
  multiple objects at one time in a single transaction for better efficiency.
  In that case, you'd begin your transaction before the first object is stored
  and commit after the last object is stored.
  ShippingLineObjects
  OQL queries for fetching object data look very much like SQL queries, except that you don't get a row cursor returned (where each row then has to be manhandled into a class instance); instead, you receive a cursor to a list of fully-formed objects. Very nice.
  public Object fetch(String objName, String id) throws PersistFetchException { Object object = null; try { _db.begin(); Query oql; QueryResults results; oql = _db.getOQLQuery( "SELECT o" + " FROM com.example.shipping." + objName + " o" + " WHERE o.id=\"" + id + "\"" ); results = oql.execute(); while (results.hasMore() ) { object = results.next(); } _db.commit(); } catch ( TransactionAbortedException ex ) { throw new PersistFetchException( ex.toString() ); } catch ( TransactionNotInProgressException ex ) { throw new PersistFetchException( ex.toString() ); } catch ( PersistenceException ex ) { throw new PersistFetchException( ex.toString() ); } return object; }
  To fetch an object from the database, we first construct an OQL query
  using the
  getOQLQuery() method of
  org.exolab.castor.oql.Database. The query
  in this case might be:
  SELECT o FROM com.example.shipping.Ship o WHERE o.id="Waterdown"
  Once the query object is constructed, it can be executed. The results are
  returned in a
  QueryResults object. The
  QueryResults object
  functions as an array of
  Object instances. I'm assuming in this code that I have only one
  result (bad programmer am I). However, when I originally wrote this example,
  I called the undocumented
  results.size() method and checked for a value equal
  to 1. I was unpleasantly surprised to find that
  size() always returned 0! In
  this case, it's a safe assumption that I'm only going to get one object per
  identifier, but it's not very defensive coding.
  The returned object(s) can be cast to the expected class type by the caller.
  Castor JDO provides a lot of capability for simplifying the storage of Java data objects in relational tables. The use of a mapping file to direct the Castor JDO engine on how to store object member data to table rows and columns really reduces the amount of grunge code involved in query/update procedures. Mapping files maintain information about object dependencies and primary/foreign keys, also; the result is that you don't have to futz with such dependencies in either the application code or database schema.
  There are many additional features of Castor JDO that I was not able to cover in this article. A lot of these are not yet well-documented; however, there's usually some example code that you can download from the Castor Web site, either as a source repository snapshot (taken daily and for each release build) or by using WebCVS.
  As of this writing, Castor sits at pre-release version 0.9.3.21. A call for contributors recently went out on the the Castor mailing list, so if storing objects in databases is your kind of gig, you might check out the possibilities available in getting Castor 1.0 out the door. Hey, it just might save you a lot of work!
  Jeff Lowery is a JDO expert and advocate and is experienced at using Exolab's Castor, Jakarta Ant, and more.
  Return to ONJava.com.