|
How To / Creating a Domain Object |
This covers the basics of writing a domain object, the base class to use, the
getters/setters and the validate and update methods. It also covers using and writing the
meta data class, as well as setting up the JDBCEngine mapping file.
Contents
- Domain Class
- Meta Class
- Configuring the JDBC Engine
- Creating the Mapping File
- Setting Up init.xml
- Complete Code Example
- Example Domain Object Class
- The Meta Data Class
- JDBCEngine Mapping
- JDBCEngine Config
|
Domain Class |
A domain class encapsulates persistent data. Each table in the database will have a
corresponding domain class. The business classes will create instances of this class,
which will be transparently converted, by the persistence engine, into new rows in
the database. Queries to the persistence engine will return instances of the appropriate
domain class for each retrieved row of data
- A domain class should extend the abstract class org.jaffa.persistence.Persistent
- It may provide functionality for the preAdd, preUpdate, preDelete and postLoad triggers
- It should have getXxx/setXxx/updateXxx/validateXxx methods for each field
- The getXxx and setXxx methods should be similar to regular javabean getter/setter methods
Example |
public java.lang.String getPart() {
return m_part;
}
public void setPart(java.lang.String part) {
m_part = part;
}
|
- The validateXxx method should utilise the meta class for validating a field. It can be
enhanced with appropriate business logic
Example |
public void validatePart(java.lang.String part) throws ValidationException {
FieldValidator.validate(part, (StringFieldMetaData) PartMeta.META_PART, true);
// add additional logic
}
|
- The updateXxx methods should invoke the validateXxx methods to perform basic validations, and then invoke the update method of the base class and finally invoke the setXxx method to set the data
Header |
public void updatePart(java.lang.String part) throws ValidationException, ReadOnlyObjectException, AlreadyLockedObjectException {
// Uncomment the following if the field is part of the primary key
//if (isDatabaseOccurence())
// return;
validatePart(part);
super.update();
setPart(part);
}
|
- The update method of the base class provides the following capabilities
- ensures that a read-only object is never modified
- locks the database data, if cautious locking strategy is specified
- sets the modified flag on the domain object
Notes
The setXxx method of the domain object is only to be invoked by the persistence engine, to pass values from the database
The business class which creates/updates/retrieves a domain object, should never invoke the setXxx method; it should
invoke the updateXxx methods instead
|
Domain Meta Class |
- Each domain class will have a corresponding meta class. For eg, the Part class will have PartMeta as the meta class
- A meta class should have the meta data information for each field of the domain object. This may include -
- The name of the field to be used in queries
- The token for getting the appropriate label from the resource bundle
- The data type
- Is the field mandatory
- The layout to be used for displaying the contents
- The pattern against which the contents will be validated
- The case type
- The length of the field
- The minimum and maximum values
- The validateXxx method of the domain class should utilise the meta data information for validations
- The presentation tier should utilise the label-token for a field, to display the appropriate label from the resource bundle
|
Configuring the JDBC Engine |
This next section is specific to the use of the JDBCEngine as the persitence layer's plug-in
engine. The mapping and configuration for a domain object will change for other engines.
- Creating The Mapping File
- Each domain class should have a corresponding xml based mapping file. For eg. the Part domain class should have a mapping file Part.xml
- The mapping file maps the fields of the domain class to the fields in the database table
- The file should reside in the search path specified in the init.xml
- The mapping file should specify the domain class
- It should list all the fields, providing the database field name, domain class field name, data type, isPrimaryKey
- Setting Up init.xml
- The init.xml has the configuration parameters for the persistence engine
- There will be only one such file in the application
- This file should reside in the location specified in the 'framework.persistence.jdbcengine.init' property of framework.properties
- It can have multiple database definitions. Although, for now, only one database definition (name = "default") is supported
- The database definition should include the information required to connect to the database. This includes the driver, connect url, user, password
- The database definition should include the hitlistsize. Data will be fetched in increments of this value
- The database definition should include values for minimum-connections and maximum-connections. These control the connection pool
- The preload element may be specified. It should consist of the most widely used domain classes. The persistence engine will parse these classes on initialization. It is mainly for efficiency purposes
- The conf-location element should list the paths (relative to the classpath) to be used for searching the mapping files
|
Complete Code Example |
- Example Domain Object Class
Part.java |
package org.jaffa.persistence.domainobjects;
import org.jaffa.persistence.Persistent;
import org.jaffa.datatypes.ValidationException;
import org.jaffa.datatypes.FieldValidator;
import org.jaffa.metadata.*;
import org.jaffa.persistence.exceptions.*;
/**
*
* @author Auto-Generated
* @version
*/
public class Part extends Persistent {
/** Holds value of property part. */
private java.lang.String part;
/** Holds value of property noun. */
private java.lang.String noun;
/** Holds value of property categoryInstrument. */
private java.lang.String categoryInstrument;
/** Getter for property part.
* @return Value of property part.
*/
public java.lang.String getPart() {
return part;
}
/** Setter for property part.
* WARNING: This is strictly for use by the Persistence Engine. A developer should never use this method. Instead, use the update(field.Name.Upper1) method.
* @param part New value of property part.
*/
public void setPart(java.lang.String part) {
this.part = part;
}
/** Use this method to update the property part. Validation will be performed on the input value.
* @param part New value of property part.
* @throws ValidationException if an invalid value is passed
*/
public void updatePart(java.lang.String part)
throws ValidationException
, ReadOnlyObjectException, AlreadyLockedObjectException {
super.update();
validatePart(part);
setPart(part);
}
/** Use this method to validate a value for the property part.
* @param part Value to be validated for the property part.
* @throws ValidationException if an invalid value is passed
*/
public void validatePart(java.lang.String part)
throws ValidationException {
FieldValidator.validate(part, (StringFieldMetaData) PartMeta.META_PART, true);
}
/** Getter for property noun.
* @return Value of property noun.
*/
public java.lang.String getNoun() {
return noun;
}
/** Setter for property noun.
* WARNING: This is strictly for use by the Persistence Engine. A developer should never use this method. Instead, use the update(field.Name.Upper1) method.
* @param noun New value of property noun.
*/
public void setNoun(java.lang.String noun) {
this.noun = noun;
}
/** Use this method to update the property noun. Validation will be performed on the input value.
* @param noun New value of property noun.
* @throws ValidationException if an invalid value is passed
*/
public void updateNoun(java.lang.String noun)
throws ValidationException
, ReadOnlyObjectException, AlreadyLockedObjectException {
super.update();
validateNoun(noun);
setNoun(noun);
}
/** Use this method to validate a value for the property noun.
* @param noun Value to be validated for the property noun.
* @throws ValidationException if an invalid value is passed
*/
public void validateNoun(java.lang.String noun)
throws ValidationException {
FieldValidator.validate(noun, (StringFieldMetaData) PartMeta.META_NOUN, true);
}
/** Getter for property categoryInstrument.
* @return Value of property categoryInstrument.
*/
public java.lang.String getCategoryInstrument() {
return categoryInstrument;
}
/** Setter for property categoryInstrument.
* WARNING: This is strictly for use by the Persistence Engine. A developer should never use this method. Instead, use the update(field.Name.Upper1) method.
* @param categoryInstrument New value of property categoryInstrument.
*/
public void setCategoryInstrument(java.lang.String categoryInstrument) {
this.categoryInstrument = categoryInstrument;
}
/** Use this method to update the property categoryInstrument. Validation will be performed on the input value.
* @param categoryInstrument New value of property categoryInstrument.
* @throws ValidationException if an invalid value is passed
*/
public void updateCategoryInstrument(java.lang.String categoryInstrument)
throws ValidationException
, ReadOnlyObjectException, AlreadyLockedObjectException {
super.update();
validateCategoryInstrument(categoryInstrument);
setCategoryInstrument(categoryInstrument);
}
/** Use this method to validate a value for the property categoryInstrument.
* @param categoryInstrument Value to be validated for the property categoryInstrument.
* @throws ValidationException if an invalid value is passed
*/
public void validateCategoryInstrument(java.lang.String categoryInstrument)
throws ValidationException {
FieldValidator.validate(categoryInstrument, (StringFieldMetaData) PartMeta.META_CATEGORY_INSTRUMENT, true);
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("<Part>");
buf.append("<part>"); if (part != null) buf.append(part); buf.append("</part>");
buf.append("<noun>"); if (noun != null) buf.append(noun); buf.append("</noun>");
buf.append("<categoryInstrument>"); if (categoryInstrument != null) buf.append(categoryInstrument); buf.append("</categoryInstrument>");
buf.append("</Part>");
return buf.toString();
}
}
|
- The Meta Data Class
PartMeta.java |
package org.jaffa.persistence.domainobjects;
import org.jaffa.metadata.*;
import java.util.*;
public class PartMeta {
// domain-object class name
private static String m_name = "org.jaffa.persistence.domainobjects.Part";
// token to be used for getting the label for the domain-object
private static String m_labelToken = "";
// Field constants
public static final String PART = "Part";
public static final String NOUN = "Noun";
public static final String CATEGORY_INSTRUMENT = "CategoryInstrument";
// Step4: Meta Data Definitions
public static final FieldMetaData META_PART =
new StringFieldMetaData(PART, "PART",Boolean.TRUE
, null, null, null);
public static final FieldMetaData META_NOUN =
new StringFieldMetaData(NOUN, "NOUN",Boolean.FALSE
, null, null, null);
public static final FieldMetaData META_CATEGORY_INSTRUMENT =
new StringFieldMetaData(CATEGORY_INSTRUMENT, "CATEGORY_INSTRUMENT",Boolean.FALSE
, null, null, null);
// Map of FieldConstants + MetaDataDefinitions
private static Map m_fieldMap = new HashMap();
static {
m_fieldMap.put(PART, META_PART);
m_fieldMap.put(NOUN, META_NOUN);
m_fieldMap.put(CATEGORY_INSTRUMENT, META_CATEGORY_INSTRUMENT);
}
/** Returns the name of the persistent class.
* @return the name of the persistent class.
*/
public static String getName() {
return m_name;
}
/** Getter for property labelToken.
* @return Value of property labelToken.
*/
public static String getLabelToken() {
return m_labelToken;
}
/** This returns an array of all the fields of the persistent class.
* @return an array of all the fields of the persistent class.
*/
public static String[] getAttributes() {
return DomainMetaDataHelper.getAttributes(m_fieldMap);
}
/** This returns an array of meta information for all the fields of the persistent class.
* @return an array of meta information for all the fields of the persistent class.
*/
public static FieldMetaData[] getFieldMetaData() {
return DomainMetaDataHelper.getFieldMetaData(m_fieldMap);
}
/** This returns meta information for the input field.
* @param fieldName the field name.
* @return meta information for the input field.
*/
public static FieldMetaData getFieldMetaData(String fieldName) {
return DomainMetaDataHelper.getFieldMetaData(m_fieldMap, fieldName);
}
}
|
- The JDBCEngine Mapping
Part.xml |
<classmap>
<class name="org.jaffa.persistence.domainobjects.Part">
<map-to table="TEST_PART" />
<field name="Part" type="java.lang.String" primary-key="true">
<sql name="PART" type="varchar" dirty="ignore"/>
</field>
<field name="Noun" type="java.lang.String">
<sql name="DESCRIPTION" type="varchar" dirty="ignore"/>
</field>
<field name="CategoryInstrument" type="java.lang.String">
<sql name="CATEGORY_INSTRUMENT" type="varchar" dirty="ignore"/>
</field>
</class>
</classmap>
|
- JDBCEngine Config
init.xml |
<init>
<database name="default" engine="oracle">
<driver url="jdbc:oracle:thin:@host.domain.com:1521:rnd"
class="oracle.jdbc.driver.OracleDriver"/>
<param name="user" value="dummy"/>
<param name="password" value="dummy"/>
<param name="hitlistSize" value="10"/>
<param name="minimumConnections" value="5"/>
<param name="maximumConnections" value="25"/>
<param name="logFileName" value="DbConnectionBroker.log"/>
</database>
<preload>
<class name="org.jaffa.persistence.domainobjects.Condition"/>
</preload>
<conf-location>
<dir-loc dir="jdbcengine"/>
<dir-loc dir="org.jaffa.persistence.mappingfiles"/>
</conf-location>
</init>
|
This example has been taken from the Jaffa Persistence Layer Unit Tests.
|
|