blob: 9191835a41173f37960bae4a2ebcc9f3ed7ec0ca [file] [log] [blame]
<?xml version="1.0" encoding="ISO-8859-1"?>
<document>
<properties>
<title>OpenEJB CMP Mapping</title>
</properties>
<body>
<title>OpenEJB CMP Mapping</title>
<section title="Preface">
<p>
The OpenEJB CMP Container is no simple container. Unlike most CMP 1.1
containers, which simply generate BMP code for you and cannot handle
complex object-to-relational (O/R) mapping, the OpenEJB CMP Container
does all of that and more. It supports very complicated O/R mapping
and can map an entity bean across several tables and dependent objects.
It also supports the OMG's Object Query Language (OQL) which gives your
ejbFind methods added power.
</p>
<p>
All of this is done through the power of Castor JDO, a project that has been
developed since day one to be the most sophisticated CMP Container ever created.
Castor fulfills that role in spades and has become one of the most popular
object-to-relational and object-to-xml tools in the commercial or open source
world.
</p>
<p>This document details the full syntax of Castor's O/R mapping ability, it is
not for the weak of heart. For a simple introduction to OpenEJB CMP and the
related Castor mapping.xml files, see this wonderful doc written by Jacek Laskowski,
<a href="cmp_entity_postgresql.xml">CMP Hello World.</a>
</p>
<p>OpenEJB would like to thank the whole Castor team for their great work and to
<a href="mailto:ferret@frii.com">Bruce Snyder</a> for writing this very thorough
doc on the syntax of the mapping.xml file used for entity-to-relational mapping.
</p>
</section>
<section title="Introduction">
<p>
Castor mapping files are used by the OpenEJB CMP Container to provide a mechanism
for binding a Java object model (an EntityBean and it's Java objects) to a
relational database model. This is usually referred to as object-to-relational
mapping (O/R mapping). O/R mapping bridges the gap between an object model and a
relational model.
</p>
<p>
The following is a high-level example of a mapping file:
</p>
<code>
&lt;mapping>
&lt;class>
&lt;map-to />
&lt;field>
&lt;sql />
&lt;/field>
...
&lt;/class>
&lt;/mapping>
</code>
<p>
Each EntityBean and dependent Java object is represented by a &lt;class> element
composed of attributes, a &lt;map-to> element and &lt;field> elements. The &lt;map-to> element
contains a reference to the relational table to which the EntityBean maps.
Each &lt;field> element represents either a public class variable or a the
variable's accessor/mutator methods (depending upon the mapping info). Each
&lt;field> element is composed of attributes and one &lt;sql> element.
The &lt;sql> element represents the field in the relational table to which
the &lt;field> element maps.
</p>
</section>
<section title="The Mapping File">
<section title="The &lt;class> element ">
<code>
&lt;!ELEMENT class ( description?, cache-type?, map-to?, field+ )>
&lt;!ATTLIST class
name ID #REQUIRED
extends IDREF #IMPLIED
depends IDREF #IMPLIED
auto-complete ( true |false ) "false"
identity CDATA #IMPLIED
access ( read-only | shared | exclusive | db-locked ) "shared"
key-generator IDREF #IMPLIED >
</code>
<p>
The &lt;class> element contains all the information used to map a EntityBean
to a relational database. The content of &lt;class> is mainly used to describe
the fields that will be mapped.
</p>
<p>
Description of the attributes:
</p>
<ul>
<li><b>name:</b> The fully qualified package name of the EntityBean or dependent Java object to map to.</li>
<li><b>extends:</b> Should be used _only_ if this EntityBean or dependent Java object extends another Java
object for which mapping information is provided. It should _not_ be used if the
extended Java object is not referenced in the mapping file.</li>
<li><b>depends:</b> For more information on this field, please see
<a href="http://castor.exolab.org/castor-one.html#Dependent-and-related-relationships">
Dependent and related relationships</a>.</li>
<li><b>identity:</b> For more information on this field, please see
<a href="http://castor.exolab.org/design-persist.html#Persistence">Design -> Persistence</a>.</li>
<li><b>access:</b> For more information on this field, please see
<a href="http://castor.exolab.org/locking.html#Locking-Modes">Locking Modes</a>.</li>
<li><b>key-generator</b>: For more information on this field, please see
<a href="http://castor.exolab.org/key-generator.html">KeyGen</a>.</li>
</ul>
<p>Description of the elements:</p>
<ul>
<li><b>&lt;description></b>: An optional description.</li>
<li><b>&lt;cache-type></b>: For more information on this field please see
<a href="http://castor.exolab.org/long-transact.html#Bounded-dirty-checking">Bounded Dirty Checking</a>
and <a href="http://castor.exolab.org/castor-one.html#LRU-Cache">LRU Cache</a>.</li>
<li><b>&lt;map-to></b>: Used to tell the CMP Container the name of the relational
table to which to map.</li>
<li><b>&lt;field></b>: Zero or more &lt;field> elements are used to describe properties
of each EntityBean or dependent Java object.</li>
</ul>
</section>
<section title="The &lt;map-to> element">
<code>
&lt;!ELEMENT map-to EMPTY>
&lt;!ATTLIST map-to
table NMTOKEN #IMPLIED
xml NMTOKEN #IMPLIED
ns-uri NMTOKEN #IMPLIED
ns-prefix NMTOKEN #IMPLIED
ldap-dn NMTOKEN #IMPLIED
ldap-oc NMTOKEN #IMPLIED>
</code>
<p>&lt;map-to> is used to specify the name of the item that should be associated
with the given EntityBean or dependent Java object. The &lt;map-to> element is only used for the root
Java object.</p>
<p>Description of the attributes:</p>
<ul>
<li><b>table:</b> The name of the relational database table to which the
EntityBean or dependent Java object is associated.</li>
</ul>
</section>
<section title="The &lt;field> element">
<code>
&lt;!ELEMENT field ( description?, sql?, xml?, ldap? )>
&lt;!ATTLIST field
name NMTOKEN #REQUIRED
type NMTOKEN #IMPLIED
required ( true | false ) "false"
direct ( true | false ) "false"
lazy ( true | false ) "false"
transient ( true | false ) "false"
get-method NMTOKEN #IMPLIED
set-method NMTOKEN #IMPLIED
create-method NMTOKEN #IMPLIED
collection ( array | vector | hashtable | collection | set | map ) #IMPLIED>
</code>
<p>The &lt;field> element is used to describe a property of a EntityBean or dependent Java object. It provides:</p>
<ul>
<li>the object's identity ('name')</li>
<li>the object's type (inferred from 'type' and 'collection')</li>
<li>the object's access method (inferred from 'direct', 'get-method', 'set-method')</li>
</ul>
<p>From this information, the CMP Container is able to access a given property in the EntityBean or dependent Java
object.</p>
<p>In order to determine the signature that the CMP Container expects, there are two easy
rules to apply.</p>
<p><b>1. Determine &lt;type>.</b></p>
<ul>
<li><p><b>If there is no 'collection' attribute</b>, the object type is the the value
of the 'type' attribute. The value of the type attribute can be a fully qualified Java
object like 'java.lang.String' or one of the allowed aliases:</p>
<table border="1" cellpadding="4">
<tr><th>short name</th><th>Primitive type?</th><th>Java Class</th></tr>
<tr><td>other</td><td>N</td><td>java.lang.Object</td></tr>
<tr><td>string</td><td>N</td><td>java.lang.String</td></tr>
<tr><td>integer</td><td>Y</td><td>java.lang.Integer.TYPE</td></tr>
<tr><td>long</td><td>Y</td><td>java.lang.Long.TYPE</td></tr>
<tr><td>boolean</td><td>Y</td><td>java.lang.Boolean.TYPE</td></tr>
<tr><td>double</td><td>Y</td><td>java.lang.Double.TYPE</td></tr>
<tr><td>float</td><td>Y</td><td>java.lang.Float.TYPE</td></tr>
<tr><td>big-decimal</td><td>N</td><td>java.math.BigDecimal</td></tr>
<tr><td>byte</td><td>Y</td><td>java.lang.Byte.TYPE</td></tr>
<tr><td>date</td><td>N</td><td>java.util.Date</td></tr>
<tr><td>short</td><td>Y</td><td>java.lang.Short.TYPE</td></tr>
<tr><td>char</td><td>Y</td><td>java.lang.Character.TYPE</td></tr>
<tr><td>bytes</td><td>N</td><td>byte[]</td></tr>
<tr><td>chars</td><td>N</td><td>char[]</td></tr>
<tr><td>strings</td><td>N</td><td>String[]</td></tr>
<tr><td>locale</td><td>N</td><td>java.util.Locale</td></tr>
</table>
<p>the CMP Container will try to cast the data in the mapping file to the proper Java
type.</p></li>
<li><p><b>If there is a collection attribute</b>, the items in the following table can be
used:</p>
<table border="1" cellpadding="4">
<tr><th>name</th><th>type</th><th>default implementation</th></tr>
<tr><td>array</td><td>&lt;type_attribute>[]</td><td>&lt;type_attribute>[]</td></tr>
<tr><td>vector</td><td>java.util.Vector</td><td>java.util.Vector</td></tr>
<tr><td>hashtable</td><td>java.util.Hashtable</td><td>java.util.Hashtable</td></tr>
<tr><td>collection</td><td>java.util.Collection</td><td>java.util.Arraylist </td></tr>
<tr><td>arraylist</td><td>java.util.ArrayList</td><td>java.util.Arraylist </td></tr>
<tr><td>set</td><td>java.util.Set</td><td>java.util.Hashset</td></tr>
<tr><td>map</td><td>java.util.Map</td><td>java.util.Hashmap</td></tr>
</table>
<p>The type of the object inside the collection is the 'type' attribute. The 'default
implementation' is the type used if the object holding the collection is found
to be null and needs to be instantiated.</p>
<p>For hashtable and map, the CMP Container will add an object using the put(object, object)
method - the object is both the key and the value. This will be improved in the future.</p></li>
</ul>
<p>It is necessary to use a collection when the content model of the element expects more
than one element of the specified type. This is how the 'to-many' portion of a relationship
is described.</p>
<p><b>2. Determine the signature of the method</b></p>
<li><p><b>If 'direct' is set to true</b>, the CMP Container expects to find a public EntityBean or dependent Java
object variable with the given signature:</p>
<code>
public &lt;type> &lt;name>;
</code>
<li><p><b>If 'direct' is set to false or omitted</b>, the CMP Container will access the property
though accessor methods. the CMP Container determines the signature of the accessors and mutators
as follows: If the 'get-method' or 'set-method' attributes are supplied, it will
try to find a function with the following signature:</p>
<code>
public &lt;type> &lt;get-method>();
</code>
or
<code>
public void &lt;set-method>(&lt;type> value);
</code>
<p>If 'get-method' or 'set-method' attributes are not provided, the CMP Container will try to
find the following function:</p>
<code>
public &lt;type> get&lt;capitalized-name>();
</code>
or
<code>
public void set&lt;capitalized-name>(&lt;type> value);
</code>
<p>&lt;capitalized-name> means that the CMP Container uses the &lt;name> attribute by changing its first
letter to uppercase without modifying the other letters.</p>
<p>The content of the &lt;field> element will contain the information about how to map
this field to the relational table.</p>
</li>
</li>
<p>Description of the attributes: </p>
<ul>
<li><b>name:</b> If 'direct' access is used, 'name' should be the name of a public
variable in the object we are mapping (the field must be public, not
static and not transient). If no direct access and no 'get-/set-method'
is specified, this name will be used to infer the name of the accessor and
mutator methods.</li>
<li><b>type:</b> The Java type of the field. This is used to access the
field. The CMP Container will use this information to cast the data type(e.g. string
into integer). It is also used to define the signature of the accessor and
mutator methods. If a collection is specified, this is used to specify the
type of the object inside the collection. See description above for more
details.</li>
<li><b>required:</b> If true, the field is not optional.</li>
<!--
<li><b>transient:</b> If true, this field will be ignored during the
marshalling. This is usefull in when used with the auto-complete
option.</li>
-->
<li><b>direct:</b> If true, the CMP Container expects a public variable in the object
and will modify it directly.</li>
<li><b>collection:</b> If a parent object expects more than one occurrence of
one of its fields, it is necessary to specify which collection type the CMP Container will
use to handle them. The type specified is used to define the type of the
content inside the collection.</li>
<li><b>get-method:</b> An optional name of the accessor method the CMP Container should
use. If this attribute is not set, the CMP Container will try to guess the name with the
algorithm described above.</li>
<li><b>set-method:</b> An optional name of the mutator method the CMP Container should
use. If this attribute is not set, the CMP Container will try to guess the name with the
algorithm described above.</li>
<li><b>create-method:</b> Factory method for instantiation of the object.</li>
</ul>
</section>
<section title="The &lt;sql> element">
<p>
<code>
&lt;!ELEMENT sql EMPTY>
&lt;!ATTLIST sql
name NMTOKENS #IMPLIED
type NMTOKENS #IMPLIED
many-key NMTOKENS #IMPLIED
many-table NMTOKEN #IMPLIED
read-only ( true | false ) "false"
dirty ( check | ignore ) "check">
</code>
</p>
<p>
The &lt;sql> element is used to denote information about the relational
database table to which a EntityBean and dependent Java object is mapped.
It should be declared
for all &lt;field> elements. Each &lt;field> element contains one &lt;sql>
element. The &lt;sql> element pertains directly to the the &lt;map-to>
element for the containing &lt;class> element. The &lt;sql> elements
contains the following attributes:
<ul>
<li><b>name:</b> The column name in the relational database table.</li>
<li><b>type:</b> The column type in the relational database table.</li>
<li><b>many-key:</b> Specifies the name of the column that holds the
foreign key of the containing object. Used _only_ for 'to-many' relations.</li>
<li><b>many-table:</b> Specifies the name of the bridge table that contains
the primary keys of the object on each side of the relationship.</li>
<li><b>read-only:</b> If true, the column in the relational database
table will only be read, not updated or deleted.</li>
<li><b>dirty:</b> If the value is 'ignore', the field will not be checked
against the database for modification.</li>
</ul>
</p>
</section>
</section>
<section title="Usage Pattern">
<p>Here is an example of a mapping file and the corresponding EntityBean and dependent Java object and
DDL for the databse table.</p>
<p>The following is an example Java object:</p>
<table border="1" cellpadding="4">
<tr>
<td BGCOLOR="#CCCCCC">
<code>
package myapp;
public class Product implements javax.ejb.EntityBean
{
private int _id;
private String _name;
private float _price;
private ProductGroup _group;
public int getId()
...
public void setId( int anId )
...
public String getName()
...
public void setName( String aName )
...
public float getPrice()
...
public void setPrice( float aPrice )
...
public ProductGroup getProductGroup()
...
public void setProductGroup( ProductGroup aProductGroup )
...
}
</code>
</td>
</tr>
</table>
<p>The following is the relational database table:</p>
<table border="1" cellpadding="4">
<tr>
<td BGCOLOR="#CCCCCC">
<code>
create table prod
(
id int not null,
name varchar(200) not null,
price numeric(18,2) not null,
group_id int not null
);
</code>
</td>
</tr>
</table>
<p>The following is the mapping file for the example EntityBean:</p>
<table border="1" cellpadding="4">
<tr>
<td BGCOLOR="#CCCCCC">
<code>
&lt;?xml version="1.0"?>
&lt;!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD Version 1.0//EN"
"http://castor.exolab.org/mapping.dtd">
&lt;mapping>
&lt;class name="myapp.Product" identity="id">
&lt;map-to table="prod" />
&lt;field name="id" type="integer">
&lt;sql name="id" type="integer" />
&lt;/field>
&lt;field name="name" type="string">
&lt;sql name="name" type="char" />
&lt;/field>
&lt;field name="price" type="float">
&lt;sql name="price" type="numeric" />
&lt;/field>
&lt;field name="group" type="myapp.ProductGroup" >
&lt;sql name="group_id" />
&lt;/field>
&lt;/class>
&lt;/mapping>
</code>
</td>
</tr>
</table>
</section>
</body>
</document>