ExoLab     OpenEJB     OpenJMS     OpenORB     Castor     Tyrex     
 

Main
  Home
  Download
  API
  Schema
  Mailing Lists
  CVS / Bugzilla
  Support

XML
  Using XML
  Source Generator
  Schema Support
  XML Mapping
  XML FAQ

JDO
  Using JDO
  JDO Config
  Types
  JDO Mapping
  JDO FAQ
  Other Features

Advanced JDO
  OQL
  Trans. & Locks
  Design
  KeyGen
  Long Trans.
  Nested Attrs.
  Pooling Examples
  Blobs and PostgreSQL

More
  Presentations
  The Examples
  Extras and 3rd Party Tools
  Test Framework -- JDO
  Test Framework -- XML
  Configuration
  Tips & Tricks
  Full JavaDoc

About
  License
  Contributors
  Status, Todo
  Changelog
  Library
  Contact

  



Reference: The Java Data Objects API

What is in Castor JDO 0.9
LRU Cache
Dependent and related relationships
Different cardinalities of relationship
Lazy Loading
Mutliple columns primany keys

What is in Castor JDO 0.9

Castor JDO is transactional. Data objects loaded in Castor are properly locked and isolated from other transactions. Castor supports full 2-phase commit via xa.Synchronzation. Castor supports several locking modes, including "shared", "exclusive", "database locked", and "read-only".

-Shared access, the default, is useful for situations in which it is common for two or more transactions to read the same objects, and/or update different objects.
-Exclusive access uses in-memory locks implemented by Castor to force competing transactions to serialize access to an object. This is useful for applications in which it is common for more than one transaction to attempt to update the same object, and for which most, if not all access to the database is performed through Castor.
-Database-Locked access is often used for applications in which exclusive locking is required, but in which the database is frequently accessed from applications outside of Castor, bypassing Castor's memory-based locking mechanism used by "exclusive access" locking.
-Read-Only access performs no locking at all. Objects read using this access mode are not locked, and those objects do not participate in transaction commit/rollback.

In addition, Castor supports "long transactions", whichs allow objects to be read in one transaction, modified, and then committed in a second transaction, with built-in dirty-checking to prevent data that has been changed since the initial transaction from being overwritten.

Through automatic dirty-checking and deadlock detection, Castor can be used to ensure data integrity and reduce unnecessary database updates. A subset of OQL, defined in the Object Management Group (OMG) 3.0 Object Query Language Specification, is supported for interacting with the database. OQL is similar to SQL, though operations are performed directly on Java objects instead of database tables, making the language more appropriate for use within a Java-based application. Castor implements a data cache to reduce database accesses, providing several alternative LRU-based caching strategies.

Castor supports different cardinalities of relationship, including one-to-one, one-to-many and many-to-many. It also supports both object and database record inheritance. It distinguishes between related (i.e. association) and dependent (i.e. aggregation) relationships during an object's life cycle, automatically creating and deleting dependent objects at appropriate times in the independent object's life cycle. Multiple-column primary keys, and a variety of key generators are supported.

Castor automatically manages persistence for objects that contain Java collection types, including Vector, Hashtable, Collection, Set, and Map. Lazy loading of collections is implemented to reduce unnecessary database loading. Lazy loading can be turned on or off for each individual field of any supported collection type.

Other features include a type converter for all Java primitive types (see the info on supportedtypes).

No pre-processor (aka pre-compiler), class enhancer (bytecodes modification) is needed or used for data-binding and object persistence.

Castor JDO works in an application that uses multiple ClassLoaders, making it possible to use in an EJB container or servlet, for example. A Castor-defined callback interface, "Persistent", can be implemented if the objects wants to be notified on Castor events: jdoLoad(), jdoCreate(), jdoRemove() and jdoTransient(). This makes it possible to create user-defined actions to take at various times in an object's life cycle.

The Java-XML Data-Binding Framework (Castor XML) has been merged with Castor JDO for users who need both O/R Mapping and Java-XML Data-Binding together.

The following relational databases are supported:

-DB2
-Generic DBMS
-Hypersonic SQL
-Informix
-InstantDB
-Interbase
-MySQL
-Oracle
-PostgreSQL
-SAP DB
-SQLServer
-Sybase

Database support includes Oracle 8.1.x and different versions of Sybase Enterprise and Anywhere. Users can implement the Driver interface to adapt Castor to the differences in SQL syntax supported by different relational DBMS', as long as the DBMS supports JDBC 2.0, multiple ResultSet, and transactions. Thanks to many individual open source contributors, drivers for different database are available. [Links for all features will be added]

LRU Cache

Castor maintains and properly locks one copy of the dirty checking cache for each object it loads from or creates into persistence storage. Until all transactions involving the object are completed (See Design: Persistence), the cache is released. Starting from Castor 0.8.6, performance cache is implemented and developer can specify the mechanism and capacity of performance cache for each persistence capable type. Options includes none, count-limited, time-limited and unlimited. Performance cache is write-through, because all changes to objects of a transaction should be persisted at commit time without delay.

Performance cache options do not affect the behavior of short transactions or locking. Nor do the options affect the dirty checking cache, because they?re maintained separately. It only affects persistence object that is freed from any transaction. Performance cache enhances the performance by reducing the number of read operations done to persistence storage, by using the last read or committed values of the object.

Performance cache is also serves a dual purpose as dirty checking cache for long transactions. The object's duration in the performance cache determines the allowed time span of a long transaction. ObjectModifedException will be thrown if an application trys to update an object that is disposed from performance cache. See long-transactions for details.

The DTD declaration is as the following:

<!ATTLIST cache-type
    type ( none | count-limited
          | time-limited | unlimited ) "count-limited"
    capacity NMTOKEN #IMPLIED>
            

For example,

<mapping>
    <class name="com.xyz.MyObject">
        <cache-type type="time-limited" capacity="30"/>
        <field name= ... >
               ...
        </field>
    </class>
</mapping>
            
defines the time-limited least-recently-used algorithm as the caching algorithm for com.xyz.MyObject class and the cache will be disposed of if it is not used within 30 seconds. (Note that the time-limit ticks after all transaction involved with the objects complete, but not start after it is loaded.)

NOTE: The default cache-type is count-limited with a capacity of 100. This will be used when no cache-type is specified in the mapping for a class.

Dependent and related relationships

Castor distinguishes the relationship of two objects as dependent or related, and maintains the life cycle independently for the two types of relationships. Starting from Castor 0.9, the developer can explicitly define a dependent relationship in the mapping file.

When using independent relations, related objects? life cycle is independent of each other, meaning that they have to be created, removed and updated (for long transaction) independently.

When using dependent relations, one data object class must be declared as depends on one other data object class in the mapping file, and such an object is called a dependent data object class. A data object class without depends declared in the mapping is called a master object. A master object can be depended upon by zero or more dependent data object class.

As of Castor 0.9, a dependent object class can be related to other master data object classes including extended classes, but cannot depend on more than one master class.

If an object class declared as depends on another class, it may not be created, removed or updated separately. Attempting to create, remove or update a dependent object will result in ObjectNotPersistcapableException. Note that Castor doesn?t allow a dependent object instance to change its master object instance during a transaction. Each dependent object can have only one master object. Both dependent and master objects must have identities, and may or may not make use of key-generators.

Here is the DTD for declaring dependent object:

<!ATTLIST class     name ID  #REQUIRED
             extends   IDREF    #IMPLIED
             depends   IDREF    #IMPLIED
             identity  CDATA   #IMPLIED
             access    ( read-only | shared | exclusive
                        | db-locked )  "shared"
             key-generator   IDREF #IMPLIED
             

For example,

<mapping>
    <class name="com.xyz.MyDependentObject"
        depends="com.xyz.MyObject">
        ...
    </class>
</mapping>
                
declares the data object class com.xyz.MyDependentObject as a dependent upon class com.xyz.MyObject.

Different cardinalities of relationship

Castor supports different cardinalities of relationship, namely one-to-one, one-to-many, and many-to-many. Many-to-many is new to Castor 0.9. Many-to-many relationship must be related rather than dependent, because each dependent object can have only one master object.

Many-to-many requires a separate table for storing the relations between two types of objects. Many-to-many introduces two attributes, namely many-key and many-table that reside in the <sql> element which is a sub-element of the <field> element. For all many-to-many relations, a many-table must be specified. If the column name of the primary key of the class is different from the foreign keys columns of the class in the relation tables, then the relation table columns can be specified using the many-key attributes. Similarly, if the column name of the primary key of the related class is different from the foreign key columns of the related class, then the relation table columns can be specified using the name attribute.

The many-table is used to store relations in a separate table

<mapping>
    <class>
        <field>
            <sql many-key="#OPTIONAL" name="#OPTIONAL"
                 many-table="#REQURIED">
        </field>
    </class>
</mapping>
               

So, for example, if the SQL table is the following,

employee_table
id name salary
1482 Smith, Bob $123,456
628 Lee, John $43,210
1926 Arnold, Pascal $24,680
department_table
id name comment
3 Accounting
7 Engineering The very important department. :-)
employee_department
e_id d_id
.... ....

Then, the mapping for employee data object would look like this

<mapping>
    <class name="com.xyz.Employee" identity="id">
        <map-to table="employee_table"/>
            <field name="id" type="integer">
                <sql name="id"/>
            </field>
            <field>
                <sql many-table="employee_department"
                     many-key="e_id" name="d_id"/>
            </field>
            <field name="salary">
                <sql name="salary" type="integer">
            </field>
    </class>
</mapping>
                

Lazy Loading

Lazy loading of collection is also a new to castor 0.9. The following collection types are supported: java.util.Array, java.util.Vector, java.util.Hashtable, java.util.Collection, java.util.Set and java.util.Map. The elements in the collection are only loaded when the application asks for the object from the collection, using, for example, iterator.next(). The iterator in castor?s lazy collection is optimized to return a loaded object first. Lazy loading can be applied to both one-to-many and many-to-many relationship.

In mapping file, lazy loading is specified in the element of the collection?s <field>, for example,

<mapping>
    <class name="com.xzy.Department">
       ...
        <field name="com.xyz.Employee" lazy="true"
               collection="collection"/>
    </class>
</mapping>
declares that the collection of employee in a department is lazy loaded.

If lazy loading is specified for a field of a class, Castor will set the field with a special collection which contains only the identities of the objects. Because of that, it requires the data object to have the method setDepartment( Collection department ) in the data object class which was not required in previous versions.

Mutliple columns primany keys

The support of multiple column primary keys (also called compound primary keys) was another major enhancement added into Castor 0.9. Specifying multiple column primary keys is simple and straightforward, in the mapping file,

<mapping>
    <class name="com.xyz.MyObject" identity="firstName lastName">
        <field name="firstName" type="string">
           <sql name="fname"/>
        </field>
        <field name="lastName" type="string">
           <sql name="lname"/>
        </field>
           ...
    </class>
</mapping>
            

Multiple column primary keys work with both master and dependent objects, all cardinalities of relationship, including one-to-one, one-to-many and many-to-many, as well as lazy loading.

However, multiple column primary keys should only be used to adhere to an existing database design, not when designing a new database. In general, it is not a good idea to use an identity or identities which can be modified by the user, or which contain application-visible data. For example, if the system allows the user name to be changed, using user name as identity is highly discouraged, as this practice can require a major data migration to a new schema to update all foreign keys to adhere to a new primary key structure, should the user name no longer be adequate as a primary key. It should be noted that Castor doesn?t support identity change, as specified in the ODMG 3.0 specification. So, primary keys changes are almost certainly a large trade off between data integrity and performance. Well chosen primary keys are usually single (not multiple) column numeric or character fields for the reasons outlined above, as well as performance, as joining operations are faster for single column primary keys.

 
   
  
   
 


Copyright ) 1999-2003 ExoLab Group. All rights reserved.
 
Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners.