This documentation is for the XDoclet OJB module, version Juli 6, 2003.
A binary version of the XDoclet OJB module is part of OJB, however currently only in CVS. So, in order to use it, you have to checkout OJB from CVS. Refer to the instructions on the OJB site for details on how to do that.
Note: At the time of this writing, the OJB module source is not yet part of the XDoclet CVS, so the following steps cannot actually be performed.
Building the XDoclet OJB module from source is essentially building XDoclet from CVS. This process is extensivly documented on the xdoclet site: http://www.xdoclet.org/install.html. After xdoclet has been built, you find the jars of xdoclet and the modules in the ${xdoclet-all-dir}/xdoclet/target/lib
directory.
Using the xdoclet ojb module is rather easy. Put the module jar along with the xdoclet jar in a place where ant will find it, and then invoke it in your build file like:
<target name="repository-files"> <taskdef name="ojbdoclet" classname="xdoclet.modules.ojb.OjbDocletTask" classpathref="build-classpath"/> <ojbdoclet destdir="./build"> <fileset dir="./src"/> <ojbrepository destinationFile="repository_user.xml"/> <torqueschema databaseName="test" destinationFile="project_schema.xml"/> </ojbdoclet> </target>
The xdoclet ojb module has two sub tasks, ojbrepository
and torqueschema
, which generate the OJB repository part containing the user descriptors and the torque table schema, respectivly. They have only the shown options. The two filenames (repository_user.xml
and project_schema.xml
) are the default filenames which could have been omitted in the example.
The classpathref
attribute in the taskdef can be used to define the classpath for xdoclet (containing the xdoclet and ojb module jars), e.g. via:
<path id="build-classpath"> <fileset dir="lib/xdoclet"> <include name="**/*.jar"/> </fileset> </path>
Using the generated torque schema is a bit more tricky. The easiest way is to use the build-torque.xml
script which is part of OJB. Include the lib subdirectory of the OJB distribution which also includes torque (e.g. in build-classpath
as shown above). You will also want to use your OJB settings (build.properties, profile/${database}.profile), so include them at the beginning of the build script:
<property file="build.properties"/> <property file="mysql.profile"/>
Now you can create the database with the following ant calls:
<target name="init-db" depends="repository-files"> <ant dir="." antfile="build-torque.xml" target="project-sql-classpath"> <property name="schemaDirectory" value="."/> <property name="outputDirectory" value="build/db"/> </ant> <ant dir="." antfile="build-torque.xml" target="project-create-db-classpath"> <property name="schemaDirectory" value="."/> <property name="outputDirectory" value="build/db"/> </ant> <ant dir="." antfile="build-torque.xml" target="project-insert-sql"> <property name="schemaDirectory" value="."/> <property name="outputDirectory" value="build/db"/> </ant> </target>
As you can see, it is possible (and sometimes advisable) to override properties for the called tasks. In the example above, the property schemaDirectory
points to the directory containing the *-schema.xml
files, and outputDirectory
to the directory where torque will generate the SQL scripts and puts the log. If you need to manipulate the directory where the Torque build script searches for the libraries, then set the lib.dir
property to a directory containing the libraries. Due to limitations in the Torque build script, all libraries needed by it have to be in a single directory.
One important thing to note here is that the latter two calls modify the database and in the process remove any existing data, so use them with care. Similar to the above targets, you can use the additional targets project-datadump-classpath
for storing the database data in an XML file, and project-datasql-classpath
to inserting data from an XML file into the database.
Also, these steps are only valid for the torque that is delivered with OJB (which is version 3.0), but probably not for newer versions.
The ojb.class tag marks interfaces and classes that shall be present in the repository descriptor. This includes types that are used as reference targets or as collection elements, but for instance not abstract base classes not used elsewhere.
Attributes:
false
, no field, reference or collection descriptors are generated. The default is true
.true
, then the xdoclet ojb module will automatically determine all extents (ojb-relevant sub types) of this type. If set to false
, then extents need to be specified via the ojb.extent-class class tag (see below).The following class-descriptor
attributes are also supported in the ojb.class tag and will be written directly to the generated class descriptor (see repository.dtd
for their meaning):
Example: (from the unit tests)
/** * @ojb.class generate-table-info="false" */ public abstract class AbstractArticle implements InterfaceArticle, java.io.Serializable ... /** * @ojb.class table="Artikel" * proxy="dynamic" * include-inherited="true" * documentation="This is important documentation on the Article class." * attributes="color=blue,size=big" */ public class Article extends AbstractArticle implements InterfaceArticle, java.io.Serializable ...
The AbstractArticle
class will have an class descriptor in the repository file, but no field, reference or collection descriptors. The Article
class however will not only have descriptors for its own fields/references/collections but also for those inherited from AbstractArticle
. Also, its table definition in the torque file will be called "Artikel", not "Article". The resulting class descriptors look like:
<class-descriptor class="org.apache.ojb.broker.AbstractArticle" > <extent-class class-ref="org.apache.ojb.broker.Article"/> </class-descriptor> <class-descriptor class="org.apache.ojb.broker.Article" proxy="dynamic" table="Artikel" > <documentation>Some important documentation</documentation> ... <attribute attribute-name="color" attribute-value="blue"/> <attribute attribute-name="size" attribute-value="big"/> </class-descriptor> ...
Use the ojb.extent-class to explicitly specify extents (direct persistent sub types) of the current type. The class-ref attribute contains the fully qualified name of the class. However, these tags are only evaluated if the determine-extents attribute of the ojb.class tag is set to false
.
Attributes:
/** * @ojb.class determine-extents="false" * generate-table-info="false" * @ojb.extent-class class-ref="org.apache.ojb.broker.CdArticle" */ public abstract class AbstractCdArticle extends Article implements java.io.Serializable ...
which results in:
<class-descriptor class="org.apache.ojb.broker.AbstractCdArticle" > <extent-class class-ref="org.apache.ojb.broker.CdArticle"/> </class-descriptor>
Allows to modify attributes of inherited fields/references/collections (normally, all attributes are used without modifications) for this and all sub types.
Attributes: All of ojb.field, ojb.reference, and ojb.collection, and also:
/** * @ojb.class table="Artikel" * @ojb.modify-inherited name="productGroup" * proxy="true" * auto-update="true" */ public class ArticleWithReferenceProxy extends Article
produces the class descriptor
<class-descriptor class="org.apache.ojb.broker.ArticleWithReferenceProxy" table="Artikel" > ... <reference-descriptor name="productGroup" class-ref="org.apache.ojb.broker.ProductGroup" proxy="true" auto-update="true" > <documentation>this is the reference to an articles productgroup</documentation> <attribute attribute-name="color" attribute-value="red"/> <attribute attribute-name="size" attribute-value="tiny"/> <foreignkey field-ref="productGroupId"/> </reference-descriptor> </class-descriptor>
The ojb.index tag is used to define possibly unique indices for the class. An index consists of at least one field of the class (either locally defined or inherited, anonymous or explicit). Note that indices are not inherited.
Attributes:
* @ojb.class table="SITE" * @ojb.index name="NAME_UNIQUE" * unique="true" * fields="name" */ public class Site implements Serializable { /** * @ojb.field column="NAME" * length="100" */ private String name; ... }
the class descriptor
<class-descriptor class="org.apache.ojb.odmg.Site" table="SITE" > <field-descriptor name="name" column="NAME" jdbc-type="VARCHAR" length="100" > ... <index-descriptor name="NAME_UNIQUE" unique="true" > <index-column name="NAME"/> </index-descriptor> </class-descriptor>
and the torque table schema
<table name="SITE"> <column name="NAME" javaName="name" type="VARCHAR" size="100" /> ... <unique name="NAME_UNIQUE"> <unique-column name="NAME"/> </unique> </table>
Fields or accessor methods (i.e. get/is and set methods) for properties are marked with the ojb.field tag to denote a persistent field. When a method is marked, then the corresponding bean property is used for naming purposes (e.g. "value" for a method getValue()). The xdoclet ojb module ensures that a field is not present more than once, therefore it is safe to mark both fields and their accessors. However, in that case the three ojb.field tags are required to have the same attributes.
Marked fields are used for descriptor generation in the same type (if it has an ojb.class tag) and all base types with the ojb.class tag having the include-inherited attribute set to true
.
It is also possible to use the ojb.fieldtag at the class level (i.e. in the JavaDoc comment of the class). In this case, the tag is used to define an anonymous field, e.g. a "field" that has no counterpart in the class but exists in the database. In this case, the name attribute is required to specify the name of the field, and the access attribute is ignored (it defaults to the value anonymous
in this case).
Attributes:
Java type | JDBC type |
---|---|
boolean | BIT |
byte | TINYINT |
short | SMALLINT |
int | INTEGER |
long | INTEGER |
char | CHAR |
float | FLOAT |
double | DOUBLE |
java.lang.Boolean | BIT |
java.lang.Byte | TINYINT |
java.lang.Short | SMALLINT |
java.lang.Integer | INTEGER |
java.lang.Long | INTEGER |
java.lang.Character | CHAR |
java.lang.Float | FLOAT |
java.lang.Double | DOUBLE |
java.lang.String | VARCHAR |
java.util.Date | TIMESTAMP |
java.sql.Date | TIMESTAMP |
java.math.BigInteger | BIGINT |
java.math.BigDecimal | BIGINT |
org.apache.ojb.broker.util.GUID | VARCHAR |
LONGVARBINARY
using the Object2ByteArrFieldConversion
conversion (see conversion attribute below).org.apache.ojb.broker.accesslayer.conversions.Object2ByteArrFieldConversion
conversion class is used.Java type | Default conversion |
---|---|
java.util.Date | org.apache.ojb.broker.accesslayer.conversions.JavaDate2SqlTimestampFieldConversion |
org.apache.ojb.broker.util.GUID | org.apache.ojb.broker.accesslayer.conversions.GUID2StringFieldConversion |
Jdbc type | Default length |
---|---|
CHAR | 24 |
VARCHAR | 24 |
DECIMAL | 15,0 |
readonly
marks fields that are not to modified. readwrite
marks fields that may be read and written to. Anonymous fields do not have to be marked (i.e. anonymous
value) as the position of the ojb.field tag in the class JavaDoc comment suffices.Other attributes supported in the ojb.field tag that have the same meaning as in the repository descriptor (and partly in the torque table schema) are:
/** * @ojb.field column="Auslaufartikel" * jdbc-type="INTEGER" * conversion="org.apache.ojb.broker.accesslayer.conversions.Boolean2IntFieldConversion" * id="10" * attributes="color=green,size=small" */ protected boolean isSelloutArticle;
will result in the following field descriptor:
<field-descriptor name="isSelloutArticle" column="Auslaufartikel" jdbc-type="INTEGER" conversion="org.apache.ojb.broker.accesslayer.conversions.Boolean2IntFieldConversion" > <attribute attribute-name="color" attribute-value="green"/> <attribute attribute-name="size" attribute-value="small"/> </field-descriptor>
The column descriptor looks like:
<table name="Artikel"> ... <column name="Auslaufartikel" javaName="isSelloutArticle" type="INTEGER" /> ... </table>
An anonymous field is declared like this:
/** * @ojb.class table="TABLE_F" * include-inherited="false" * @ojb.field name="eID" * column="E_ID" * jdbc-type="INTEGER" * @ojb.reference name="super" * class-ref="org.apache.ojb.broker.E" * auto-retrieve="true" * auto-update="true" * auto-delete="true" * foreignkey="eID" */ public class F extends E implements Serializable ...
In this case an anonymous field is declared and also used as the foreignkey of an anonymous reference. The corresponding class descriptor looks like:
<class-descriptor class="org.apache.ojb.broker.F" table="TABLE_F" > <field-descriptor name="eID" column="E_ID" jdbc-type="INTEGER" access="anonymous" > </field-descriptor> ... <reference-descriptor name="super" class-ref="org.apache.ojb.broker.E" auto-retrieve="true" auto-update="true" auto-delete="true" > <foreignkey field-ref="eID"/> </reference-descriptor> </class-descriptor>
Similar to fields, references (java fields or accessor methods) are marked with the ojb.reference tag. We have a reference when the type of the java field is itself a persistent class (has an ojb.class tag) and therefore the java field represents an association. This means that the referenced type of an association (or the one specified by the class-ref attribute, see below) is required to be present in the repository descriptor (it has the ojb.class tag).
Foreign keys of references are also declared in the torque table schema (see example below).
OJB currently requires that the referenced type has at least one field used to implement the reference, usually some id of an integer type.
Anonymous references where there is no field in the class for the reference are also supported. Similar to anonymous fields, the ojb.reference tag for an anonymous reference is specified in the JavaDoc comment of the class, and the name and class-ref attributes are required. The foreignkeys of the reference can be anonymous fields.
Attributes:
Other supported attributes written directly to the repository descriptor file:
public abstract class AbstractArticle implements InterfaceArticle, java.io.Serializable { protected InterfaceProductGroup productGroup; /** * @ojb.reference class-ref="org.apache.ojb.broker.ProductGroup" * foreignkey="productGroupId" * documentation="this is the reference to an articles productgroup" * attributes="color=red,size=tiny" */ protected InterfaceProductGroup productGroup; /** * @ojb.field */ protected int productGroupId; ... }
Here the java type is InterfaceProductGroup
although the repository reference uses the sub type ProductGroup
. The generated reference descriptor looks like:
<field-descriptor name="productGroupId" column="Kategorie_Nr" jdbc-type="INTEGER" > </field-descriptor> <reference-descriptor name="productGroup" class-ref="org.apache.ojb.broker.ProductGroup" > <documentation>this is the reference to an articles productgroup</documentation> <attribute attribute-name="color" attribute-value="red"/> <attribute attribute-name="size" attribute-value="tiny"/> <foreignkey field-ref="productGroupId"/> </reference-descriptor>
In the torque table schema for the Article
class, the foreign key for the product group is explicitly declared:
<table name="Artikel"> ... <column name="Kategorie_Nr" javaName="productGroupId" type="INTEGER" /> ... <foreign-key foreignTable="Kategorien"> <reference local="Kategorie_Nr" foreign="Kategorie_Nr"/> </foreign-key> </table>
For an example of an anonymous reference, see the examples of ojb.field.
Persistent collections which implement 1:n or m:n associations are denoted by the ojb.collection tag. If the collection is an array, then the xdoclet ojb module can determine the element type automatically (analogous to references). Otherwise the type must be specified using the element-class-ref attribute. m:n associations are also supported (collections on both sides) via the indirection-table, foreignkey and remote-foreignkey attributes.
Attributes:
org.apache.ojb.broker.ManageableCollection
interface, and if so, generates the collection-class attribute automatically.ASC
or DESC
for ascending or descending, respectively) as a comma-separated list of name-value pairs. For instance, field1=DESC,field2,field3=ASC
specifies three fields after which to sort, the first one in descending order and the other two in ascending order (which is the default and can be omitted).The same attributes as for references are written directly to the repository descriptor file:
/** * @ojb.collection element-class-ref="org.apache.ojb.broker.Article" * foreignkey="productGroupId" * auto-retrieve="true" * auto-update="false" * auto-delete="true" * orderby="productGroupId=DESC" * @ojb.query-customizer class="org.apache.ojb.broker.accesslayer.QueryCustomizerDefaultImpl" * attributes="attr1=value1" */ private ArticleCollection allArticlesInGroup;
The corresponding collection descriptor is:
<collection-descriptor name="allArticlesInGroup" element-class-ref="org.apache.ojb.broker.Article" collection-class="org.apache.ojb.broker.ArticleCollection" auto-retrieve="true" auto-update="false" auto-delete="true" > <orderby name="productGroupId" sort="DESC"/> <inverse-foreignkey field-ref="productGroupId"/> <query-customizer class="org.apache.ojb.broker.accesslayer.QueryCustomizerDefaultImpl"> <attribute attribute-name="attr1" attribute-value="value1"/> </query-customizer> </collection-descriptor>
An m:n collection is defined using the indirection-table attribute:
/** * @ojb.class generate-table-info="false" */ public abstract class BaseContentImpl implements Content { /** * @ojb.collection element-class-ref="org.apache.ojb.broker.Qualifier" * auto-retrieve="true" * auto-update="false" * auto-delete="false" * indirection-table="CONTENT_QUALIFIER" * foreignkey="CONTENT_ID" * remote-foreignkey="QUALIFIER_ID" */ private List qualifiers; ... } /** * @ojb.class table="NEWS" */ public class News extends BaseContentImpl { ... } /** * @ojb.class generate-table-info="false" */ public interface Qualifier extends Serializable { ... }
The BaseContentImpl
has a m:n association to the Qualifier
interface. For the BaseContentImpl
class, this association is implemented via the CONTENT_ID
column (specified by the foreignkey) in the indirection table CONTENT_QUALIFIER
. Usually, both ends of an m:n association have a collection implementing the association, and for both ends the foreignkey specifies the indirection table column pointing to the class at this end. The Qualifier
interface however does not contain a collection which could be used to determine the indirection table column that implements the association from its side. So, this column is also specified in the BaseContentImpl
class using the remote-foreignkey attribute. The class descriptors are
<class-descriptor class="org.apache.ojb.broker.BaseContentImpl" > <extent-class class-ref="org.apache.ojb.broker.News"/> </class-descriptor> <class-descriptor class="org.apache.ojb.broker.News" table="NEWS" > ... <collection-descriptor name="qualifiers" element-class-ref="org.apache.ojb.broker.Qualifier" indirection-table="CONTENT_QUALIFIER" auto-retrieve="true" auto-update="false" auto-delete="false" > <fk-pointing-to-this-class column="CONTENT_ID"/> <fk-pointing-to-element-class column="QUALIFIER_ID"/> </collection-descriptor> </class-descriptor>> <class-descriptor class="org.apache.ojb.broker.Qualifier" > <extent-class class-ref="org.apache.ojb.broker.BaseQualifierImpl"/> </class-descriptor>
As can be seen, the collection definition is inherited in the News
class and the two indirection table columns pointing to the ends of the m:n associaton are correctly specified.
Specifies a query customizer for the collection. The type is required to implement org.apache.ojb.broker.accesslayer.QueryCustomizer
Attributes: