Sun Java System Application Server Platform Edition 8 Developer's Guide |
Chapter 8
Using Container-Managed Persistence for Entity BeansThis section contains information on how container-managed persistence (CMP) works in the Sun Java System Application Server environment in the following topics:
Extensive information on CMP is contained in chapters 10, 11, and 14 of the Enterprise JavaBeans Specification, v2.1.
Sun Java System Application Server SupportSun Java System Application Server support for CMP includes:
- Full support for the J2EE v 1.4 specification’s CMP model.
- Support for commit options B and C for transactions as defined in the Enterprise JavaBeans Specification, v2.1. See “Commit Options” on page 303.
- The primary key class must be a subclass of java.lang.Object. This ensures portability, and is noted because some vendors allow primitive types (such as int) to be used as the primary key class.
- The Sun Java System Application Server CMP implementation, which provides:
- An Object/Relational (O/R) mapping tool that creates XML deployment descriptors for EJB JAR files that contain beans that use CMP
- Support for compound (multi-column) primary keys
- Support for sophisticated custom finder methods
- Standards-based query language (EJB QL)
- CMP runtime support. For a list of JDBC driver and database combinations that are supported for Sun Java System Application Server, see “Configurations for Specific JDBC Drivers” on page 364. These combinations have been tested with the Sun Java System Application Server and are found to be J2EE compatible. Other drivers have been used with Sun Java System Application Server, but J2EE compliance tests have not been completed with these drivers.
Container-Managed Persistence MappingImplementation for entity beans that use CMP is mostly a matter of mapping CMP fields and CMR fields (relationships) to the database. This section addresses the following topics:
The Mapping Deployment Descriptor File
Each module with CMP beans must have the following files:
- ejb-jar.xml: Contains information such as the transactional attributes of the beans and the fields of a bean that are going to be container-managed.
- sun-ejb-jar.xml: The Sun Java System Application Server standard file for assembling enterprise beans. For a detailed description, see “The sun-ejb-jar.xml File” on page 184.
- sun-cmp-mappings.xml: The file for mapping CMP. This file can be automatically generated and does not have to exist prior to deployment. For a detailed description, see “The sun-cmp-mappings.xml File” on page 225.
The sun-cmp-mappings.xml file maps CMP fields and CMR fields (relationships) to the database. A primary table must be selected for each CMP bean, and optionally, multiple secondary tables. CMP fields are mapped to columns in either the primary or secondary table(s). CMR fields are mapped to pairs of column lists (normally, column lists are the list of columns associated with pairs of primary and foreign keys).
The sun-cmp-mappings.xml file conforms to the sun-cmp-mapping_1_1.dtd file and is packaged with the user-defined bean classes in the EJB JAR file under the META-INF directory.
The Sun Java System Application Server or the deploytool creates the mappings in the sun-cmp-mappings.xml file automatically during deployment if the file is not present. For information on how to use the deploytool for mapping, see the deploytool online help.
Automatic generation of the sun-cmp-mappings.xml file can be controlled by deployment options specified in the sun-ejb-jar.xml file and during deployment (see Automatic Mapping Options). If you use automatic mapping, you only need to understand the Java programming language objects; you do not need to know or understand the underlying database schema.
You can map the fields and relationships of your entity beans manually, by editing the sun-cmp-mappings.xml deployment descriptor. You should only do this if you are proficient in editing XML.
A listing of the mapping elements in the CMP deployment descriptors is contained in “The sun-cmp-mappings.xml File” on page 225. A sample XML file is contained in “Sample Database Schema Definition” on page 233.
The mapping information is developed in conjunction with the database schema (.dbschema) file, which can be automatically captured when you deploy the bean (see Capturing the Database Schema Automatically). You can manually generate the schema using the capture-schema utility (Using the capture-schema Utility).
Mapping Capabilities
Mapping refers to the ability to tie an object-based model to a relational model of data, usually the schema of a relational database. The CMP implementation provides the ability to tie a set of interrelated beans containing data and associated behaviors to the schema. You can then use this object representation of the database as part of a Java application. You can also customize this mapping to optimize these beans for the particular needs of an application. The result is a single data model through which you can access both persistent database information and regular transient program data.
The mapping capabilities provided by the Sun Java System Application Server include:
Automatic Mapping Options
You can control automatic mapping in the following ways using deployment descriptor elements or command line options. You can:
The following optional data subelements of the cmp-resource element in the sun-ejb-jar.xml file control the automatic creation of database tables at deployment. For more information about the cmp-resource element, see Configuring the Resource Manager.
The following options of the asadmin deploy or asadmin deploydir command control the automatic creation of database tables at deployment:
If you have manually mapped one or more of the beans in the module and you use any of the asadmin deploy or asadmin deploydir options, the deployment is not harmed in any way, but the options have no effect, and you get a warning in the server log.
If you used the deploytool to map one or more of the beans, the --uniquetablenames option has no effect when you run asadmin deploy or asadmin deploydir. The uniqueness of the table names was established when deploytool created the mapping.
The following options of the asadmin undeploy command control the automatic removal of database tables at undeployment:
For more information about the asadmin deploy, asadmin deploydir, and asadmin undeploy commands, see “The asadmin Command” on page 107
When command line and sun-ejb-jar.xml options are both specified, the asadmin options take precedence.
Supported Data Types for Mapping
CMP supports a set of JDBC data types that are used in mapping Java data fields to SQL types. Supported JDBC data types are as follows:
BIGINT
BIT
BLOB
CHAR
CLOB
DATE
DECIMAL
DOUBLE
FLOAT
INTEGER
LONGVARBINARY
LONGVARCHAR
NUMERIC
REAL
SMALLINT
TIME
TIMESTAMP
TINYINT
VARCHAR
The following table contains suggested Java type to JDBC type mappings.
The following table contains suggested mappings of JDBC types to database vendor specific types. For more information about the JDBC driver and database combinations that are supported for Sun Java System Application Server, see “Configurations for Specific JDBC Drivers” on page 364.
Note
The mappings in Table 8-5 are suggested and not supported. If these mappings don’t work, please refer to your database and JDBC driver documentation.
BLOB Support
Binary Large Object (BLOB) is a data type used to store and retrieve complex object fields. BLOBs are binary or Serializable objects, such as pictures, that translate into large byte arrays which are then serialized into CMP fields.
If a CMP field is defined as Serializable, it is serialized into a byte[] before being stored in the database. Similarly, the value fetched from the database is deserialized. However, if a CMP field is defined as byte[], it is stored directly instead of being serialized and deserialized when stored and fetched, respectively.
To enable BLOB support in the Sun Java System Application Server environment, define a CMP field of type byte[] or a user-defined type that implements the java.io.Serializable interface. If you map the CMP bean to an existing database schema, map the field to a column of type BLOB.
If you are using the Oracle Inet driver for CMP, you need to set a special property if you are using BLOB or CLOB datatypes. For details, see “Inet Oraxo JDBC Driver for Oracle 8.1.7 and 9.x Databases” on page 366.
If you use automatic mapping, you might need to change the default BLOB column length for the generated schema using the schema-generator-properties element in sun-ejb-jar.xml. See your database vendor documentation to determine whether you need to specify the length. For example:
<schema-generator-properties>
<property>
<name>Employee.voiceGreeting.jdbc-type</name>
<value>BLOB</value>
</property>
<property>
<name>Employee.voiceGreeting.jdbc-maximum-length</name>
<value>10240</value>
</property>
...
</schema-generator-properties>CLOB Support
Character Large Object (CLOB) is a data type used to store and retrieve very long text fields. CLOBs translate into long strings.
To enable CLOB support in the Sun Java System Application Server environment, define a CMP field of type java.lang.String. If you map the CMP bean to an existing database schema, map the field to a column of type CLOB.
If you are using the Inet driver for CMP, you need to set a special property if you are using BLOB or CLOB datatypes. For details, see “Inet Oraxo JDBC Driver for Oracle 8.1.7 and 9.x Databases” on page 366.
If you use automatic mapping, you might need to change the default CLOB column length for the generated schema using the schema-generator-properties element in sun-ejb-jar.xml. See your database vendor documentation to determine whether you need to specify the length. For example:
<schema-generator-properties>
<property>
<name>Employee.resume.jdbc-type</name>
<value>CLOB</value>
</property>
<property>
<name>Employee.resume.jdbc-maximum-length</name>
<value>10240</value>
</property>
...
</schema-generator-properties>Capturing the Database Schema Automatically
You can configure a CMP bean in the deploytool or Sun Java System Application Server to automatically capture the database metadata and save it in a .dbschema file during deployment. If the sun-cmp-mappings.xml file contains an empty <schema/> entry, the cmp-resource entry in the sun-ejb-jar.xml file is used to get a connection to the database, and automatic generation of the schema is performed. When the sun-cmp-mappings.xml file is itself automatically generated, it contains the <schema/> entry by default. If the database table structure is changed, you must redeploy the beans to automatically remap the CMP fields and relationships.
Using the capture-schema Utility
You can use the capture-schema command to manually generate the database metadata (.dbschema) file.
Syntax
capture-schema -username name -password password -dburl url -driver jdbcdriver -out filename [-schemaname schemaname] [-table tablename]*
Where:
- -username name: Specifies the user name for authenticating access to a database.
- -password password: Specifies the password for accessing the selected database.
- -dburl url: Specifies the JDBC URL expected by the driver for accessing a database.
- -driver jdbcdriver: Specifies the JDBC driver class name. This class must be in your CLASSPATH.
- -out filename: Specifies the output target. If the output file name does not have an extension, .dbschema is appended. If the output file name has a different extension, .dbschema is appended in addition to the specified extension, and a warning is displayed.
Note
If more than one schema is accessible for this user, more than one table with the same name might be captured if this parameter is not set.
Example
capture-schema -dburl jdbc:pointbase:server://localhost:9092/sample -username public -password public -driver com.pointbase.jdbc.jdbcUniversalDriver -out RosterSchema.dbschema
Configuring the Resource ManagerThe resource manager used by the CMP implementation is PersistenceManagerFactory, which is configured using the Sun Java System Application Server XML file, domain.xml. Refer to the Sun Java System Application Server Administration Guide for information on creating a new persistence manager.
To deploy an EJB module that contains CMP beans, you need to specify the JNDI name of the Persistence Manager’s resource in the jndi-name subelement of the cmp-resource element in the sun-ejb-jar.xml file. The Persistence Manager’s resource is a jdbc-resource or persistence-manager-factory-resource entry in the domain.xml file. Using a jdbc-resource is recommended. This name is used at run time to manage persistent resources.
If the JNDI name refers to a jdbc-resource entry, you can also set PersistenceManagerFactory properties as properties of the cmp-resource element in the sun-ejb-jar.xml file.
For example, if you have the following entry in the domain.xml file:
<jdbc-resource
jndi-name="jdbc/pmf"
pool-name="jdbc/oracle_pool">Set the CMP resource in the sun-ejb-jar.xml file as follows:
<cmp-resource>
<jndi-name>jdbc/pmf</jndi-name>
</cmp-resource>For another example, if you have the following entry in the domain.xml file:
<persistence-manager-factory-resource
factory-class="com.sun.jdo.spi.persistence.support.sqlstore.impl.PersistenceManagerFactoryImpl"
enabled="true"
jndi-name="jdo/pmf"
jdbc-resource-jndi-name="jdbc/pmfPM">Set the CMP resource in the sun-ejb-jar.xml file as follows:
<cmp-resource>
<jndi-name>jdo/pmf</jndi-name>
</cmp-resource>
Configuring Queries for 1.1 FindersThis section contains the following topics:
About JDOQL Queries
The Enterprise JavaBeans Specification, v1.1 spec does not specify the format of the finder method description. The Sun Java System Application Server uses an extension of Java Data Objects Query Language (JDOQL) queries to implement finder and selector methods. For EJB 2.1, the container automatically maps an EJB QL query to JDOQL. For EJB 1.1, this mapping is done by the developer. You can specify the following elements of the underlying JDOQL query:
- Filter expression: A Java-like expression that specifies a condition that each object returned by the query must satisfy. Corresponds to the WHERE clause in EJB QL.
- Query parameter declaration: Specifies the name and the type of one or more query input parameters. Follows the syntax for formal parameters in the Java language.
- Query variable declaration: Specifies the name and type of one or more query variables. Follows the syntax for local variables in the Java language. Query variables might be used in the filter to implement joins.
- Query ordering declaration: Specifies the ordering expression of the query. Corresponds to the ORDER BY clause of EJBQL.
The Sun Java System Application Server-specific deployment descriptor (sun-ejb-jar.xml) provides the following elements to store the EJB 1.1 finder method settings:
The Sun Java System Application Server constructs a JDOQL query of the EJB 1.1 entity bean. It adds the filter, parameter declarations, and variable declaration and ordering as specified by the developer to the JDOQL query. It executes the query using the finder method parameters. The objects from the JDOQL query result set are converted into primary key instances to be returned by the EJB 1.1 ejbFind method.
The JDO specification (see JSR 12) provides a comprehensive description of JDOQL. The following information summarizes the elements used to define EJB 1.1 finders.
Query Filter Expression
The filter expression is a String containing a boolean expression evaluated for each instance of the candidate class. If the filter is not specified, it defaults to true. Rules for constructing valid expressions follow the Java language, with the following differences:
- Equality and ordering comparisons between primitives and instances of wrapper classes are valid.
- Equality and ordering comparisons of Date fields and Date parameters are valid.
- Equality and ordering comparisons of String fields and String parameters are valid.
- White space (non-printing characters space, tab, carriage return, and line feed) is a separator and is otherwise ignored.
- The following assignment operators are not supported:
- Methods, including object construction, are not supported, except for:
- Navigation through a null-valued field, which would throw NullPointerException, is treated as if the subexpression returned false.
The following expressions are supported:
- Parentheses to explicitly mark operator precedence
- Cast operator
- Promotion of numeric operands for comparisons and arithmetic operations. The rules for promotion follow the Java rules (see the numeric promotions of the Java language specification) extended by BigDecimal, BigInteger, and numeric wrapper classes.
Query Parameters
The parameter declaration is a String containing one or more parameter type declarations separated by commas. This follows the Java syntax for method signatures.
Query Variables
The type declarations follow the Java syntax for local variable declarations.
Example1
The following query returns all players called Michael. It defines a filter that compares the name field with a string literal:
name == "Michael"
The finder element of the sun-ejb-jar.xml file would look like this:
<finder>
<method-name>findPlayerByName</method-name>
<query-filter>name == "Michael"</query-filter>
</finder>Example 2
This query returns all products in a specified price range. It defines two query parameters which are the lower and upper bound for the price: double low, double high. The filter compares the query parameters with the price field:
low < price && price < high
Query ordering is set to price ascending.
The finder element of the sun-ejb-jar.xml file would look like this:
<finder>
<method-name>findInRange</method-name>
<query-params>double low, double high</query-params>
<query-filter>low < price && price < high</query-filter>
<query-ordering>price ascending</query-ordering>
</finder>Example 3
This query returns all players having a higher salary than the player with the specified name. It defines a query parameter for the name java.lang.String name. Furthermore, it defines a variable for the player to compare with. It has the type of the persistence capable class that corresponds to the bean:
mypackage.PlayerEJB_170160966_JDOState player
The filter compares the salary of the current player denoted by this keyword with the salary of the player with the specified name:
(this.salary > player.salary) && (player.name == name)
The finder element of the sun-ejb-jar.xml file would look like this:
<finder>
<method-name>findByHigherSalary</method-name>
<query-params>java.lang.String name</query-params>
<query-filter>
(this.salary > player.salary) && (player.name == name)
</query-filter>
<query-variables>mypackage.PlayerEJB_170160966_JDOState player</query-variables>
</finder>
Restrictions and OptimizationsThis section discusses any restrictions and performance optimizations you should be aware of in using CMP entity beans.
Eager Loading of Field State
By default, the EJB container loads the state for all CMP fields (except BLOB and CLOB fields) before invoking the ejbLoad method of the abstract bean. This approach may not be optimal for entity objects with large state if most business methods require access to only parts of the state. If this is an issue, use the fetched-with element in sun-cmp-mappings.xml for fields that are used infrequently.
Restrictions on Remote Interfaces
The following restrictions apply to the remote interface of an entity bean that uses CMP:
Dependent value classes can be exposed in the remote interface or remote home interface, and can be included in the client EJB JAR file.
Sybase Finder Limitation
If you execute any finder method with an input greater than 255 characters and map the primary key column to a VARCHAR column, Sybase attempts to convert type VARCHAR to type TEXT and generates the following error:
com.sybase.jdbc2.jdbc.SybSQLException: Implicit conversion from datatype 'TEXT' to 'VARCHAR' is not allowed. Use the CONVERT function to run this query.
To avoid this error, make sure your finder method input is less than 255 characters.
Date and Time Fields as CMP Field Types
If a CMP field type is a Java date or time type (java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp), make sure that the field value exactly matches the value in the database.
For example, the following code uses a java.sql.Date type as a primary key field:
java.sql.Date myDate = new java.sql.Date(System.currentTimeMillis())
beanHome.create(myDate, ...);For some databases, this code results in only the year, month, and date portion of the field value being stored in the database. Later on if the client tries to find this bean by primary key as follows:
myBean = beanHome.findByPrimaryKey(myDate);
the bean is not found in the database because the value does not match the one that is stored in the database.
Similar problems can happen if the database truncates the timestamp value while storing it, or if a custom query has a date or time value comparison in its WHERE clause.
When you use automatic mapping and an Oracle database, all fields of type java.util.Date, java.sql.Date, java.sql.Time, and java.sql.Timestamp are mapped to Oracle’s DATE data type.