Index: doc/src/docbkx/reference/jdo/jdo-database-conf.xml =================================================================== --- doc/src/docbkx/reference/jdo/jdo-database-conf.xml (revision 0) +++ doc/src/docbkx/reference/jdo/jdo-database-conf.xml (revision 0) @@ -0,0 +1,670 @@ + + +
+ Castor JDO - Configuration + + + Castor JDO allows for two simple ways of specifying its required configuration, e.g. + by the means of supplying Castor JDO with an XML-based configuration file, and by + specifying its configuration programmatically via the + org.exoalb.castor.util.jdo.JDOConfFactory class. + + +
+ The Castor configuration file + + + The default way to configure how Castor interacts with a specific database system + is by using a configuration file. It specifies the means to obtain a connection + to the database server, the mapping between Java classes and tables + in that database server, and the service provider to use for talking + to that server (For a more flexible, programmatic way without configuration files see + section JDOConfFactory). + + + The application will access the database(s) by its given name + (database/name) and will be able to persist all objects specified + in the included mapping file(s). + + + + The engine attribute specifies the persistence engine for this + database server. Different database servers vary in the SQL syntax and + capabilites they support, and this attribute names the service provider to use. + + + The following names are supported in Castor: + + + + + + engine name + RDBMS + + + + + db2 + DB/2 + + + derby + Derby + + + generic + Generic JDBC support + + + hsql + Hypersonic SQL + + + informix + Informix + + + instantdb + InstantDB + + + interbase + Interbase + + + mysql + MySQL + + + oracle + Oracle 7 - Oracle 9i + + + postgresql + PostgreSQL 7.1 + + + sapdb + SAP DB / MaxDB + + + sql-server + Microsoft SQL Server + + + sybase + Sybase 11 + + + pointbase + Borland Pointbase + + + progress + Progress RDBMS + + + + + + + + Castor doesn't work with JDBC-ODBC bridge from Sun. + In particular, MS Access is not supported. + + + + + The means to acquire a database connection is specified in one of three + ways: as a JDBC driver URL, as a JDBC DataSource, or as a DataSource + to lookup through JNDI. When Castor is used inside a J2EE application server + it is recommended to use JNDI lookup (see the jndi element), + allowing the application server to manage connection pooling and distributed + transactions. + + + + The class mapping is included from an external mapping file, allowing + multiple mappings to be included in the same database configuration, or two + databases to share the same mappings. For concurrency and integrity reasons, + two database configurations should never attempt to use overlapping mappings. + It is recommended to use one database configuration per database server. + + + + The mapping file is specified using a URL, typically a file: URL. + If the database configuration file and mapping file reside in the same + directory, use a relative URL. Relative URLs also work if the database + configuration and mapping files are obtained from the application JAR and + reside in the same classpath. + + + + The driver element specifies the JDBC driver for obtaining + new connections to the database server. The driver is obtained from the JDBC + DriverManager and must be located in the class path. The JDBC URL + locates the driver and provides the access properties. Additional properties + may be specified using param elements (e.g. buffer size, network + protocol, etc). + + + + Use the class-name attribute to specify the driver class for + automatic registration with the JDBC DriverManager. If missing, + the driver must be registered in any other means, including properties file, + Class.forName(), etc. + + + + For example, to configure an Oracle 8 thin driver, use: + + + + + + + ... + + ... + ]]> + + + + The data-source element specifies the JDBC DataSource for + obtaining new connections to the database server. DataSources are defined + in the JDBC 2.0 standard extension API which is included with Castor, and + implement the interface javax.sql.DataSource. + + + + The DataSource implementation class name is specified by the + class-name attribute and configured through Bean-like accessor + methods specified for the param element. + The DTD for the param element is undefined + and depends on the DataSource being used. + + + + For example, to configure a PostgreSQL 7.1 DataSource, use: + + + + + + + + + + ... + + ... + ]]> + + + + The jndi element specifies the JDBC DataSource for obtaining + new connections to the database server through a JNDI lookup. The JNDI environment + naming context (ENC) is used to obtain a suitable DataSource.. + + + + When running inside a J2EE application server, this is the preferred method + for obtaining database connections. It enables the J2EE application server to + configure the connection, maintain a connection pool, and manage distributed + transactions. + + + + For example, to specify a J2EE DataSource, use: + + + + + ... + ]]> + + +
+ Transaction demarcation + + + As opposed to release pre 0.9.6, transaction demarcation is now configured + in the JDO configuration file. As such, the user has to specify which transaction + demarcation to use. Transactions when used with Castor JDO can either be + local or global, + and you instruct Castor to use a specific mode by supplying + a <transaction-demarcation> element. + + +
+ Local Mode + + + When using Castor JDO stand-alone and you want Castor to control + transaction demarcation, please use the + <transaction-demarcation> element as follows: + + + +]]> + + +
+ +
+ Global Mode + + + When running inside a J2EE application server, and you want to use + global (XA) transactions, please make use the + <transaction-demarcation> element as follows: + + + + +]]> + + + + In this mode, the <transaction-manager> + element specifies the transaction manager that is used by your + J2EE container to control these transactions. + + + The following transaction managers are supported in Castor: + + + + + + NameDescription + + + + + jndiTM looked up in the JNDI ENC + + + websphereIBM WebSphere 4 and previous releases + + + websphere5IBM WebSphere 5 + + + websphere51IBM WebSphere 5.1 + + + jotmJOTM + + + atomikosAtomikos + + + + + + + In addition to specifying the transaction manager name, it is possible + to pass arbitrary name/value pairs to the transaction manager instance. + + + + Note: At the moment, only the JNDI + transaction manager factory supports such an attribute. In this context, + the jndiEnc attribute can be used to specify what JNDI ENC to use to + lookup the transaction manager as shown below: + + + + + + + ]]> + +
+ +
+ +
+ Sample Configuration File + + + The following configuration file instructs Castor JDO to execute against + an Oracle RDBMS using the thin (type 4) JDBC driver, and refers to + three mapping files that define mappings for product, order and customer related + data. + + + + + + + + + + + + + + + ]]> + + + The following configuration file uses a connection obtained from the + J2EE application server and a single mapping file: + + + + + + + + + + + + ]]> + + +
+ +
+ Prepared statement pooling + + + Castor JDO uses JDBC prepared statements + to execute SQL statements against the specified RDBMS of your choice. + Per definition, Castor JDO does not + provide any prepared statement pooling. As such, Castor relies on prepared + statement pooling being provided by different means. + + + + One such way is to use + Jakarta's Commons DBCP + as database connection pool, and to turn prepared statement pooling on by + configuring DBCP accordingly. + + + + Please check with Using Pooled Database Connections + for general information about hot to use DBCP with Castor. + + +
+ +
+ Sample configurations for various databases + + + Besides the examples listed above, more configuraton examples can be found in the + configuration files for the Castor JDO tests, which can be found in + src/tests/jdo once you have downloaded and expanded the Castor + source package. For each database (vendor) supported, you are going to find a + database-specific JDO configuration file in this directory, e.g. + src/tests/jdo/mysql.xml for + mySQL or + src/tests/jdo/oracle.xml + for Oracle. + + + +
+ Sybase JConnect (JDBC data source) + + + + + + + + + ...]]> + +
+ +
+ PostgreSQL (JDBC data source) + + + + + + + + + + ...]]> + +
+ +
+ Oracle (JDBC Driver) + + + + + + + ...]]> + +
+ +
+ mySQL (JDBC Driver) + + + + + + + ...]]> + +
+ +
+ InstantDB + + + + + + + ...]]> + +
+ +
+ + +
+ +
+ JDOConfFactory - A programmatic way of configuring Castor JDO + + + Many applications need to connect to a database using varying + user accounts or database instances. To accomplish this, the utility class + org.exolab.castor.jdo.util.JDOConfFactory">JDOConfFactory + and a + JDOManager.loadConfiguration(org.exolab.castor.jdo.conf.JdoConf) + method has been added to Castor. + + + + The following code snippet shows an example how to create a JDO configuration without + the use of a default XML-based database configuration file: + + + + private static final String DRIVER = "oracle.jdbc.driver.OracleDriver"; + private static final String CONNECT = "jdbc:oracle:thin:localhost:1521:SID"; + private static final String USERNAME = "scott"; + private static final String PASSWORD = "tiger"; + private static final String MAPPING = "mapping.xml"; + private static final String DATABASE = "mydb"; + private static final String ENGINE = "oracle"; + + // create driver configuration + org.castor.jdo.conf.Driver driverConf = + JDOConfFactory.createDriver(DRIVER, CONNECT, USERNAME, PASSWORD); + + // create mapping configuration + org.castor.jdo.conf.Mapping mappingConf = + JDOConfFactory.createMapping(getClass().getResource(MAPPING).toString()); + + // create database configuration + org.castor.jdo.conf.Database dbConf = + JDOConfFactory.createDatabase(DATABASE, ENGINE, driverConf, mappingConf); + + // create and load jdo configuration + JDOManager.loadConfiguration(JDOConfFactory.createJdoConf(dbConf)); + + // Construct a new JDOManager for the database + jdoManager = JDOManager.createInstance(DATABASE); + + // Obtain a new database + Database db = jdoManager.getDatabase(); + + + + As an alternative to using a org.exolab.castor.jdo.conf.Driver, + you can also configure Castor to use a JDBC 2.0 DataSource: + + + + private static final String DS = "oracle.jdbc.pool.OracleConnectionCacheImpl"; + private static final String CONNECT = "jdbc:oracle:thin:localhost:1521:SID"; + private static final String USERNAME = "scott"; + private static final String PASSWORD = "tiger"; + private static final String MAPPING = "mapping.xml"; + private static final String DATABASE = "mydb"; + private static final String ENGINE = "oracle"; + + // setup properties for datasource configuration + Properties props = new Properties(); + props.put("URL", CONNECT); + props.put("user", USERNAME); + props.put("password", PASSWORD); + + // create datasource configuration + org.castor.jdo.conf.DataSource dsConf = + JDOConfFactory.createDataSource(DS, props); + + // create mapping configuration + org.castor.jdo.conf.Mapping mappingConf = + JDOConfFactory.createMapping(getClass().getResource(MAPPING).toString()); + + // create database configuration + org.castor.jdo.conf.Database dbConf = + JDOConfFactory.createDatabase(DATABASE, ENGINE, dsConf, mappingConf); + + // create and load jdo configuration + JDOManager.loadConfiguration(JDOConfFactory.createJdoConf(dbConf)); + + // Construct a new JDOManager for the database + jdoManager = JDOManager.createInstance(DATABASE); + + // Obtain a new database + Database db = jdoManager.getDatabase(); + + +
+ +
+ References + +
+ The JDO Configuration DTD + + + For validation, the configuration file should include the following + document type definition. For DTD validation use: + + ]]> + For XML Schema validation use: + + ]]> + The Castor namespace URI is http://castor.org/. + + + + The Castor JDO database configuration DTD is: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + +
+ +
+ +
Index: doc/src/docbkx/reference/jdo/jdo-examples.xml =================================================================== --- doc/src/docbkx/reference/jdo/jdo-examples.xml (revision 0) +++ doc/src/docbkx/reference/jdo/jdo-examples.xml (revision 0) @@ -0,0 +1,582 @@ + + +
+ Castor JDO code samples + + + +
+ Introduction + + + This document provides object mapping examples and the corresponding + Java objects and DDL for the database table. + + +
+ Java class files + + + The following fragment shows the Java class declaration for the + Product class: + + + +package myapp; + +public class Product { + + 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 ) { ... } +} + + + The following fragment shows the Java class declaration for the + ProductGroup class: + + + +public class ProductGroup { + + private int _id; + + private String _name; + + public int getId() { ... } + + public void setId( int id ) { ... } + + public String getName() { ... } + + public void setName( String name ) { ... } + +} +
+ +
+ DDL + + + The following sections show the DDL for the relational database + tables PROD, PROD_GROUP, + and PROD_DETAIL: + + + + PROD: + + + +create table prod ( + id int not null, + name varchar(200) not null, + price numeric(18,2) not null, + group_id int not null +); + + + PROD_GROUP: + + + +create table prod_group ( + id int not null, + name varchar(200) not null +); + + + PROD_DETAIL: + + + +create table prod_detail ( + id int not null, + prod_id int not null, + name varchar(200) not null +); +
+ +
+ Object Mappings + + + The following code fragment shows the object mapping for the + ProductGroup class: + + + +<?xml version="1.0"?> +<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD Version 1.0//EN" + "http://castor.org/mapping.dtd"> +<mapping> + + <class name="myapp.ProductGroup" identity="id"> + + <description>Product group</description> + + <map-to table="prod_group" xml="group" /> + + <field name="id" type="integer" > + <sql name="id" type="integer"/> + </field> + + <field name="name" type="string"> + <sql name="name" type="char" /> + </field> + + </class> + +</mapping> + + + As a result of that declaration, Castor JDO will create the following + SQL statements for creating, deleting, loading and updating instances + of ProductGroup: + + + +create: INSERT INTO prod_group (id, name) VALUES (?,?) +delete: DELETE FROM prod_group WHERE id=? +load: SELECT prod_group.id, prod_group.name FROM prod_group WHERE prod_group.id=?; +update: UPDATE prod_group SET name=? WHERE id=? + + +
+ Read-only fields + + + To declare the name field + read-only, the field definition + above for the field name needs + to be changed to: + + + + <class name="myapp.ProductGroup" identity="id"> + + ... + <field name="name" type="string"> + <sql name="name" type="char" read-only="true" /> + </field> + + </class> + + + As a result of that declaration, Castor JDO creates the following + SQL statements for creating, deleting, loading and updating + instances of ProductGroup: + + + +create: INSERT INTO prod_group (id) VALUES (?) +delete: DELETE FROM prod_group WHERE id=? +load: SELECT prod_group.id, prod_group.name FROM prod_group WHERE prod_group.id=?; +update: no statement will be generated +
+ +
+ Transient fields + + + To declare the name field + transient with regards to + persistence, above field definition for the field + name needs to be changed to: + + + + <class name="myapp.ProductGroup" identity="id"> + + ... + <field name="name" type="string" > + <sql name="name" type="char" transient="true" /> + </field> + + </class> +
+
+ +
+ Relations + +
+ 1:1 relation + + + The following code fragment shows the mapping file for the Product + class. Apart from the simple field declarations, this includes a + simple 1:1 relation between Product and + ProductGroup, where every product instance + is associated with a ProductGroup: + + + + <class name="myapp.Product" identity="id"> + + <map-to table="prod" /> + + <field name="id" type="integer"> + <sql name="id" type="integer" /> + </field> + + <field name="name" type="string"> + <sql name="name" type="char" /> + </field> + + <field name="price" type="float"> + <sql name="price" type="numeric" /> + </field> + + <field name="group" type="myapp.ProductGroup" > + <sql name="group_id" /> + </field> + + <field name="details" type="myapp.ProductDetail" + collection="vector"> + <sql many-key="prod_id"/> + </field> + + <field name="categories" type="myapp.Category" collection="vector"> + <sql name="category_id" + many-table="category_prod" many-key="prod_id" /> + </field> + + </class> +
+ +
+ 1:M relation + + + The following code fragment shows (again) the mapping file for + the Product class. The field definition highlighted + shows how to declare a 1:M relation between Product + and ProductDetail, where every product instance is + made up of many ProductDetails: + + + + <class name="myapp.Product" identity="id"> + + <map-to table="prod" /> + + <field name="id" type="integer"> + <sql name="id" type="integer" /> + </field> + + <field name="name" type="string"> + <sql name="name" type="char" /> + </field> + + <field name="price" type="float"> + <sql name="price" type="numeric" /> + </field> + + <field name="group" type="myapp.ProductGroup" > + <sql name="group_id" /> + </field> + + <field name="details" type="myapp.ProductDetail" collection="vector"> + <sql many-key="prod_id"/> + </field> + + <field name="categories" type="myapp.Category" collection="vector"> + <sql name="category_id" + many-table="category_prod" many-key="prod_id" /> + </field> + </class> + + + The following code fragment shows the corresponding mapping + entry for the ProductDetail class that defines the + second leg of the 1:M relation between Product and + ProductDetail. + + + + <class name="myapp.ProductDetail" identity="id" depends="myapp.Product" > + + <description>Product detail</description> + + <map-to table="prod_detail" xml="detail" /> + + <field name="id" type="integer"> + <sql name="id" type="integer"/> + </field> + + <field name="name" type="string"> + <sql name="name" type="char"/> + </field> + + <field name="product" type="myapp.Product"> + <sql name="prod_id" /> + </field> + + </class> +
+ +
+ M:N relation + + + The following code fragment shows (again) the mapping file for + the Product class. The field definition highlighted + shows how to declare a M:N relation between Product + and ProductCategory, where many products can be + mapped to many product categories: + + + + <class name="myapp.Product" identity="id"> + + <map-to table="prod" /> + + <field name="id" type="integer"> + <sql name="id" type="integer" /> + </field> + + <field name="name" type="string"> + <sql name="name" type="char" /> + </field> + + <field name="price" type="float"> + <sql name="price" type="numeric" /> + </field> + + <field name="group" type="myapp.ProductGroup" > + <sql name="group_id" /> + </field> + + <field name="details" type="myapp.ProductDetail" collection="vector"> + <sql many-key="prod_id">/> + </field> + + <field name="categories" type="myapp.Category" collection="vector"> + <sql name="category_id" + many-table="category_prod" many-key="prod_id" /> + </field> + + </class> + + + The following code fragment shows the corresponding mapping + entry for the ProductCategory class that defines the + second leg of the M:N relation between Product and + Category. + + + + <class name="myapp.Category" identity="id"> + + <description> + A product category, any number of products can belong to + the same category, a product can belong to any number of + categories. + </description> + + <map-to table="category" xml="category" /> + + <field name="id" type="integer"> + <sql name="id" type="integer"/> + </field> + + <field name="name" type="string"> + <sql name="name" type="char"/> + </field> + + <field name="products" type="myapp.Product" collection="vector"> + <sql name="prod_id" + many-table="category_prod" many-key="category_id" /> + </field> + + </class> +
+
+ +
+ Extend relation & polymorphism + + + As of release 0.9.9, Castor supports polymorphic queries on extend + hierarchies. (That is, hierarchies where some entities "extend" + other entities.) To highlight this new feature, let's add two new + classes to what we have currently. + + + +package myapp; + +public class Computer extends Product { + + private int _id; + + private String _make; + + public int getId() { ... } + + public void setId( int anId ) { ... } + + public String getmake() { ... } + + public void setMake( String aMake ) { ... } + +} + +public class Car extends Product { + + private int _id; + + private Date _registeredIn; + + public int getId() { ... } + + public void setId( int anId ) { ... } + + public Date getRegisteredIn() { ... } + + public void setRegisteredIn( Date aRegisteredIn ) { ... } +} + + + The corresponding DDL statements for the relational database tables + COMP and CAR would look as follows: + + + COMP: + + +create table comp ( + id int not null, + make varchar(200) not null +); + + CAR: + + +create table car ( + id int not null, + regIn int not null +); + + + Based upon the mapping defined for the Product class + as shown above, the following code fragment shows the mapping for + the Computer and Car classes. + + + + <class name="myapp.Computer" extends="myapp.Product" identity="id"> + + <map-to table="COMP" /> + + <field name="id" type="integer"> + <sql name="id" type="integer" /> + </field> + + <field name="make" type="string"> + <sql name="make" type="char" /> + </field> + + </class> + + <class name="myapp.Car" extends="myapp.Product" identity="id"> + + <map-to table="CAR" /> + + <field name="id" type="integer"> + <sql name="id" type="integer" /> + </field> + + <field name="registeredIn" type="date"> + <sql name="regIn" type="long" /> + </field> + + </class> + + + Based upon this mapping, it is possible to execute the following OQL + queries against this class model: + + + +OQLQuery query = d.getOQLQuery("SELECT c FROM myapp.Computer c"); + + + To return all computers: + + +OQLQuery query = d.getOQLQuery("SELECT c FROM myapp.Computer c WHERE c.make = $"); + + + To return all computers of a particular make: + + +OQLQuery query = d.getOQLQuery("SELECT p FROM myapp.Product p"); + + + + To return all products (where Castor will return the actual object + instances, i.e. a Computer instance if the object + returned by the query is of type Computer or a + Car instance if the object returned by the query is + of type Car): + + + +OQLQuery query = d.getOQLQuery("SELECT p FROM myapp.Product p WHERE p.group.name = $"); + + + + To return all products that belong to the specified product group + (where Castor will return the actual object instances, i.e. a + Computer instance if the object returned by the query + is of type Computer or a Car instance + if the object returned by the query is of type Car): + +
+ +
+ OQL samples + + + Based upon above definitions, here are a few OQL sample queries that + highlight various artifacts of the OQL support of Castor JDO. + + + + To Be Written + +
+
+
\ No newline at end of file Index: doc/src/docbkx/reference/jdo/jdo-faq.xml =================================================================== --- doc/src/docbkx/reference/jdo/jdo-faq.xml (revision 0) +++ doc/src/docbkx/reference/jdo/jdo-faq.xml (revision 0) @@ -0,0 +1,1476 @@ + + + +
+ Castor JDO FAQ + +
+ Castor's relation to other specifications + +
+ Does Castor JDO comply with the SUN JSR-000012 specification? + + + No, Castor JDO doesn't comply with the SUN's JDO specification. + + + + Although Castor JDO carries very similar goals as SUN's JDO, it has + been developed independently from the JSR. + + + + Although it is not impossible to shape (perhaps "hammer" is a more + descriptive verb) Castor JDO into the SUN's JDO specification, there + are several major technical differences which make it unfavorable to + do so. Castor is RDBMS centric. Each persistence object loaded by + Castor is locked. Locks in Castor are observable, meaning that locks + may not be granted because of timeout or deadlock. On the other + hand, the SUN's JDO hides details about locks. + + + + Internally, Castor JDO maintains a single copy of lock (and cache) + for each active persistence object for all transaction. SUN's JDO + specification implicitly requires a copy of cache per object per + transaction. SUN's JDO also implicitly requires a bytecode modifier + which Castor doesn't require. + + + + Castor also provides other features, such as key generators, long + transaction support and OQL query which cannot be found in SUN's JSR. + +
+ +
+ Is Castor JDO better than EJB CMP? + + + The relation between JDO and EJB Container-Managed + Persistence is more complicated than simply saying, "one + is better than the other". + + + + An Entity Bean may manage persistence itself - the EJB + specification calls this Bean Managed Persistence + (BMP). Alternatively, the Entity Bean may rely on an EJB + container to manage all peersistence automatically - the + EJB specification calls this Container Managed Persistence + (CMP). When implementing BMP, an Entity Bean may use + Castor JDO as its persistence mechanism, or it may use + others methods, such as dealing with JDBC directly. + During CMP, an EJB Container vendor may implement their + CMP on top of Castor JDO. In such an implementation, + Castor JDO will be used to persist the Entity Bean. + + + + If a developer would like to take advantage of an EJB's + life-cycle management, security, the "write once deploy + anywhere" promise and other distributed business + application facilities, then EJB will be the right + choice. Otherwise, the fact that Castor is simple, is Open + Source (you can always include Castor in your application + or product), has much less overhead, provides more design + freedom, and is integrated with Castor XML may be enough + of a reason to choose Castor JDO. + +
+ +
+ +
+ XML related questions + +
+ Is it possible to make XML marshalling transactionally using Castor? + + + No. The decision of putting XML and JDO together is NOT intended to + make XML marshalling transactional. Instead, the integration is done + to help developers of a typical client-server situation whereby an + application server receives incoming XML messages, process the + messages and replies to the client. + + + + With Castor, incoming XML messages can be unmarshaled into data + objects. Required information can be obtained from a database using + JDO in form of data objects. With this approach, all data + manipulation can be done in an object-oriented way. Changes to JDO + data objects can be committed transactionally, and result data + objects can be marshaled into XML and returned to the client. + +
+ +
+ Is it possible to do queries on a XML file using Castor? + + + No, Castor does not provide an OQL query facility on a XML file. If + querying is important for you, you should consider using a DBMS to store + your data instead of using XML files, especially if querying performance + is a concern. + + + + Another alternative is parse an XML Document directly and use XPath to + retrieve Nodes and/or NodeSets from an XML Document. Other open source + tools which provide this functionality are: + + + + SAXPath + + + + + Jakarta Commons JXPath + + + + +
+ +
+ +
+ Technical questions + +
+ Where can I find some examples to start with? + + + Download the full SVN snapshot and look into the src/tests/jdo + directory. + +
+ +
+ I have encountered problems using Sun JDBC-ODBC bridge with Castor... + + + It cannot be used with Castor, because it doesn't allow more than one + open ResultSet at the same time. + Either use JDBC driver of type > 1, or use some other JDBC-ODBC + bridge without such a restriction + (for example, from Easysoft). + +
+ +
+ + My get-method for the Collection of dependent objects returns null. + Why? + + + You should initialize the Collection yourself: + + +
+ +
+ Should my JDO classes implement some special interface? + + + In general, no. If you need some behavior that is not directly + supported by Castor, you can implement interface + org.exolab.castor.jdo.Persistent. + In order to use dirty checking for long transaction you should + implement interface + org.exolab.castor.jdo.TimeStampable. + If you need an example of use of these interfaces, see Persistent.java + and TestPersistent.java among Castor JDO tests. + +
+ +
+ Can Castor automatically create/remove related objects? + + + First of all, let's agree upon terminology. We distinguish dependent + and independent objects: + + + + + dependent objects are bounded + to the parent object's lifecycle + + + + + independent objects have + independent lifecycle + + + + + Thus, dependent objects are created/removed automatically, when + their parent object is created/removed, while all operations on + independent objects should be performed explicitly. + + + + However, with Castor 0.8.x you cannot describe explicitly the kind + of object. Instead, the following rule applies: if you have + one-to-many relation, and each side of the relation refers to + another (Collection attribute on "one" side, simple attribute on + "many" side), then "many" side is a dependent object. All other + objects are independent. In particular, related objects via + one-to-one relation are not created/removed automatically. + + + + With Castor 0.9 dependent objects should be described via "depends" + attribute of "class" element in mapping configuration file. + + + + If you wish some independent object was created and/or removed + automatically on operations on other independent object, you may + use interface Persistent to code the desired behavior. + +
+ +
+ + Is Castor JDO using any connection pooling mechanism to improve + the overall performance? + + + + No, Castor JDO doesn't have any built-in JDBC resource pooling. + However the framework can transparently use any resource pooling + facilities provided through DataSource implementation or + -even better- through JDNI. In fact we even recommend people to use + some Connection and PreparedStatement pool with Castor as this can + increase Castor's performance 3-5 fold. + + + + For example the following set of statements: + + will be executed in much less time with the resource pooling because it + will avoid creating a new physical JDBC connection at every execution. + + + + With Oracle, instead of specifying the usual JDBC driver you can use a + DataSource that specifically provides some Connection caching/pooling. + + + + Thus if your jdo config file looks like : + + + + + + ... + + ]]> + then it can be changed into (for example): + + + + + ... + + ]]> + + + + When Castor is used inside a Container such as an EJB container + (within BMP or Session Bean), then the Container usually provides + the JDBC resource through the JNDI ENC, which implicitely includes + pooling facilities. + +
+ +
+ + I am getting ClassNotFoundException for my JDO class, + but it is in the class path. Why? + + + Probably castor.jar file is in jre/lib/ext directory. In this case + you should call: + + jdo.setClassLoader(getClass().getClassLoader()); + + before jdo.getDatabase(). + +
+ +
+ + I am getting exception + 'the class ... is not persistence capable...'. Why? + + + + In this case as well as in many others you can get more information + with the help of logging. Call: + + + jdo.setLogWriter(Logger.getSystemLogger()); + + and seek in the output for warnings and errors. +
+ +
+ + I call db.remove() on the dependent object and commit, + but this doesn't work... + + + + You should not add/remove dependent objects directly. In order to + add/remove the dependent object you should just add/remove it from the + collection in the master object and call db.commit() + + + + Dependent objects cannot be created/removed explicitly. It's created + automatically when it is added to a master object, and removed + automatically when it de-linked/dereferenced from a master object. + + + + Otherwise, we will be encounter into problem where a dependent object + created explicitly but removed implicitly (delinked from a master object), + or vice versa. It can also lead to other problems that are harder to + detect. + +
+ +
+ + How should I represent string/date/boolean literals in OQL query? + + + + It is recommended to replace literals with parameters and to set them + via OQLQuery.bind(), for example: + + $2 AND married=$3"); +query.bind("John %"); +query.bind((new SimpleDateFormat("yyyy-MM-dd")) + .parse("1960-01-01")); +query.bind(false); + ]]> +
+ +
+ + I get 'java.lang.AbstractMethodError: getBigDecimal' + for numeric fields. Why? + + + + Your JDBC driver is not JDBC 2.0 compliant, upgrade it or find another one. + +
+ +
+ Does Castor support both one-way and two-way relationships? + + + + + Typcially a relationship between two objects is either one-way + (aka uni-directional) or two-way (aka bi-directional). + Officially, Castor currently only supports bi-directional relationships. + For example, if an Order object contains a reference + to a LineItem object, the LineItem + object must contain a reference to the Order object. + However, this requirement is not enforced in all situations. + + + + This is a very complex problem to solve. So until Castor is expanded + the support uni-directional relationships, the best policy is to + implement the bi-directionalality for all relationships. This will + ensure proper functionality. + +
+ +
+ + I have an object that holds a relation to itself. + Does Castor support this? + + + + This is a very common occurrence in an object model and is known as + a self-referenential relationship. Unfortunately, Castor does not + currently support self-referential relationships. An example of such + a relationship occurs when a Folder object contains + a reference to another Folder object. + Castor does not currently support this. However, there are ways + around this limitation. + + + + One way is to manage this type of relationship manually. For example, + let's say that a parent object FolderA needs to hold + references to child objects FolderB, + FolderC and FolderD. + The Folder object contains not only a property + to hold its own id, but also a property to hold its parent id + (we'll call this parentId). + The parentId property is used to determine + if there is a relationship to another Folder object. + If parentId is null, there is no relationship. + If parentId is populated, there is a relationship + and the object tree can be walked by comparing the object id to the + parentId. When the two properties are equal, + you're at the top of the tree. + + + + Another say to solve this problem is to make use of an intermediary + object. For example, a Folder object contains a + Reference object in lieu of the actual + Folder object. The Reference + object is somewhat of a proxy object whereby it only contains enough + information to identify the object to which the + Reference object refers. Then the + Folder object can be easily instantiated via the + information contained in the Reference object. + +
+ +
+ + Why do I get an ObjectModifiedException when trying to commit + a transaction? + + + + The dirty checking engine will throw an + ObjectModifiedException when the values in the + cache and in the database are different. This can happen when + someone else changed the database content, but also when type + mapping is not reversible. + + + + For example, if a java timestamp (java.util.Date) + is stored as a DATE, the time part is lost and the dirty checking + will fail. Oracle cannot tell the difference between an empty String + and a null value: if an attribute value is an empty String, dirty + checking will also fail. Some precision loss sometimes occur with + floating point numbers. + + + + To avoid this, always use reversible mapping conversions. If this + is not possible, mark the fields with dirty="ignore" + in the mapping file. + +
+ +
+ I'm receiving a java.sql.SQLException: ORA-01461 + + + When using Weblogic Portal 4.0 with Oracle I am receiving the following + error: + + According to + Weblogic Release Notes, this error can remedied by setting + a Weblogic environment variable. + +
+
+ +
+ Castor and performance caches + +
+ + Sometimes long transaction fails: on update() it is thrown + ObjectModifiedException. Why? + + + + Most probably the object that is being updated has more than 100 related + objects of one class and the cache size for this class is not enough. + You should either increase the size of the cache or change the cache type + to time-limited (the default cache type is count-limited, the default + size is 100), for example: + + + ... + + ]]> + +
+ +
+ Can I use the cache-type='none' with long transactions? + + + As of release 0.9.5.3, you cannot. When using a cache of type 'none' + with your 'Timestampable' objects, a MappingException is thrown when + performing long transactions. Currently, Castor requires a (performance) + cache of type other than 'none' to be used with classes that implement + the 'TimeStampable' interface. In other words, if you want to use long + transactions, please make sure that you use one of these cache types: + 'unlimited', 'count-limited' or 'time-limited'. + + + + The next entry has some more information about a potential cause of + confusion in the context of long transactions and a cache type other + than 'unlimited'. + +
+ +
+ + What is causing a PersistenceException with long transactions and + how do I fix it? + + + + With long transactions, sometimes update() throws a PersistenceException. + As of release 0.9.5.3, Castor requires a (performance) cache (of type + other than 'none') to be used with classes that implement the + 'TimeStampable' interface. + + + + Please note that if you are using a cache type other than 'unlimited', + it is possible that objects expire from the cache. This case will be + highlighted to you by a PersistenceException being thrown. + + + + In this cases, please consider switching to cache type 'unlimited' + (if possible) or increase the size of the cache according to your + needs when using 'count-limited' (which has a default capacity of 100). + +
+
+ +
+ OQL + +
+ Is there any document available for Castor OQL? + + + Yes. It is available from the Castor website: + Advanced JDO —> OQL + +
+ +
+ + The OQL document describes several phases of development. + Which is the current phase? + + + We are currently working on Phase 3. +
+ +
+ Does Castor OQL support sub-queries? + + Not yet +
+ +
+ + I cannot get Castor OQL to join two objects for me. Is it supported? + + + + Yes or no. Castor OQL supports implicit joins. And, in most case, + you simply don't need explicit join. + + + + Consider the following example, + 100 + ]]> + + + + It is simply equivalent to the following OQL + 100 + ]]> + +
+ +
+ Can I write a pass-thru OQL? + + + Yes. Just put "CALL SQL" keywords in front of your SQL statement. For example, + + + + + + But remember that the order of the fields listed must match what is + defined in the mapping file. + + +
+ +
+ Does Castor OQL support struct? + + + No, Castor OQL doesn't support struct. For example, the following + query CANNOT be done: + + +
+ +
+ How do I structure a query using the 'LIKE' expression? + + + A query using the 'LIKE' expression includes the use of the SQL + wildcard '%'. The wildcard must be included in the + bind() + statement: + + OQLQuery oql = castorDb.getOQLQuery( + "SELECT p FROM Product p WHERE p.name LIKE $1" ); + oql.bind( "%widget%" ); + + +
+ +
+ Does Castor support the SQL 'IN' expression? + + + Yes. However, the full expression is a bit different using the LIST + keyword. The following example provides a demonstration: + + + + + If identifiers other than numbers are used, those identifiers must be + quoted: + + + + + To include NULL values in the 'IN' list, use the 'nil' keyword: + + + + + It is even possible to include bind values in the 'IN' lists + using the following syntax: + + +
+ +
+ +
+ Features requests + +
+ Can a foreign key be part of multiple primary keys? + + + Unfortunately, the answer is no. We're aware that many users need + this feature so it is a very high priority in our todo list. + + + + If foreign key is the primary key, as a workaround you may consider + using the 'extends' relationship. + +
+ +
+ Is polymorphic collection supported? + + Unfortunately, the answer is no. + + + In version 0.8.11, we tried to enable polymorphic collection by + introducing the notation of Object Reloading. Object Reloading + delegates the determination of the class to a data object. However, + it is proved that reloading can only be done before any instance of + the target object is returned to user, and we have no way to determine + that. As a result, we removed the support in version 0.9.x. + + + + In the near future, we are going to use a new mechanism to provide + extends. The new mechanism loads a table with an SQL statement that + outer-joins all of the extending tables with the base. The existence + of an extended table row can be used to determine the class of a data + object. Notice that all extended table rows of the same entity should + always be stored in the same data-store. + + + + In the further future, we also want to let users to define a + discriminator column (or determinance field). Basing on the value of + discriminator columns in the base table, the bridge layer fetches the + additional information and returns the combined entity with the + appropriate list of entity classes. + +
+ +
+ +
+ Data model issues + +
+ Is it possible to map an object to more than one tables? + + + Yes, if the two tables share the same identity, you can specify one + data object to "extends" the other. When the extended data object is + loaded, its table (specified in ]]> will be joined + with all the tables of its super classes'. + + + + Another solution (in my opinion more flexible) is having two set + of methods in the main object. One for Castor JDO and another for + application. + + + + Consider the following example: + + +
+ +
+ + Can an object with the same identity be re-created after being removed + in the same transaction? + + + + Yes, as long as the deleted object is the same instance as the one + being recreated. + +
+ +
+ What is a dependent object? + + + Dependent object is actually a concept from the object-oriented + database world. A dependent object's lifetime depends on its master + object. So, create/delete/update of the master object will trigger + the proper actions, newly linked dependent object will be + automatically created and de-referenced dependent object will be + removed. + + + + The concept was also used in the earlier CMP 2.0 draft, although + it is later removed. + +
+ +
+ + Can a data object involved in many-to-many relationship be dependent? + + + No +
+ +
+ +
+ Castor JDO design + +
+ How does Castor JDO work anyway? + + Let's use object loading as an example. + + + When an application invoke db.load, the underneath + TransactionContext is invoked. + If the object with the requested identity exists in the + TransactionContext, previously loaded object in the + TransactionContext is returned. Otherwise, + TransactionContext creates a new instance + of the interested type and invokes LockEngine to "fill" the object. + + + + LockEngine acquires a lock of the object, + and it makes sure ClassMolder has a thread-safe + environment when it invokes ClassMolder. + In ClassMolder, if the interested set of fields + representing the object is not existed in the cache yet, + SQLEngine will be invoked and the set of fields + from the underneath data store will be returned. + ClassMolder binds the loaded or cached fields into + the new instance. ClassMolder requests the + TransactionContext to load the related and the + dependent objects. Eventually, the object is returned after all of + the relationships are resolved. + + + + The process of commit has several states. The first state is + preStore. In preStore state, objects existing in the + TransactionContext are checked for modification + one by one, including dependent and related objects. + De-referenced dependent objects are marked as delete-able, + and reachable dependent objects are added into + TransactionContext. An object is marked + "dirty" if it is modified. Also, if any modification should cause + any related or dependent to be dirty, the related or dependent object + is marked as dirty as well. + + + + After the preStore state, all dirty object is properly stored. And, + all marked delete object will be removed. Then, the connection is + committed. If succeed, all cache with be updated. Finally, all lock + is released. + +
+ +
+ + Does Castor support two-phase commits? How is this implemented? + + + + Yes, via javax.transaction.Synchronization interface. + + + + For Castor to work with global transactions, Castor must be configured + to use global transaction demarcation in its main configuration file: + + + + ... + + + + + ]]> + + When retrieving a Database instance via + + + + + the Database implementation will authomatically + be registered with the transaction manager, as it implements + javax.jta.Synchronization interface. + Subsequently, the transaction manager communicates with Castor + via the beforeCompletion() and afterCompletion() calls. + +
+ +
+ Does Castor support nested transaction? + + No +
+ +
+ +
+ Working with open source databases + +
+ Does Castor support PosgreSQL? + + + Yes, starting from PostgreSQL 7.1, where outer joins support has + been added. + +
+ +
+ Does Castor support MySQL? + + + Yes, starting from MySQL version 3.23, where transaction support has + been added. Note: if you use Mark Matthews MySQL JDBC driver, then + you need version 2.0.3 or higher. + +
+ +
+ Which Open Source database is supported better? + + + For now only with + PostgreSQL 7.1 + and SAP DB you get a full + set of Castor features. Other Open Source databases don't support + select with write lock, so db-locked locking mode doesn't work + properly (it works in the same way as exclusive locking mode). + + + + All other Castor features are supported with + MySQL, + Interbase, + InstantDB and + Hypersonic SQL. + +
+ +
+ +
+ RDBMS-specific issues + +
+ MySQL + +
+ Use of DATETIME fields in general + + + MySQL in it's current releases (4.0.x and 4.1.x) does not store fractions of a + second in fields of type DATETIME that are mapped to java.sql.TimeStamp fields. + As a result, Castor will throw ObjectModifiedExceptions during commits as Castor + internally maintains fractions of a seconds. + + + Instead, Please use a column type that can be mapped to a long value, as Castor + internally handles conversion between java.util.Date and long values with + the required precision. + +
+ +
+ Use of TIMESTAMP fields & NULLs in long transactions + + + In MySQL, fields of type 'Timestamp' exhibit special behaviour wih + regards to NULLs. When inserting a "NULL" into such a field, it + actually inserts the current date and time. This causes problems + for Castor's caching mechanism since Castor internally believes the + field is still NULL. If you subsequently perform an update on the + entry whilst it is still in the cache, an ObjectModifiedException + will be thrown, because Castor believes that the database record + has changed in the meantime. + + + The workaround is to use a DATETIME field instead of TIMESTAMP. + +
+ +
+ MySQL 4.1.x and upgrade issues + + + As with many other open source products, MySQL seems to be changing + slightly from version to version. There seems to be a problem with + concurrency in MySQL 4.1.5 that can be resolved by upgrading to + 4.1.7 or higher. + + + + At Castor we frequently use Connector/J 3.0.16, 3.1.13 and nowadays 5.1.6 to + execute our test farmework. If you use one of this versions of Connector/J + you should be on the safe side. If you are hit by any problems using one of + these versions, please let us know. + + +
+ + +
+ +
+ Oracle + +
+ Oracle & (C|B)LOB fields + + + As of Oracle release 10g, the problem of Castor to handle BLOBs + with a size greater than 2kB and CLOBs with a size greater than + 4 kB correctly has been resolved. With the 10 release of Oracle's + JDBC driver, both driver types (type 2 and type 4) can be used. + With earlier releases, only the OCI driver (type 2) seems to work. + + + + The 10g release of the Oracle JDBC Driver can be downloaded + here. + + +
+ +
+
+ +
+ Castor & Logging + +
+ + How can I integrate Castor's logging with a logging infrastructure + using Log4J? + + + + Please see + + this message from the mailing list. It includes an adapter class + that will provide this functionality. (Thanks John!) + +
+ +
+ + Can I see what SQL statement Castor issues to the database as a result + of an operation? + + + + Yes, you can. By default, Castor uses JDBC proxy classes (wrapping + java.sql.Connection and + java.sql.PreparedStatement) that capture the + core SQL statements as generated by Castor and the user-supplied + parameters at execution timeof the various persistence operations, + and outputs them to the standard logger used by Castor. + By default, these output statements are not visible, + as the log level is set to level 'info'. To see these SQL statements, + please increase the log level to level 'debug' in + log4j.xml. + + +
+ +
+ How can I disable the use of JDBC proxy classes? + + + As of release 0.9.7, a new property + org.exolab.castor.persist.useProxies + has been added to castor.properties to allow + configuration of the JDBC proxy classes mentioned above. + If enabled, JDBC proxy classes will be used for logging SQL statements. + When turned off, no logging statements will be generated at all. + + +
+ +
+ +
+ Lazy Loading related questions + +
+ + How do I configure the JDO mapping to use the lazy loading feature + for 1:1 relations? + + + + Let us convert one of the classes from the + JDO examples to use + lazy-loading. + + + + In the example model, every Product belongs to one ProductGroup. + This is reflected in the conventional mapping as below. + Here's the mapping for Product: + + + + + Product definition + + + + + + + + + + + + + + + +]]> + + + Let us now make the relationship between Product and ProductGroup use + lazy loading. The relevant field in Product can be re-written like so: + + + + <field name="group" type="myapp.ProductGroup" lazy="true"> + <sql name="group_id" /> + <bind-xml name="group" node="element" /> + </field> + + + + There have been one change only. We have placed the attribute lazy="true" in + the field element. Note that no change is required in the ProductDetail + mapping. + + +
+ +
+ Lazy loading for 1:1 relations and serialization + + + Please note that Castor does not support full serialization of lazy-loaded + objects at this time. Rather than serializing just the information + required to re-build the underlying proxy implementation during + deserialization, Castor will materialize (read: load from the persistence + store) all objects before serialization. As this can lead to a lot of + database accesses, please use this feature carefully. A full working + solution will be provided with the next release. + + +
+ +
+ + How do I configure the JDO mapping to use the lazy loading feature for + 1:m and M:N relations? + + + + Let us convert one of the classes from the + JDO examples + to use lazy-loading. + + + + In the example model, one Product can contain many ProductDetails. + This is reflected in the conventional mapping as below. + First, the mapping for Product: + + + Product definition + + + + + + + + + + + + + + + ]]> + + + + Now let us examine ProductDetail. Note, the relationship is mapped + bi-directionally as must be + all relationships when using Castor JDO. + + + Product detail + + + + + + + + + + + + + + ]]> + + + + + Let us now make the relationship between Product and ProductDetail use + lazy loading. We need only change the way that the relationship to + ProductDetail is specified in the mapping of Product. The relevant + field in Product can be re-written like so: + + + + + ]]> + + + + + There have been two changes. + + + + We have placed the attribute lazy="true" in the field element + + + + + We have changed the type of the underlying collection type to be + a java.util.Collection by changing the field + element attribute to collection="collection". + + + + + + Note that no change is required in the ProductDetail mapping. + +
+ + +
+ + I have modified my mapping to use lazy loading. Now I get the error + 'no method to set value for field: com.xyz.ClassB in class: + ClassMolder com.xyz.ClassA' or + 'org.exolab.castor.jdo.DataObjectAccessException: no method to set + value for field: com.xyz.ClassB in class: ClassMolder com.xyz.ClassA'. + What am I doing wrong? + + + + To use lazy loading you must also change the persistent class that + will hold the related objects. At the very highest level, you need + to provide a set method that accepts a java.util.Collection for the + field in question. This is demonstrated by changing the + JDO examples below. + + + + In the original Product class we have the following code: + + + + + Let us now make the necessary changes to set up lazy loading. + As stated above we now require a special set method for the related + ProductDetails (stored originally as a + java.util.Vector) that accepts a + java.util.Collection as an argument. This mandates + that we must also use a java.util.Collection to + hold our ProductDetails. If this is not added, you will receive the + errors above. + + +
+ +
+ +
+ Tuning for LOBs + + + Castor JDO provides a property in castor.properties + for adjusting the size of the JDBC driver's buffer for reading LOBs + (BLOBs and CLOBs) from the database. The propery is named + org.exolab.castor.jdo.lobBufferSize and its default + is 5120 bytes (5k). The size of this buffer can be tuned for larger LOBs, + but is dependent upon the JDBC driver implementation being used and what + it supports. + +
+ +
+ Database-specific issues + +
+ HSQL and identity key generators + + + Due to a product limitation, AUTO_INCREMENT sequences in HSQL begin + with 0 rather 1, as is the case with most other RDBMS. As a result + of this, long transactions will not work for the object with the + identity 0, and a ObjectModifiedException will be thrown. + + + + To avoid this issue, we recommend inserting a temp object into the + database in question, and removing thereafter so that no object with + identity 0 is stored. + +
+ +
+ +
+ Changing database configurations + + + Some applications need to change the database connection or switch + between different mapping files on the fly. Because Castor caches + database configurations per name, you would have to register a new + JDO configuration using a distinct name for any of the different + configurations. + + + + Instead you can call + org.exolab.castor.jdo.engine.DatabaseRegistry.clear() + to reset the database registry before registering the new configuration as + follows: + + + +// Reset database registry +org.exolab.castor.jdo.engine.DatabaseRegistry.clear(); + +
+
\ No newline at end of file Index: doc/src/docbkx/reference/jdo/jdo-introduction.xml =================================================================== --- doc/src/docbkx/reference/jdo/jdo-introduction.xml (revision 0) +++ doc/src/docbkx/reference/jdo/jdo-introduction.xml (revision 0) @@ -0,0 +1,194 @@ + + +
+ Castor JDO - An introduction + + + +
+ What is Castor JDO + + + Castor JDO is an Object-Relational Mapping and Data-Binding Framework, which is + written in 100% pure Java[tm]. Castor can map relational database data into + Java Data Object based on user-defined mapping schema. In the other point-of-view, + it provides java data objects a persistence layer. + + + + It frees programmer from dealing with database directly and replacing the entire + burden of composing updating the database. Proper SQL statements are automatically + generated for loading, updating, creating and deleting. Changes to objects in transaction + are automatically done to data source at commit time. Thus programmer can stay in pure-Java + without remember all the details in the backing database, after the creation of + database tables and the mapping schema. The separation of persistence and programming + logic also enable much clearer object-oriented design, which is important in larger + projects. + + +
+ +
+ Features + + + 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 as well as simple 1:1 relations) is implemented to reduce unnecessary + database loading. Lazy loading can be turned on or off for each individual field (of + any supported collection type for 1-to-many and many-to-many relations). + + + + Other features include a type converter for all Java primitive types (see the + info on supported types). + + + + 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 + Derby + Generic DBMS + Hypersonic SQL + Informix + InstantDB + Interbase + MySQL + Oracle + PostgreSQL + Progress + SAP DB / MaxDB + 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's, 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. + + +
+ +
\ No newline at end of file Index: doc/src/docbkx/reference/jdo/jdo-mapping.xml =================================================================== --- doc/src/docbkx/reference/jdo/jdo-mapping.xml (revision 0) +++ doc/src/docbkx/reference/jdo/jdo-mapping.xml (revision 0) @@ -0,0 +1,780 @@ + + +
+ Castor JDO Mapping + + + +
+ News + + + Release 1.0 M3: + + + Added collection type 'iterator'. + + + Added collection type 'enumerate'. + + + Added additional syntax for specifying the identity of a class. + + + +
+ +
+ Introduction + + + The Castor mapping file also provides a mechanism for binding a Java + object model 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. + + + + The mapping file provides a description of the Java object model to + Castor JDO. Via Castor XML, Castor JDO uses the information in the mapping + file to map Java objects to relational database tables. The + following is a high-level example of a mapping file: + + + + + + + + + ... + + ]]> + + + Each Java object is represented by a <class> element composed of attributes, + a <map-to> element and <field> elements. The <map-to> element + contains a reference to the relational table to which the Java object maps. + Each <field> element represents either a public class variable or the + variable's accessor/mutator methods (depending upon the mapping info). Each + <field> element is composed of attributes and one <sql> element. + The <sql> element represents the field in the relational table to which + the <field> element maps. + + + + It is possible to use the mapping file and Castor's default behavior in + conjunction. When Castor handles an object but is unable to locate + information about it in the mapping file, it will rely upon its default + behavior. Castor makes use of the Java programming language + + Reflection API to introspect the Java objects to determine the methods + to use. This is the reason some attributes are not required in the mapping + file. + + +
+ +
+ The Mapping File + +
+ The <mapping> element + + ]]> + + + The <mapping> element is the root element of a mapping file. It contains: + + + + + an optional description + + + zero or more <include> which facilitates reusing mapping files + + + + zero or more <class> descriptions: one for each class we intend to give + mapping information + + + + zero or more <key-generator>: not used for XML mapping + + + + A mapping file look like this: + + + + + + Description of the mapping + + + + ... + + + + ... + + ]]> + +
+ +
+ The <class> element + + + ]]> + + + + The <class> element contains all the information used to map a Java object + to a relational database. The content of <class> is mainly used to describe + the fields that will be mapped. + + + Description of the attributes: + + + + + name: The fully qualified package name of the + Java object to map to. + + + + + extends: Should be used + only if this 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. + + + + + + depends: For more information on this field, + please see + + Dependent and related relationships. + + + + + + identity: For more information on this field, + please see + Design -> Persistence. + + + + + + access: For more information on this field, + please see Locking Modes. + + + + + + key-generator: For more information on + this field, please see KeyGen. + + + + + Description of the elements: + + + + + <description>: + An optional description. + + + + + + <cache-type>: + For more information on this field please see + Bounded Dirty Checking + and Caching. + + + + + + <map-to>: + Used to tell Castor the name of the relational + table to which to map. + + + + + + <field>: Zero or more + <field> elements are used to describe properties + of each Java object. + + + + +
+ +
+ The <map-to> element + + + ]]> + + <map-to> is used to specify the name of the item that should be associated + with the given Java object. The <map-to> element is only used for the root + Java object. + + Description of the attributes: + + + + + table: + The name of the relational database table to which the + Java object is associated. + + + + +
+ +
+ The <field> element + + + ]]> + + + The <field> element is used to describe a property of a Java object. It provides: + + + + the identity ('name') of the property + + + the type of the property (inferred from 'type' and 'collection') + + + + the access method of the property + (inferred from 'direct', 'get-method', 'set-method') + + + + + + From this information, Castor is able to access a given property in the Java + object. + + + + In order to determine the signature that Castor expects, there are two easy + rules to apply. + + + 1. Determine <type>. + + + + + If there is no 'collection' attribute, + the object type is 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: + + + + + + + + short name + Primitive type? + Java Class + + big-decimal Njava.math.BigDecimal + big-integer Yjava.math.BigInteger + boolean Yjava.lang.Boolean.TYPE + byte Yjava.lang.Byte.TYPE + bytes Nbyte[] + char Yjava.lang.Character.TYPE + chars Nchar[] + clob Njava.sql.Clob + date Njava.util.Date + double Yjava.lang.Double.TYPE + float Yjava.lang.Float.TYPE + int Yjava.lang.Integer.TYPE + integer Yjava.lang.Integer + locale Njava.util.Locale + long Yjava.lang.Long.TYPE + other Njava.lang.Object + serializableYjava.io.Serializable + short Yjava.lang.Short.TYPE + sqldate Yjava.sql.Date + sqltime Yjava.sql.Date + string Njava.lang.String + strings NString[] + stream Njava.io.InputStream + timestamp Njava.sql.Timestamp + + + + + + + Castor will try to cast the data in the mapping file to the proper Java + type. + + + + + + + If there is a collection attribute, + the items in the following table can be + used: + + + + + + + + name + type + default implementation + added in release + + + array + <type_attribute>[] + <type_attribute>[] + + + + enumerate + java.util.Enumeration + - + 1.0 M3 + + + collection + java.util.Collection + java.util.ArrayList + + + + set + java.util.Set + java.util.HashSet + + + + arraylist + java.util.ArrayList + java.util.ArrayList + + + + vector + java.util.Vector + java.util.Vector + + + + map + java.util.Map + java.util.HashMap + + + + hashtable + java.util.Hashtable + java.util.Hashtable + + + + sortedset + java.util.SortedSet + java.util.TreeSet + 1.0 M2 + + + iterator + java.util.Iterator + n/a + 1.0 M3 + + + + + + + + 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. + + + + For hashtable and map, Castor 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. + + + + + + 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. + + + + + It is not possible to use a collection of type 'iterator' or 'enumerate' + with lazy loading enabled. + + + + + 2. Determine the signature of the method + + + + + + If 'direct' is set to true, + Castor expects to find a public Java object variable with the + given signature: + + + ;]]> + + + + + If 'direct' is set to false or omitted, + Castor will access the property though accessor methods. + Castor 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: + + + ();]]> + or + ( value);]]> + + + If 'get-method' or 'set-method' attributes are not provided, Castor will try to + find the following functions: + + + is();]]> + or + get();]]> + + + the former for boolean types, the latter for all other types (or if the + 'is<capitalized-name>()' method is not defined for a boolean type), and + a standard set method of + + + ( value);]]> + + + If there are more than one set<capitalized-name> method it first tries to find the one + that exactly matches <type>. If no such method is available and <type> is a java + primitive type it tries to find a method with the corresponing java object type. + + + + <capitalized-name> means that Castor uses the <name> attribute by changing its first + letter to uppercase without modifying the other letters. + + + + The content of the <field> element will contain the information about how to map + this field to the relational table. + + + + + Description of the attributes: + + + + + name: 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. + + + + + + type: The Java type of the field. + This is used to access the field. Castor 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. + + + + + + required: If true, the field is not optional. + + + + + + transient: If true, the field will + be ignored during persistence (and XML un-/marshalling). + If you want this field to be ignored during any persistence-related + operations only, please use the 'transient' attribute at the <sql> + level. + + + + + + identity: If true, the field is part of + the class identity. Please use this as an alternative way of specifying + the identity of an object. + + + + + + direct: If true, Castor expects a public + variable in the object and will modify it directly. + + + + + + collection: If a parent object expects + more than one occurrence of one of its fields, it is necessary to specify + which collection type Castor will use to handle them. The type specified + is used to define the type of the content inside the collection. + + + + + + comparator: If the collection type equals + 'sortedset', it is possible to specify a + java.util.Comparator instance that will be used with + the java.util.SortedSet (implementation) to specify + a custom sort order. Please use this attribute to specify the class name + of the Comparator instance to be used. Alternatively, it is possible to not + specify a Comparator instance and have the Java objects stored in the + SortedSet implement java.util.Comparable + to specify the sort order. + + + + + + get-method: An optional name of the + accessor method Castor should use. If this attribute is not set, + Castor will try to guess the name with the algorithm described above. + + + + + + + set-method: An optional name of the + mutator method Castor should use. If this attribute is not set, + Castor will try to guess the name with the algorithm described above. + + + + + + create-method: Factory method + for instantiation of the object. + + + + +
+ +
+ The <sql> element + + + + cascading ( create | delete | update | all | none ) "none"]]> + + + The <sql> element is used to denote information about the database + column to which a Java object is mapped. It should be declared for all + <field> elements. Each <field> element contains one <sql> + element. The <sql> element correlates directly to the <map-to> + element for the containing <class> element. The <sql> elements + contains the following attributes: + + + + + + name: The name of the column in the + database table. + + + + + + type: The JDBC type of the column. + It is inferred from the object when the type of this field is a + persistent Java class that is defined elsewhere in the mapping. + The complete list of automatic type conversions, and which values + require manual mapping (e.g, java.util.Date) is listed in the + SQL Type Conversion + section of the Type Support document. + + + + + + read-only: If true, the column in + the relational database table will only be read, not updated or deleted. + + + + + + transient (as of 0.9.9): If true, the + field will be ignored during persistence only. If you want this field + to be ignored during XML un-/marshalling as well, please use the + 'transient' attribute at the <field> level. + + + + + + dirty: If the value is 'ignore', the + field will not be checked against the database for modification. + + + + + + cascading: If the field is a relation, + this attribute specifies which operations to cascade. Possible values + are: 'all', none', 'create', 'update' or 'delete'; when not specifying + 'none' or 'all', it is possibel to specify more than one value, using + whitespace as a delimiter (e.g. 'create update'). For further + information see + HOW-TO + on using cascading operation. + + + + + + There are two more attributes used only + with 'to-many' relations. + + + + + + many-key: Specifies the name + of the column that holds the foreign key to this object. + That column is in the database table that stores objects + of the Java type of this field. + + + + + + many-table: Specifies the + name of the bridge table that contains the primary keys of + the object on each side of the relationship. This is + only used for many-to-many relationships. + + + + +
+ +
+ +
Index: doc/src/docbkx/reference/jdo/jdo-starter-tutorial.xml =================================================================== --- doc/src/docbkx/reference/jdo/jdo-starter-tutorial.xml (revision 0) +++ doc/src/docbkx/reference/jdo/jdo-starter-tutorial.xml (revision 0) @@ -0,0 +1,146 @@ + + +
+ Castor JDO - Instructions for novices + +
+ Introduction + + + This guide assumes that you do not have any experience with CASTOR JDO, but would + like to make your first steps into the world of persistence and object/relation + mapping tools. The following sections show how to setup and configure Castor JDO so that + it is possible to perform persistence operations on the domain objects presented. + + +
+ +
+ Sample domain objects + + + The sample domain objects used in here basically define a + Catalogue, + which is a collection of Products. + + + +public class Catalogue { + + private long id; + private List products = new ArrayList(); + + public long getId() { ... } + public void setId(long id) { ... } + + public String getProducts() { ... } + public void setProducts(List products) { ... } + +} + +public class Product { + + private long id; + + private String description; + + public long getId() { ... } + public void setId(long id) { ... } + + public String getDescription() { ... } + public void setDescription(String description) { ... } + +} + + + In order to be able to perform any persistence operation (such as loading products, deleting + products from a catalogue, ...) on these domain objects through Castor JDO, a Castor + JDO mapping has to be provided, defining class and field level mappings for the Java classes given + and their members: + + + +<class name="org.castor.sample.Catalogue"> + <map-to table="catalogue"/> + <field name="id" type="long"> + <sql name="id" type="integer" /> + </field> + <field name="products" type="org.castor.sample.Product" collection="arraylist"> + <sql many-key="c_id" /> + </field> +</class> + +<class name="org.castor.sample.Product"> + <map-to table="product"/> + <field name="id" type="long"> + <sql name="id" type="integer" /> + </field> + <field name="description" type="string"> + <sql name="desc" type="varchar" /> + </field> +</class> + +
+ +
+ Using Castor JDO for the first time + + + To e.g. load a given Catalogue instance as defined + by its identity, and all its associated Product instances, + the following code could be used, based upon the Castor-specific interfaces + JDOManager and Database. + + + +JDOManager.loadConfiguration("jdo-conf.xml"); +JDOManager jdoManager = JDOmanager.createInstance("sample"); + +Database database = jdoManager.getDatabase(); +database.begin(); +Catalogue catalogue = database.load(catalogue.class, new Long(1)); +database.commit(); +database.close(); + + + For brevity, exception handling has been ommitted completely. But is is quite obvious + that - when using such code fragments again and again, to e.g. implement various + methods of a DAO - there's a lot of redundant code that needed to be written again + and again - and exception handling is adding some additional complexity here as well. + + +
+ +
+ JDO configuration + + + As shown in above code example, before you can perform any persistence operations on + your domain objects, Castor JDO has to be configured by the means of a JDO + configuration file. as part of this JDO configuration, the user defines one or more + databases and everything required to connect to this database (user credentials, JDBC + connection string, ....). + + + + A valid JDO configuration file for HSQL looks as follows: + + + +<?xml version="1.0" ?> +<!DOCTYPE jdo-conf PUBLIC "-//EXOLAB/Castor JDO Configuration DTD Version 1.0//EN" "http://castor.org/jdo-conf.dtd"> +<jdo-conf> + <database name="hsqldb" engine="hsql"> + <driver class-name="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:hsql://localhost:9002/dbname"> + <param name="user" value="sa"/> + <param name="password" value=""/> + </driver> + <mapping href="mapping.xml"/> + </database> + <transaction-demarcation mode="local"/> +</jdo-conf> + + +
+
\ No newline at end of file Index: doc/src/docbkx/reference/jdo/jdo.xml =================================================================== --- doc/src/docbkx/reference/jdo/jdo.xml (revision 0) +++ doc/src/docbkx/reference/jdo/jdo.xml (revision 0) @@ -0,0 +1,531 @@ + + + +
+ Using Castor JDO + +
+ Opening A JDO Database + + + Castor JDO supports two type of environments, client applications and J2EE servers. + Client applications are responsible for configuring + the database connection and managing transactions explicitly. J2EE + applications use JNDI to obtain a pre-configured database connection, and use + UserTransaction or container managed transactions (CMT) to manage transactions. + If you have been using JDBC in these two environments, you will be readily familiar with + the two models and the differences between them. + + +
+ Stand-alone application + + + Client applications are responsible for defining the JDO configuration, and managing + the transaction explicitly. The database is by default configured through a separate + XML file which links to the mapping file. Alternatively, it can be configured using the + utility class org.exolab.castor.jdo.util.JDOConfFactory. + + + + In the example code I refer to the JDO configuration file as jdo-conf.xml, but + any name can be used. See Castor JDO Configuration for more + information. + + + + As of release 0.9.6, a new JDOManager class is provided, that replaces the former JDO + class. Any new features will be implemented against the new JDOManager class only. + + + As with its predecessor, org.exolab.castor.jdo.JDOManager defines the database + name and properties and is used to open a database connection. An instance of this class + is constructed with a two-step approach: + + + + + + Statically load the JDO configuration file through one of the + loadConfiguration() methods, e.g. + org.exolab.castor.jdo.JDOManager.loadConfiguration(java.lang.String). + + + + + Create an instance of the JDO engine using the factory method + org.exolab.castor.jdo.JDOManager.createInstance(java.lang.String) + where you supply one of the database names defined in the configuration file loaded in step 1). + + + + + + The org.exolab.castor.jdo.Database object represents an open connection to the + database. By definition the database object is not thread safe and should not be used from + concurrent threads. There is little overhead involved in opening multiple + Database + objects, and a JDBC connection is acquired only per open transaction. + + + + The following code fragment creates an instance of JDOManager for a database 'mybd', + opens a database, performs a transaction, and closes the database - as it will typically + appear in client applications (for brevity, we have ommitted any required exception + handling): + + + +JDOManager jdoManager; +Database db; + +// load the JDO configuration file and construct a new JDOManager for the database 'mydb' +JDOManager.loadConfiguration("jdo-conf.xml"); +jdoManager = JDOManager.createInstance("mydb"); + +// Obtain a new database +Database db = jdoManager.getDatabase(); + +// Begin a transaction +db.begin(); + +// Do something +. . . + +// Commit the transaction and close the database +db.commit(); +db.close(); + + + + For an example showing how to set up a database configuration on the fly without + the need of a preconfigured XML configuration file) see + JdoConfFactory. + +
+ +
+ J2EE Application + + + J2EE applications depend on the J2EE container (Servlet, EJB, etc) to configure + the database connection and use JNDI to look it up. This model allows the application + deployer to configure the database properties from a central place, and gives the J2EE + container the ability to manage distributed transactions across multiple data sources. + + + Instead of constructing a org.exolab.castor.jdo.JDOManager + the application uses the JNDI namespace to look it up. We recommend enlisting the + JDOManager object under the java:comp/env/jdo namespace, + compatible with the convention for listing JDBC resources. + + + + The following code fragment uses JNDI to lookup a database, and uses the JTA + UserTransaction interface to manage the transaction: + + + +InitialContext ctx; +UserTransaction ut; +Database db; + +// Lookup databse in JNDI +ctx = new InitialContext(); +db = (Database) ctx.lookup( "java:comp/env/jdo/mydb" ); + +// Begin a transaction +ut = (UserTransaction) ctx.lookup( "java:comp/UserTransaction" ); +ut.begin(); +// Do something +. . . +// Commit the transaction, close database +ut.commit(); +db.close(); + + + + If the transaction is managed by the container, a common case with EJB beans and + in particular entity beans, there is no need to begin/commit the transaction explicitly. + Instead the application server takes care of enlisting the database in the ongoing + transaction and executes commit/rollback at the proper time. + + + + The following code snippet relies on the container to manage the transaction + + + +InitialContext ctx; +UserTransaction ut; +Database db; + +// Lookup database in JNDI +ctx = new InitialContext(); +db = (Database) ctx.lookup( "java:comp/env/jdo/mydb" ); + +// Do something +. . . +// Close the database +db.close(); + + +
+ +
+ +
+ Using A JDO Database to perform persistence operations + +
+ Transient And Persistent Objects + + + All JDO operations occur within the context of a transaction. JDO works by loading + data from the database into an object in memory, allowing the application to modify + the object, and then storing the object's new state when the transaction commits. + All objects can be in one of two states: transient or persistent. + + + + Transient: Any object whose state will not be saved + to the database when the transaction commits. Changes to transient objects will not + be reflected in the database. + + + + Persistent: Any object whose state will be saved + to the database when the transaction commits. Changes to persistent objects will + be reflected in the database. + + + + An object becomes persistent in one of two ways: it is the result of a query, + (and the query is not performed in read-only mode) or it is added to the database + using org.exolab.castor.jdo.Database.create(java.lang.Object) + or org.exolab.castor.jdo.Database.update(java.lang.Object). + All objects that are not persistent are transient. When the transaction commits or + rolls back, all persistent objects become transient. + + + + In a client application, use org.exolab.castor.jdo.Database.begin(), + org.exolab.castor.jdo.Database>commit() and + org.exolab.castor.jdo.Database.rollback() to manage transactions. + In a J2EE application, JDO relies on the container to manage transactions either + implicitly (based on the transaction attribute of a bean) or explicitly using the + javax.transaction.UserTransaction interface. + + + + If a persistent object was modified during the transaction, at commit time the modifications + are stored back to the database. If the transaction rolls back, no modifications will be + made to the database. Once the transaction completes, the object is once again transient. + To use the same object in two different transactions, you must query it again. + + + + An object is transient or persistent from the view point of the database to which + the transaction belongs. An object is generally persistent in a single database, + and calling + org.exolab.castor.jdo.Database">isPersistent(java.lang.Object) + from another database will return false. It is possible to make an object persistent + in two database, e.g. by querying it in one, and creating it in the other. + + +
+ +
+ Running an OQL Query + + + OQL queries are used to lookup and query objects from the database. OQL queries are + similar to SQL queries, but use object names instead of SQL names and do not require + join clauses. For example, if the object being loaded is of type TestObject, + the OQL query will load FROM TestObject, whether the actual table name in + the database is test, test_object, or any other name. + If a join is required to load related objects, Castor will automatically perform the join. + + + + The following code snippet uses an OQL query to load all the objects in a given group. + Note that product and group are related objects, the JDBC query involves a join: + + + +OQLQuery oql; +QueryResults results; + +// Explicitly begin transaction +db.begin(); + +// Construct a new query and bind its parameters +oql = db.getOQLQuery("SELECT p FROM Product p WHERE Group=$1"); +oql.bind(groupId); + +// Retrieve results and print each one +results = oql.execute(); +while (results.hasMore()) { + System.out.println(results.next()); +} + +// Explicitly close the QueryResults +results.close(); + +// Explicitly close the OQLQuery +oql.close(); + +// Explicitly commit transaction +db.commit(); +db.close(); + + + + The following code snippet uses the previous query to obtain products, mark down + their price by 25%, and store them back to the database (in this case using + a client application transaction): + + + +OQLQuery oql; +QueryResults results; + +// Explicitly begin transaction +db.begin(); + +// Construct a new query and bind its parameters +oql = db.getOQLQuery("SELECT p FROM Product p WHERE Group=$1"); +oql.bind(groupId); + +// Retrieve results and mark up each one by 25% +Product prod; +while (results.hasMore()) { + prod = (Product) results.next(); + prod.markDown(0.25); + prod.setOnSale(true); +} + +// Explicitly close the QueryResults +results.close(); + +// Explicitly close the OQLQuery +oql.close(); + +// Explicitly commit transaction +db.commit(); +db.close(); + + + + As illustrated above, a query is executed in three steps. First a query object is + created from the database using an OQL statement. If there are any parameters, the + second step involves binding these parameters. Numbered parameters are bound using + the order specified in their names. (e.g. first $1, after that $2, and so on...) + The third step involves executing the query and obtaining a result set of type + org.exolab.castor.jdo.QueryResults. + + + + A query can be created once and executed multiple times. Each time it is executed + the bound parameters are lost, and must be supplied a second time. The result of + a query can be used while the query is being executed a second time. + + + + There is also a special form of query that gives a possibility to call stored + procedures: + + + +oql = db.getOQLQuery("CALL sp_something($) AS myapp.Product"); + + + + Here sp_something is a stored procedure returning one or more + ResultSets with the same sequence of fields as Castor-generated + SELECT for the OQL query "SELECT p FROM myapp.Product p" + (for objects without relations the sequence is: identity, then all + other fields in the same order as in mapping.xml). + + +
+ +
+ Creating a persistent object + + + The method + org.exolab.castor.jdo.Database.create(java.lang.Object) + creates a new object in the database, or in JDO terminology makes a transient + object persistent. An object created with the create method + will remain in the database if the transaction commits; + if the transaction rolls back the object will be removed from the database. + An exception is thrown if an object with the same identity already exists in + the database. + + + + The following code snippet creates a new product with a group that was previously + queried: + + + +Database db = ...; +db.begin(); + +//load product group +ProductGroup furnitures = db.load(...); + +// Create the Product object +Product prod; +prod = new Product(); +prod.setSku(5678); +prod.setName("Plastic Chair"); +prod.setPrice(55.0 ); +prod.setGroup(furnitures); + +// Make it persistent +db.create(prod); + +db.commit(); + + +
+ +
+ Removing a persistent object + + + The method + org.exolab.castor.jdo.Database.remove(java.lang.Object) + has the reverse effect, deleting a persistent object. Once removed the object is no + longer visible to any transaction. If the transaction commits, the object will be removed + from the database, however, if the transaction rolls back the object will remain in + the database. An exception is thrown when attempting to remove an object that is not + persistent. + + + + The following code snippet deletes the previously created Product instance: + + + +Database db = ...; +db.begin(); + +// load the Product instance with sku = 5678 +Product prod = db.load (Product.class, new Integer(5678); + +// delete the Product instance +db.remove(prod); + +db.commit(); + + +
+ +
+ Updating a persistent object + + + There's no special method offering on the + org.exolab.castor.jdo.Database + to update an existing persistent object. Simply load the object to be updated, change + one or more of its properties, and commit the transaction. Castor JDO will automatically + figure that that the object in question has changed and will persist these changes + to the underlying database. + + + + The following code snippet loads a previously created Product instance, changes its + description property and commits the transaction. + + + +Database db = ...; +db.begin(); + +// load the Product instance with sku = 5678 +Product prod = db.load (Product.class, new Integer(5678); + +// change the object properties +prod.setDescription("New plastic chair"); + +//commit the transaction +db.commit(); + + +
+ +
+ +
+ Using JDO And XML + + + Castor JDO and Castor XML can be combined to perform transactional database operations + that use XML as the form of input and output. The following code snippet uses a combination + of persistent and transient objects to describe a financial operation. + + + + This example retrieves two account objects and moves an amount from one account to the + other. The transfer is described using a transient object (i.e. no record in the database), + which is then used to generate an XML document describing the transfer. An extra step + (not shown here), uses XSLT to transform the XML document into an HTML page. + + + +Transfer tran; +Account from; +Account to; +OQLQuery oql; + +tran = new Transfer(); + +// Construct a query and load the two accounts +oql = db.getOQLQuery("SELECT a FROM Account a WHERE Id=$"); +oql.bind(fromId); +from = oql.execute().nextElement(); +oql.bind(toId); +to = oql.execute().nextElement(); + +// Move money from one account to the other +if (from.getBalance() >= amount) { + from.decBalance(amount); + to.incBalance(amount); + trans.setStatus(Transfer.COMPLETE); + trans.setAccount(from); + trans.setAmount(amount); +} else { + // Report an overdraft + trans.setStatus( Transfer.OVERDRAFT ); +} + +// Produce an XML describing the transfer +Marshaller.marshal(trans, outputStream); + + + The XML produced by the above code might look like: + + + + Completed + + + +]]> + +
+
+ + + + + + + + + Index: doc/src/docbkx/reference/jdo/types.xml =================================================================== --- doc/src/docbkx/reference/jdo/types.xml (revision 0) +++ doc/src/docbkx/reference/jdo/types.xml (revision 0) @@ -0,0 +1,525 @@ + + +
+ Type Support + +
+ Types + + + The Castor type mechanism assures proper conversion between Java types + and external types. + + +
+ Castor XML + + + Castor XML converts all Java fields into XML element and attribute + values. + + +
+ +
+ Castor JDO + + + Castor JDO converts Java fields into SQL columns which are persisted + through the JDBC driver. Due to implementation details, the field + type expected by the JDBC driver is not always the field type defined + for the mapped object. + + + + The most common occurrences of mistyping is when using fields of type + FLOAT, DOUBLE, NUMERIC, + and DECIMAL. SQL type FLOAT actually + maps to Java type java.lang.Double. SQL types + NUMERIC and DECIMAL map to Java + type java.math.BigDecimal. + + + + When such an inconsistency occurs, Castor JDO will throw an + IllegalArgumentException during object persistence with a + message indicating the two conflicting types. + + + + In order to avoid runtime exceptions, we recommend explicitly + specifying types in the mapping file using the SQL typing convention. + See SQL Type Conversion. + + +
+ +
+ Castor DAX + + + Castor DAX converts all Java fields into LDAP attribute values. LDAP + attribute values are always textual and are represented as the string + value of the field, e.g. "5" or "true". + + + + LDAP attributes may also contain binary values. When storing byte + arrays or serialized Java objects, DAX will store them as byte arrays. + + +
+ +
+ +
+ The Field Mapping + + + The field element includes an optional attribute called + type which can be used to specify + the Java type of the field. This attribute is optional since Castor + can always derive the exact Java type from the class definition. + + + + We highly recommend that developers use the type field in their mapping + file as a means to provide static type checking. When loading a mapping + file, Castor will compare the actual Java type with the type specified + in the mapping and will complain about inconsistencies. + + + + The field type can be specified either given the full class name + (e.g. java.lang.Integer) or using a short name. + The following table lists all the acceptable short names and the Java + types they represent: + + + + + + + short name + Primitive type? + Java Class + + + + big-decimalNjava.math.BigDecimal + booleanYjava.lang.Boolean.TYPE + byteYjava.lang.Byte.TYPE + bytesNbyte[] + charYjava.lang.Character.TYPE + charsNchar[] + clobNjava.sql.Clob + dateNjava.util.Date + doubleYjava.lang.Double.TYPE + floatYjava.lang.Float.TYPE + integerYjava.lang.Integer.TYPE + localeNjava.util.Locale + longYjava.lang.Long.TYPE + otherNjava.lang.Object + shortYjava.lang.Short.TYPE + stringNjava.lang.String + stringsNString[] + streamNjava.io.InputStream + + + + + + In addition, support for the following Castor-internal field types + has been added: + + + + + + + short name + Primitive type? + Java Class + + + + + duration + N + org.exolab.castor.types.Duration + + + + + +
+ +
+ SQL Dates and Default Timezones + + Castor will use the JDBC ResultSet.getDate(int, Calendar) + and related methods which take a Calendar object to specify the timezone of + the data retrieved from the database when the timezone information is not + already specified in the data; this ensures that the "current" + timezone is applied. + + + + The default time zone can be configured in the castor.properties file; + see the configuration section for details + on how to configure Castor with information about your default time zone. + + + + To change the timezone to a different timezone than the default, please + set a (different) value on the + org.exolab.castor.jdo.defaultTimeZone property: + + + +# Default time zone to apply to dates/times fetched from database fields, +# if not already part of the data. Specify same format as in +# java.util.TimeZone.getTimeZone, or an empty string to use the computer's +# local time zone. +org.exolab.castor.jdo.defaultTimeZone= +#org.exolab.castor.jdo.defaultTimeZone=GMT+8:00 + + +
+ +
+ SQL Type Conversion + + + Castor JDO uses the JDBC getObject/setObject methods + in order to retrieve and set fields. These methods do not perform + automatic type conversion, often resulting in unexpected behavior. + For example, when using a NUMERIC field with direct JDBC access, + application developers tend to call getInteger() + or getFloat(), but the Java object returned from + a call to getObject is often a + java.math.BigDecimal. + + + + Castor JDO implements automatic type conversion between Java and SQL. + For this mechanism to work, the mapping file must specify the SQL type + being used for Castor to employ the proper convertor. If no SQL type + is specified, no conversion will occur, possibly resulting in an + IllegalArgumentException being thrown. + + + + SQL types are specified with the + sql-type attribute using either + the default Java type returned by the JDBC driver + (e.g. java.lang.Integer or the proper SQL type name + (without precision). The following table lists the supported SQL type + names and the corresponding Java types: + + + + + + + SQL Type + Java Type + + + + bigint java.lang.Long + binary byte[] + bit java.lang.Boolean + blob java.io.InputStream + char java.lang.String + clob java.sql.Clob + decimal java.math.BigDecimal + double java.lang.Double + float java.lang.Double + integer java.lang.Integer + longvarbinarybyte[] + longvarchar java.lang.String + numeric java.math.BigDecimal + real java.lang.Float + smallint java.lang.Short + time java.sql.Time + timestamp java.sql.Timestamp + tinyint java.lang.Byte + varbinary byte[] + varchar java.lang.String + other java.lang.Object + javaobject java.lang.Object + + + + + + The following example illustrates how to specify SQL type in field mapping: + + + + + ]]> + + + Please note that java.util.Date is not automatically converted into a + java.sql.Date object; while it is in theory possible to do so, there + are three different possible storage formats for date information: + as a java.sql.Date, java.sql.Time, and java.sql.Timestamp. Rather than + impose a possibly inappropriate data mapping on an entry, no automatic + transformation will take place. + + + + JDBC drivers which do not, themselves, perform a mapping between + java.util.Date and the sql format specified on the database will throw + an error when java.util.Date is passed to them on the prepared + statement. Moreover, auto-conversion of java.util.Date is outside of + the JDBC specification; it is not a supported auto-convert format. + + + + Users wishing to store date information into the database should ensure + that they set date, time, or timestamp as the sql type on the + sql-type attribute. + + +
+ +
+ Parameterized Type Convertors + + + Some of the type convertors may have a string parameter, which changes + the conversion algorithm. The parameter is specified in square + brackets after the SQL type, for example: + + + + + ]]> + + + where "0" is the character value for + false and "1" is + the character value for true. + + + + In the above example the first of a bunch of parameterized type convertors + is used, "boolean --> char" convertor. The parameter must have length 2, + the first character is the value for false, + the second character is the value for true. + The default value is "FT". The actual SQL type should be char(1). + + + + The second and third convertors are "boolean --> integer" and + "boolean --> numeric". Its parameter must be + + for +1 or + - for -1 representing true. + False is always converted to 0. For example: + + + + + ]]> + + If the parameter is not specified, true is converted to +1. + + + The fourth convertor is "date --> char". Its parameter must be a correct + pattern for SimpleDateFormat. For example: + + + + + ]]> + + + If the parameter is not specified, the conversion is performed + using toString() method of the Date class. + + + + The fifth and the sixth convertors are "date --> integer" and + "date --> numeric". Their parameters are also patterns having syntax + based on the SimpleDateFormat syntax, but repeated characters are + eliminated. The following table shows the substitution rules that are + used to obtain the SimpleDateFormat pattern from the parameter. + + + + + + + Y,yyyyyyear + + + M MM month in year + + + D,ddd day in month + + + h,HHH hour in day (0~23) + + + m mm minute in hour + + + s ss second in minute + + + S SSS millisecond + + + + + + + For example, "YMD" parameter is expanded to "yyyyMMdd" SimpleDateFormat + pattern, "YMDhmsS" parameter is expanded to "yyyyMMddHHmmssSSS" + SimpleDateFormat pattern. The length of the expanded parameter gives + the minimal number of decimal digits that the actual SQL type must + support. The default value of the parameter is "YMD". + + + + The date and time types of org.exolab.castor.types package support 2 + timelines as defined by XML schema specification. One for timezoned values and one + for non-timezoned values which are treated to be local. When converting such types + to long the timezone information is lost. In most cases it is no problem to loose + for which timezone the value was specified if the value get converted to UTC time + before. But we also loose if the value had a timezone or not. This causes that + we do not know to which timeline the value belongs. If we just treat it as + non-timezoned value while it has been a timezoned one we have changed the value. + + + + Therefore we have added support for another parameterized type converter. This one + allows you to specify if the date and time values created out of a persisted long + value are meant to be timezoned or not. By default, without a parameter, local + date or time instances are created without a timezone. If you specify the parameter + utc in mapping the date or time values are created based on UTC timezone. + It need to be noted that such a mapping can only handle date and time values of one + of the 2 timelines defined by XML schema specification. Having said that this only + applies to the conversion of such values to long and does not cause issues when + converting to string and back. + + + + + ]]> + +
+ +
+ BLOB and CLOB Types + + + BLOB and CLOB stand for binary and character large objects (or in + Sybase, IMAGE and TEXT types, respectively). This means that most + likely you don't want to load the whole objects into memory, but + instead want to read and write them as streams. Usually these types are + not comparable via the WHERE clause of a SQL statement. + That is why you should disable dirty checking for such fields, e.g. + + + + + ]]> + + + In this example CLOB field will be read as a String. This may cause + OutOfMemoryError if the text is really large, but in many cases mapping + CLOB to String is acceptable. The advantage of mapping to String is + that we obtain a Serializable value that can be passed via RMI. + Similarly you can map BLOB and CLOB to byte[] and + char[] types, respectively: + + + + + + + + ]]> + + + Now, assume that mapping to String is not acceptable. The natural Java + type mapping for the BLOB type is java.io.InputStream, + and this mapping is supported by Castor: + + + + + ]]> + + + The natural Java type mapping for the CLOB type is + java.io.Reader, but this mapping is + not supported by Castor because + java.io.Reader doesn't provide information + about the length of the stream and this information is necessary + for JDBC driver (at least for the Oracle driver) to write the value to + the database. This is why the CLOB type is mapped to + java.sql.Clob: + + + + + ]]> + + + When you read data from the database, you can use the + getCharacterStream() method to obtain a + java.io.Reader from java.sql.Clob. + When you write data to the database, you can either use the helper class + org.exolab.castor.jdo.engine.ClobImpl to construct + java.sql.Clob from java.io.Reader + and the length: + + + + object.setClob(new ClobImpl(new FileReader(file), file.length()); + + + or implement the java.sql.Clob interface yourself. + + + + But be aware of the followng restriction: if you map BLOB to + java.io.InputStream or CLOB to + java.sql.Clob, then you should turn caching + off for the Java class containing those values, e.g.: + + + + + ... + + + + ]]> + + + Blob and Clob values cannot be cached, because they are alive only while + the ResultSet that produced them is open. In particular, this means + that you cannot use dirty checking for long transactions with such + classes. + +
+ +
\ No newline at end of file