CMP fields are declared on the bean class as abstract getter and setter methods that follow the JavaBean property accessor conventions. The gangster bean, for example, has a getName() method and a setName() method for accessing the name CMP field. The following sections look at how to configure these declared CMP fields and control the persistence and behavior. CMP Field DeclarationThe declaration of a CMP field starts in the ejb-jar.xml file. On the gangster bean, for example, the gangsterId, name, nickName, and badness are declared in the ejb-jar.xml file as follows: <ejb-jar> <enterprise-beans> <entity> <ejb-name>GangsterEJB</ejb-name> <cmp-field><field-name>gangsterId</field-name></cmp-field> <cmp-field><field-name>name</field-name></cmp-field> <cmp-field><field-name>nickName</field-name></cmp-field> <cmp-field><field-name>badness</field-name></cmp-field> </entity> </enterprise-beans> </ejb-jar> Note that the J2EE deployment descriptor doesn't declare any object-relational mapping details or other configuration. It is nothing more than a simple declaration of the CMP fields. CMP Field Column MappingYou do the relational mapping configuration of a CMP field in the jbosscmp-jdbc.xml file. The structure is similar to that of the ejb-jar.xml file, with an entity element that has cmp-field elements under it, with the additional configuration details. The following shows the basic column name and data type mappings for the gangster bean: <jbosscmp-jdbc> <enterprise-beans> <entity> <ejb-name>GangsterEJB</ejb-name> <table-name>gangster</table-name> <cmp-field> <field-name>gangsterId</field-name> <column-name>id</column-name> </cmp-field> <cmp-field> <field-name>name</field-name> <column-name>name</column-name> <not-null/> </cmp-field> <cmp-field> <field-name>nickName</field-name> <column-name>nick_name</column-name> <jdbc-type>VARCHAR</jdbc-type> <sql-type>VARCHAR(64)</sql-type> </cmp-field> <cmp-field> <field-name>badness</field-name> <column-name>badness</column-name> </cmp-field> </entity> </enterprise-beans> </jbosscmp-jdbc> The full content model of the cmp-field element of the jbosscmp-jdbc.xml is shown in Figure 11.4. Figure 11.4. The JBoss entity element content model.
Detailed descriptions of the entity elements follow:
Read-only FieldsJBoss allows you to have read-only CMP fields by setting the read-only and read-time-out elements in the cmp-field declaration. These elements work the same way as they do at the entity level. If a field is read-only, it will never be used in an INSERT or UPDATE statement. If a primary key field is read-only, the create method will throw a CreateException. If a set accessor is called for a read-only field, it throws an EJBException. Read-only fields are useful for fields that are filled in by database triggers, such as last update. A read-only CMP field declaration example follows: <jbosscmp-jdbc> <enterprise-beans> <entity> <ejb-name>GangsterEJB</ejb-name> <cmp-field> <field-name>lastUpdated</field-name> <read-only>true</read-only> <read-time-out>1000</read-time-out> </cmp-field> </entity> </enterprise-beans> </jbosscmp-jdbc> Auditing Entity AccessThe audit element of the entity section allows you to specify how access to an entity bean is audited. Auditing is allowed only when an entity bean is accessed under a security domain so that the caller identity is established. The content model of the audit element is shown in Figure 11.5. Figure 11.5. The jbosscmp-jdbc.xml audit element content model.
The supported elements are as follows:
For each element, if a field-name is given, the corresponding audit information should be stored in the specified CMP field of the entity bean being accessed. Note that there does not have to be a corresponding CMP field declared on the entity. If there are matching field names, you can access audit fields in the application by using the corresponding CMP field abstract getters and setters. Otherwise, the audit fields are created and added to the entity internally. You can access audit information in EJB-QL queries, using the audit field names but not directly through the entity accessors. If, on the other hand, a column-name is specified, the corresponding audit information should be stored in the indicated column of the entity table. If JBoss is creating the table, you can use the jdbc-type and sql-type element to define the storage type. The following code shows the declaration of audit information with given column names: <jbosscmp-jdbc> <enterprise-beans> <entity> <ejb-name>AuditChangedNamesEJB</ejb-name> <table-name>cmp2_audit_changednames</table-name> <audit> <created-by> <column-name>createdby</column-name> </created-by> <created-time> <column-name>createdtime</column-name> </created-time> <updated-by> <column-name>updatedby</column-name></updated-by> <updated-time> <column-name>updatedtime</column-name> </updated-time> </audit> </entity> </enterprise-beans> </jbosscmp-jdbc> Dependent Value ClassesDependent value class (DVC) is a fancy term used to identity any Java class that is the type of a cmp-field and is not one of automatically recognized core types, such as strings and number values. By default, a DVC is serialized, and the serialized form is stored in a single database column. Although not discussed here, there are several known issues with the long-term storage of classes in serialized form. JBoss also supports the storage of the internal data of a DVC in one or more columns. This storage is useful for supporting legacy JavaBeans and database structures. It is not uncommon to find a database with a highly flattened structure (for example, a PURCHASE_ORDER table with the fields SHIP_LINE1, SHIP_LINE2, SHIP_CITY, and so on, and an additional set of fields for the billing address). Other common database structures include telephone numbers with separate fields for area code, exchange, and extension and a person's name spread across several fields. With a DVC, multiple columns can be mapped to one logical field. JBoss requires that a DVC to be mapped follow the JavaBeans naming specification for simple properties and that each property to be stored in the database have both a getter and a setter method. Furthermore, the bean must be serializable and must have a no-arg constructor. A property can be any simple type, and it can be an unmapped DVC or a mapped DVC, but it cannot be an EJB. A DVC mapping is specified in a dependent-value-class element within the dependent-value-classes element. Figure 11.6 shows the structure jbosscmp-jdbc element. Figure 11.6. The jbosscmp-jdbc dependent-value-class element model.Here is an example of a simple ContactInfo DVC class: public class ContactInfo implements Serializable { /** The cell phone number. */ private PhoneNumber cell; /** The pager number. */ private PhoneNumber pager; /** The email address */ private String email; /** * Creates empty contact info. */ public ContactInfo() { } public PhoneNumber getCell() { return cell; } public void setCell(PhoneNumber cell) { this.cell = cell; } public PhoneNumber getPager() { return pager; } public void setPager(PhoneNumber pager) { this.pager = pager; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email.toLowerCase(); } // ... equals, hashCode, toString } The contact info includes a phone number, which is represented by another DVC class: public class PhoneNumber implements Serializable { /** The first three digits of the phone number. */ private short areaCode; /** The middle three digits of the phone number. */ private short exchange; /** The last four digits of the phone number. */ private short extension; // ... getters and setters // ... equals, hashCode, toString } The DVC mappings for these two classes are relatively straightforward: <dependent-value-classes> <dependent-value-class> <description>A phone number</description> <class>org.jboss.cmp2.crimeportal.PhoneNumber</class> <property> <property-name>areaCode</property-name> <column-name>area_code</column-name> </property> <property> <property-name>exchange</property-name> <column-name>exchange</column-name> </property> <property> <property-name>extension</property-name> <column-name>extension</column-name> </property> </dependent-value-class> <dependent-value-class> <description>General contact info</description> <class>org.jboss.cmp2.crimeportal.ContactInfo</class> <property> <property-name>cell</property-name> <column-name>cell</column-name> </property> <property> <property-name>pager</property-name> <column-name>pager</column-name> </property> <property> <property-name>email</property-name> <column-name>email</column-name> <jdbc-type>VARCHAR</jdbc-type> <sql-type>VARCHAR(128)</sql-type> </property> </dependent-value-class> </dependent-value-classes> Each DVC is declared with a dependent-value-class element. A DVC is identified by the Java class type declared in the class element. Each property to be persisted is declared with a property element. This specification is based on the cmp-field element, so it should be self-explanatory. (This restriction will be removed in a future release.) The current proposal involves storing the primary key fields in the case of a local entity and the entity handle in the case of a remote entity. The dependent-value-class section defines the internal structure and default mapping of the classes. When JBoss encounters a field that has an unknown type, it searches the list of registered DVCs, and if a DVC is found, it persists that field into a set of columns; otherwise, the field is stored in serialized form in a single column. JBoss does not support inheritance of DVCs; therefore, this search is only based on the declared type of the field. A DVC can be constructed from other DVCs, so when JBoss runs into a DVC, it flattens the DVC tree structure into a set of columns. If JBoss finds a DVC circuit during startup, it throws an EJBException. The default column name of a property is the column name of the base cmp-field, followed by an underscore and then the column name of the property. If the property is a DVC, the process is repeated. For example, a cmp-field named info that uses the ContactInfo DVC would have the following columns: info_cell_area_code info_cell_exchange info_cell_extension info_pager_area_code info_pager_exchange info_pager_extension info_email The automatically generated column names can quickly become excessively long and awkward. You can override the default mappings of columns in the entity element, as follows: <jbosscmp-jdbc> <enterprise-beans> <entity> <ejb-name>GangsterEJB</ejb-name> <cmp-field> <field-name>contactInfo</field-name> <property> <property-name>cell.areaCode</property-name> <column-name>cell_area</column-name> </property> <property> <property-name>cell.exchange</property-name> <column-name>cell_exch</column-name> </property> <property> <property-name>cell.extension</property-name> <column-name>cell_ext</column-name> </property> <property> <property-name>pager.areaCode</property-name> <column-name>page_area</column-name> </property> <property> <property-name>pager.exchange</property-name> <column-name>page_exch</column-name> </property> <property> <property-name>pager.extension</property-name> <column-name>page_ext</column-name> </property> <property> <property-name>email</property-name> <column-name>email</column-name> <jdbc-type>VARCHAR</jdbc-type> <sql-type>VARCHAR(128)</sql-type> </property> </cmp-field> </entity> </enterprise-beans> </jbosscmp-jdbc> When overriding property information for the entity, you need to refer to the property from a flat perspective, as in cell.areaCode. |