Skip Headers

Oracle9iAS TopLink Foundation Library Guide
Release 2 (9.0.3)

Part Number B10064-01
Go To Documentation Library
Home
Go To Solution Area
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

8
Descriptor Implementation

A descriptor is a TopLink object that describes how an object's attributes and relationships are to be represented in relational database table(s). A "TopLink descriptor" is not the same as an "EJB deployment descriptor", although it plays a similar role.

Most descriptors can be created in the Mapping Workbench, but you may also have reasons to specify them in native Java code. This chapter illustrates

Implementing primary keys in Java

If a single field constitutes the primary key, send the setPrimaryKeyFieldName() message to the descriptor. For a composite primary key, send the addPrimaryKeyFieldName() message for each field that makes up the primary key.

Alternatively, you could use a convenience method, setPrimaryKeyFieldNames( ), sending a Vector of the fields used as the primary key.

Example 8-1 Setting a single-field primary key in Java.

// Define a new descriptor and set the primary key.
descriptor.setPrimaryKeyFieldName("ADDRESS_ID");

Example 8-2 Setting a composite primary key in Java.

// Define a new descriptor and set the primary key.
descriptor1.addPrimaryKeyFieldName("PHONE_NUMBER");
descriptor1.addPrimaryKeyFieldName("AREA_CODE");

Implementing inheritance in Java

To implement an inheritance hierarchy completely in Java, you must modify the descriptors for the superclass and its subclasses. The inheritance implementation for a descriptor is encapsulated in an InheritancePolicy object, which is accessed by sending getInheritancePolicy() to the descriptor.

Queries for inherited superclasses can require multiple queries to obtain all of the rows for all of the subclasses. This is only required if the superclass is configured to read subclasses and its subclasses define additional tables. This situation can be optimized by providing TopLink with a view to execute the query against. This view can internally perform an outer join or union on all of the subclass tables and return a single result set with all of the data. This view can be set through the setReadAllSubclassesViewName() method.

Using TopLink's default inheritance mechanism may not always be possible. In this case the inheritance mechanism can be further customized. Instead of using a class indicator field and mapping, a class extraction method may be used. This method takes the objects row and returns the class to be used for that row. The setClassExtractionMethodName() method is used to accomplish this.

Normally queries for inherited classes also require filtering of the tables rows; by default, TopLink generates this from the class indicator information. However, if the class extraction method is given, the filtering expressions must be specified. These can be set for concrete classes through setOnlyInstancesExpression() and for branch classes through setWithAllSubclassesExpression().

Figure 8-1 shows an example of an inheritance hierarchy. The Vehicle-Bicycle branch demonstrates how all subclass information can be stored in one table. The FueledVehicle-Car branch demonstrates how subclass information can be stored in two tables.

Figure 8-1 Inheritance hierarchy

Text description of inhrtnc.gif follows.

Text description of the illustration inhrtnc.gif

The Car and Bicycle classes are leaf classes, so queries done on them return instances of Car and Bicycle respectively.

FueledVehicle is a branch class. By default, branch classes are configured to read instances and subclass instances. Queries for FueledVehicle return instances of FueledVehicle and also return instances of Car.

NonFueledVehicle is a branch class and is configured to read subclasses. Because it does not have a class indicator defined in the root, it cannot be written to the database. Queries done on NonFueledVehicle return instances of its subclasses.

Vehicle is a root class, which is configured to read instances of itself and instances of its subclass by default. Queries made on the Vehicle class return instances of any of the concrete classes in the hierarchy.

Example 8-3 Implementing descriptors for the different classes in the inheritance hierarchy.

// Vehicle is a root class. Because it is the root class, it must add the class 
indicators for its subclasses.
public static Descriptor descriptor()
{
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Vehicle.class);
descriptor.setTableName("VEHICLE");
descriptor.setPrimaryKeyFieldName("ID");

// Class indicators must be supplied for each of the subclasses in the hierarchy 
that can have instances.
InheritancePolicy policy = descriptor.getInheritancePolicy();
policy.setClassIndicatorFieldName("TYPE");
policy.addClassIndicator(FueledVehicle.class, "Fueled");
policy.addClassIndicator(Car.class, "Car");
policy.addClassIndicator(Bicycle.class, "Bicycle");

descriptor.addDirectMapping("id", "ID");
descriptor.addDirectMapping("passengerCapacity", "CAP");

return descriptor;
}

// FueledVehicle descriptor; it is a branch class and a subclass of Vehicle. 
Queries made on this class will return instances of itself and instances of its 
subclasses.
public static Descriptor descriptor()
{
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(FueledVehicle.class);
descriptor.addTableName("FUEL_VEH");
descriptor.getInheritancePolicy().setParentClass(Vehicle.class);
descriptor.addDirectMapping("fuelCapacity", "FUEL_CAP");
descriptor.addDirectMapping("fuelType", "FUEL_TYPE");
return descriptor;
}

// Car descriptor; it is a leaf class and subclass of FueledVehicle.
public static Descriptor descriptor()
{
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Car.class);
descriptor.addTableName("CAR");
descriptor.getInheritancePolicy().setParentClass(FueledVehicle.class);

// Next define the attribute mappings.
descriptor.addDirectMapping("description", "DESCRIP");
descriptor.addDirectMapping("fuelType", "FUEL_VEH.FUEL_TYPE");
return descriptor;
}

// NonFueledVehicle descriptor; it is a branch class and a subclass of Vehicle. 
Queries made on this class will return instances of its subclasses.
public static Descriptor descriptor()
{
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(NonFueledVehicle.class);
descriptor.getInheritancePolicy().setParentClass(Vehicle.class);
return descriptor;
}

// Bicycle descriptor; it is a leaf class and subclass of NonFueledVehicle. 
public static Descriptor descriptor()
{
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Bicycle.class);
descriptor.getInheritancePolicy().setParentClass(NonFueledVehicle.class);
descriptor.addDirectMapping("description", "BICY_DES");
return descriptor;
}

// FueledVehicle class; If a class extraction method is used, the following 
would need to be added to specify that only the branch class itself needs to be 
returned. This example is just specifying the class indicator field, which can 
also be specified in Mapping Workbench in the Descriptor Advanced Properties 
dialog.
public void addToDescriptor(Descriptor descriptor) 
{
ExpressionBuilder builder = new ExpressionBuilder();
descriptor.getInheritancePolicy().setOnlyInstancesExpression(builder.getField("V
EHICLE.TYPE").equal("F"));
}

// FueledVehicle class; If a class extraction method is used, the following 
would need to be added to specify that the branch class and its subclasses need 
to be returned. This example can also be specified in Mapping Workbench in the 
Descriptor Advanced Properties dialog.
public void addToDescriptor (Descriptor descriptor)
{
ExpressionBuilder builder = new ExpressionBuilder();
descriptor.getInheritancePolicy().withAllSubclassesExpression(builder.getField("
VEHICLE.TYPE").equal("F"));
}

Reference

Table 8-1 summarizes the most common public methods for InheritancePolicy:

For a complete description of all available methods for InheritancePolicy, see the TopLink JavaDocs.

Table 8-1 Elements for the inheritance policy  
Element Default Method Names

Class indicators

use indicator mapping

setClassIndicatorFieldName 
(String fieldName)

Parent classes

not applicable

setParentClass(Class parentClass)

Implementing interfaces in Java

Descriptors can their own parent interfaces. They can set multiple interfaces if they have implemented multiple interfaces. The query keys are defined in a normal way except that they must define the abstract query key from the interface descriptor in their descriptors. An abstract query key on the interface descriptor enables it to write expression queries on the interface.

Example 8-4 Using an abstract query key on the interface descriptor.

ExpressionBuilder contact = new 
ExpressionBuilder();session.readObject(Contact.class, 
contact.get("id").equal(2));

Setting the copy policy using Java

The Descriptor class provides three methods that can be used to determine how an object is cloned:

Implementing multiple tables in Java code

To define a multiple table descriptor, call the addTableName() method for each table the descriptor maps to. If the descriptor inherits its primary table and is only defining a single additional one, then the descriptor is mapped normally to this table.

Primary keys match

Normally the primary key is defined only for the primary table of the descriptor. The primary table is the first table specified through addTableName(). The primary key is not defined for the additional tables and is required to be the same as in the primary table. If the additional table's key is different, refer to the next example.

By default, all the fields in a mapping are assumed to be part of the primary table. If a mapping's field is for one of the additional tables it must be fully qualified with the field's table name.

Example 8-5 Implementing a multiple table descriptor where the primary keys match.

//Define a new descriptor that uses three tables.
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
descriptor.addTableName("PERSONNEL"); // Primary table
descriptor.addTableName("EMPLOYMENT");
descriptor.addTableName("USERS");

descriptor.addPrimaryKeyFieldName("PER_NUMBER");
descriptor.addPrimaryKeyFieldName("DEP_NUMBER");

descriptor.addDirectMapping("id", "PER_NUMBER");
descriptor.addDirectMapping("firstName", "F_NAME");
descriptor.addDirectMapping("lastName", "L_NAME");

OneToOneMapping department = new OneToOneMapping();
department.setAttributeName("department");
department.setReferenceClass(Department.class);
department.setForeignKeyFieldName("DEP_NUMBER");
descriptor.addMapping(department);
// Mapping the primary key fields in the additional tables is not required
descriptor.addDirectMapping("salary", "EMPLOYMENT.SALARY");

AggregateObjectMapping period = new AggregateObjectMapping();
period.setAttributeName(period);
period.setReferenceClass(EmployementPeriod.class);
period.addFieldNameTranslation("EMPLOYMENT.S_DATE", "S_DATE");
period.addFieldNameTranslation("EMPLOYMENT.E_DATE", "E_DATE");
descriptor.addMapping(period);

descriptor.addDirectMapping("userName", "USERS.NAME");
descriptor.addDirectMapping("password", "USERS.PASSWORD");

Primary keys are named differently

If the additional tables primary key is named differently then call the descriptor method addMultipleTablePrimaryKeyName(), which provides:

Example 8-6 Implementing a multiple table descriptor where the additional table primary keys are named differently.

//Define a new descriptor that uses three tables.
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
descriptor.addTableName("PERSONNEL"); 
// Primary table
descriptor.addTableName("EMPLOYMENT");
descriptor.addTableName("USERS");

descriptor.addPrimaryKeyFieldName("PER_NUMBER");
descriptor.addPrimaryKeyFieldName("DEP_NUMBER");

descriptor.addMultipleTablePrimaryKeyName("PERSONEL.PER_NUMBER", 
"USERS.PERSONEL_NO");
descriptor.addMultipleTablePrimaryKeyName("PERSONEL.DEP_NUMBER", 
"USERS.DEPARTMENT_NO");

// Assumed EMPLOYMENT uses same primary key
descriptor.addDirectMapping(id, PER_NUMBER);

OneToOneMapping department = new OneToOneMapping();
department.setAttributeName("department");
department.setReferenceClass(Department.class);
department.setForeignKeyFieldName("DEP_NUMBER");
descriptor.addMapping(department);

// Primary key does not have to be mapped for additional tables.
...

Tables related by foreign key relationships

For TopLink to support read, insert, update and delete operations on an object mapped to multiple tables:

The API is addMultipleTableForeignKeyFieldName(). This method builds the join expression and adjusts the table insertion order to respect the foreign key constraints.

The following example shows the setup of a descriptor for an object mapped to multiple tables where the tables are related by a foreign key relationship from the primary table to the secondary table. The addMultipleTableForeignKeyFieldName() method is used to specify the direction of the foreign key relationship.

If the foreign key is in the secondary table and refers to the primary table then the order of the arguments to addMultipleTableForeignKeyFieldName() is reversed.


Note:

The foreign key field in the primary table and the primary key in the secondary table must be mapped. This allows read, insert, update and delete operation to be performed on the Employee object.


Example 8-7 Implementing multiple tables where a foreign key from the primary table to the secondary table is used to join the tables.

Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
Vector vector = new Vector();
vector.addElement("EMPLOYEE");
vector.addElement(ADDRESS");
descriptor.setTableNames(vector);
descriptor.addPrimaryKeyFieldName("EMPLOYEE.EMP_ID");
// Map the foreign key field of the employee table and the primary key of the 
address table.
descriptor.addDirectMapping("employee_addressID", "EMPLOYEE.ADDR_ID");
descriptor.addDirectMapping("address_addressID", "ADDRESS.ADDR_ID");

// Setup the join from the address table to the country employee table to the 
address table by specifying the FK info to the descriptor. Set the foreign key 
info from the address table to the country table. 
descriptor.addMultipleTableForeignKeyFieldName("EMPLOYEE.ADDR_ID", 
"ADDRESS.ADDR_ID");

Non-standard table relationships

Occasionally the join condition can be non-standard. In this case, the descriptors query manager can be used to provide a custom multiple table join expression. The getQueryManager() method is called on the descriptor to obtain its query manager, and the setMultipleTableJoinExpression() method is used to customize the join expression.

Simply specifying the join expression allows TopLink to perform read operations for the object. Insert operations can also be supported if the table insertion order is specified and the primary key of the additional tables is mapped manually.

The insertion order is required so as not to violate foreign key constraints when inserting to the multiple tables. The insert order can be specified using the descriptor method setMultipleTableInsertOrder().

The following example shows the use of the setMultipleTableJoinExpression() and setMultipleTableInsertOrder() methods. In addition, it shows the use of a custom join expression without specifying the table insert order.


Note:

Using these methods does not support update or delete operations because of the lack of primary key information for the secondary table(s). If update and delete operations are required they could be done with custom SQL, or the foreign key information can be specified explicitly as explained in the previous section.


Example 8-8 Implementing multiple tables where a join expression and the table insert order are specified.

Using this method allows only read and insert operations to be performed on Employee objects. Note that the primary key of the secondary table and the foreign key of the primary table must be mapped and maintained by the application for insert operations to work.

Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
Vector vector = new Vector();
vector.addElement("EMPLOYEE");
vector.addElement(ADDRESS");
descriptor.setTableNames(vector);

// Specify the primary key information for each table.
descriptor.addPrimaryKeyFieldName("EMPLOYEE.EMP_ID");

// Map the foreign key field of the employee table and the primary key of the 
address table. 
descriptor.addDirectMapping("employee_addressID", "EMPLOYEE.ADDR_ID");
descriptor.addDirectMapping("address_addressID", "ADDRESS.ADDR_ID");
// Setup the join from the employee table to the address table using a custom 
join expression and specifying the table insert order.
ExpressionBuilder builder = new ExpressionBuilder();
descriptor.getQueryManager().setMultipleTableJoinExpression(builder.getField("EM
PLOYEE.ADDR_ID").equal(builder.getField("ADDRESS.ADDR_ID")));
Vector tables = new Vector(2);
tables.addElement(new DatabaseTable("ADDRESS"));
tables.addElement(new DatabaseTable("EMPLOYEE"));
descriptor.setMultipleTableInsertOrder(tables);
...

Example 8-9 Mapping a multiple table descriptor where a custom join expression is required.

In this example only read operations are supported.

//Define a new descriptor that uses three tables.
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
descriptor.addTableName("PERSONNEL"); 
// Primary table
descriptor.addTableName("EMPLOYMENT");
descriptor.addPrimaryKeyFieldName("PER_NO");
descriptor.addPrimaryKeyFieldName("DEP_NO");

ExpressionBuilder builder = new ExpressionBuilder();
descriptor.getQueryManager().setMultipleTableJoinExpression((builder.getField("P
ERSONEL.EMP_NO").equal(builder.getField("EMPLOYMENT.EMP_NO")));
descriptor.addDirectMapping("personelNumber", "PER_NO");

OneToOneMapping department = new OneToOneMapping();
department.setAttributeName("department");
department.setReferenceClass(Department.class);
department.setForeignKeyFieldName("DEP_NO");
descriptor.addMapping(department);
// The primary key field on the EMPLOYMENT does not have to be mapped.
...

Implementing sequence numbers in Java

To implement sequence numbers using Java code, send the setSequenceNumberFieldName( ) message to the descriptor to register the name of the database field that holds the sequence number. The setSequenceNumberName( ) method also holds the name of the sequence. This name can be one of the entries in the SEQ_NAME column or the name of the sequence object (if you are using Oracle native sequencing).


Notes:

  • The sequence field must be in the first (primary) table if multiple tables are used.

  • If you use Sybase, SQL Server or Informix native sequencing, this has no direct meaning but should still be set for compatibility reasons.


Example 8-10 Implementing sequence numbers using Java code.

// Set the sequence number information.
descriptor.setSequenceNumberName("EMP_SEQ");
descriptor.setSequenceNumberFieldName("EMP_ID");

Overriding the instantiation policy using Java code

The Descriptor class provides the following methods to specify how objects get instantiated.

Implementing locking in Java

Use the API to set optimistic locking completely in code. All of the API is on the descriptor:

Example 8-11 Implementing optimistic locking using the VERSION field of EMPLOYEE table as the version number of the optimistic lock.

// Set the field that control optimistic locking. No mappings are set for fields 
which are version fields for optimistic locking.
descriptor.useVersionLocking("VERSION");

The code in the example above, stores the optimistic locking value in the identity map. If the value should be stored in a non-read only mapping, then the code would be:

descriptor.useVersionLocking("VERSION", false);

The false indicates that the lock value is not stored in the cache but is stored in the object.

Implementing identity maps in Java

To change the identity map type for a descriptor from the default to specify it explicitly as full identity map), useNoIdentityMap(), useCacheIdentityMap(), useWeakIdentityMap(), useSoftCacheWeakIdentityMap(), useHardCacheWeakIdentityMap()or useFullIdentityMap() message to the descriptor.

To change the size of the identity map from the default of 100, use the setIdentityMapSize() message.

Example 8-12 Changing the default identity map parameters

// Set any identity map parameters.
descriptor.useCacheIdentityMap();
descriptor.setIdentityMapSize(10);

Implementing query keys in Java

Register query keys with a descriptor using the addQueryKey() method of the Descriptor class. Direct query keys can also be defined with the addDirectQueryKey() method, specifying the name of the query key and the name of the table field. Abstract query keys are registered to interface descriptors through the addAbstractQueryKey() method.

Example 8-13 Implementing a query key.

// Add a query key for the foreign key field using the direct method
direct descriptor.addDirectQueryKey("managerId", "MANAGER_ID");

// The same query key could also be added through the add method
DirectQueryKey directQueryKey = new DirectQueryKey();
directQueryKey.setName("managerId");
directQueryKey.setFieldName("MANAGER_ID");
descriptor.addQueryKey(directQueryKey);

// Add a one-to-one query key for the large project that the employee is a 
leader of (this assumes only one project)
OneToOneQueryKey lprojectQueryKey = new OneToOneQueryKey();
lprojectQueryKey.setName("managedLargeProject");
lprojectQueryKey.setReferenceClass(LargeProject.class);
ExpressionBuilder builder = new ExpressionBuilder();
projectQueryKey.setJoinCriteria(builder.getField("PROJECT.LEADER_
ID").equal(builder.getParameter("EMPLOYEE.EMP_ID")));
descriptor.addQueryKey(lprojectQueryKey);

// Add a one-to-many query key for the projects that the employee multiple 
projects)
OneToManyQueryKey projectsQueryKey = new OneToManyQueryKey();
projectsQueryKey.setName("managedProjects");
projectsQueryKey.setReferenceClass(Project.class);
ExpressionBuilder builder = new ExpressionBuilder();
projectsQueryKey.setJoinCriteria(builder.getField("PROJECT.LEADER_
ID").equal(builder.getParameter("EMPLOYEE.EMP_ID")));
descriptor.addQueryKey(projectsQueryKey);
// Next define the mappings. 
...

Implementing indirection in Java

To create indirection objects in code, the application must replace the relationship reference with a ValueHolderInterface. It must also call the useIndirection() method of the mapping if the mapping does not use indirection by default. Likewise, call the dontUseIndirection() method to disable indirection. ValueHolderInterface is defined in the oracle.toplink.indirection.

Example 8-14 A mapping that does not use indirection.

// Define the One-to-One mapping. Note that One-to-One mappings have indirection 
enabled by default, so the "dontUseIndirection()" method must be called if 
indirection is not used.
OneToOneMapping oneToOneMapping = new OneToOneMapping();
oneToOneMapping.setAttributeName("address");
oneToOneMapping.setReferenceClass(Address.class);
oneToOneMapping.setForeignKeyFieldName("ADDRESS_ID");
oneToOneMapping.dontUseIndirection();
oneToOneMapping.setSetMethodName("setAddress");
oneToOneMapping.setGetMethodName("getAddress");
descriptor.addMapping(oneToOneMapping);

The following code illustrates a mapping using indirection.

// Define the One-to-One mapping. One-to-One mappings have indirection enabled 
by default, so the "useIndirection()" method is unnecessary if indirection is 
used.
OneToOneMapping oneToOneMapping = new OneToOneMapping();
oneToOneMapping.setAttributeName("address");
oneToOneMapping.setReferenceClass(Address.class);
oneToOneMapping.setForeignKeyFieldName("ADDRESS_ID");
oneToOneMapping.setSetMethodName("setAddressHolder");
oneToOneMapping.setGetMethodName("getAddressHolder");
descriptor.addMapping(oneToOneMapping);

Implementing proxy indirection in Java

To enable proxy indirection in Java code, use the following API for ObjectReferenceMapping:

Example 8-15 Using proxy indirection.

// Define the 1:1 mapping, and specify that Proxy Indirection should be used
OneToOneMapping addressMapping = new OneToOneMapping();
addressMapping.setAttributeName("address");
addressMapping.setReferenceClass(AddressImpl.class);
addressMapping.setForeignKeyFieldName("ADDRESS_ID");
addressMapping.setSetMethodName("setAddress");
addressMapping.setGetMethodName("getAddress");
addressMapping.useProxyIndirection();
descriptor.addMapping(addressMapping);
. . .

Implementing object-relational descriptors in Java

Use the ObjectRelationalDescriptor class to define object-relational descriptors. This descriptor subclass contains the following additional properties:

The demo application provided in <INSTALL_DIR>\examples\core\examples \sessions\remote\rmi illustrates an object-relational data model and descriptors.

Example 8-16 Creating an object-relational descriptor.

import oracle.toplink.objectrelational.*;
ObjectRelationalDescriptor descriptor = new ObjectRelationalDescriptor()
descriptor.setJavaClass(Employee.class);
descriptor.setTableName("EMPLOYEES");
descriptor.setStructureName("EMPLOYEE_T");
descriptor.setPrimaryKeyFieldName("OBJECT_ID");

descriptor.addFieldOrdering("OBJECT_ID"); 
descriptor.addFieldOrdering("F_NAME");
descriptor.addFieldOrdering("L_NAME");
descriptor.addFieldOrdering("ADDRESS"); 
descriptor.addFieldOrdering("MANAGER");
descriptor.addDirectMapping("id", "OBJECT_ID"); 
descriptor.addDirectMapping("firstName", "F_NAME"); 
descriptor.addDirectMapping("lastName", "L_NAME");
//Refer to the mappings section for examples of object relational mappings.
...

Changing Java classes to use indirection

Attributes using indirection must conform to the ValueHolderInterface. You can change your attribute types in the Class Editor without re-importing your Java classes. Ensure that you change the attribute types in your Java code as well. Attributes that are typed incorrectly will be marked as deficient.

In addition to changing the attribute's type, you may also need to change its accessor methods. If you use method access, TopLink requires accessors to the indirection object itself, so your get method returns an instance that conforms to ValueHolderInterface and your set method accepts one argument that conforms to the same. If the instance variable returns a Vector instead of an object then the value holder should be defined in the constructor as follows:

addresses = new ValueHolder(new Vector());

In any case, the application uses the getAddress() and setAddress() methods to access the Address object. When indirection is used, TopLink uses the getAddressHolder() and setAddressHolder() methods when saving and retrieving instances to and from the database.

Example 8-17 Implementing the Employee class using indirection with method access for a one-to-one mapping to Address.

The class definition is modified so that the address attribute of Employee is a ValueHolderInterface instead of an Address and appropriate get and set methods are supplied.

// Initialize ValueHolders in Employee Constructor
public Employee() {
address = new ValueHolder();
}
protected ValueHolderInterface address;

// 'Get' and `Set' accessor methods registered with the mapping and used by 
TopLink.
public ValueHolderInterface getAddressHolder() {
return address;
}
public void setAddressHolder(ValueHolderInterface holder) {
address = holder;
}

// `Get' and `Set' accessor methods used by the application to access the 
attribute.
public Address getAddress() {
return (Address) address.getValue();
}
public void setAddress(Address theAddress) {
address.setValue(theAddress);
}

Setting the wrapper policy using Java code

The Descriptor class provides methods that are used in conjunction with the wrapper policy:

Implementing events using Java

In this example, we check to see if there is a lock conflict whenever an instance of Employee is built from information in the database:

//In the employee class, declare the event method which will be invoked when the 
event occurs.
public void postBuild(DescriptorEvent event) {

// Uses objects row to integrate with some application level locking 
service.
if ((event.getRow().get("LOCKED")).equals("T")) {
LockManager.checkLockConflict(this);
}
}

Registering event listeners

TopLink only supports registering events to call methods on the domain object. If you want an object other than the domain object to handle these events, you must register it as a listener with the descriptor's event manager. If you want a LockManager to receive events for all Employees, you could modify your descriptor amendment to register the LockManager as the listener. Any object you register as a listener must implement the DescriptorEventListener interface. The amendment method is shown in the following example.

Example 8-18 Registering event listeners

public static void addToDescriptor(Descriptor descriptor)
{

   descriptor.getEventManager().addListener
(LockManager.activeManager()); }

Reference

Table 8-2 summarizes the most common public methods for DescriptorEventManager:

For a complete description of all available methods for DescriptorEventManager, see the TopLink JavaDocs.

Table 8-2 Elements for the descriptor event manager  
Element Default Method Names

Events selectors Defaults come from listener interface implementation

All events take DescriptorEvent

All events take (String methodName)

postBuild

setPostBuildSelector

postRefresh

setPostRefreshSelector

preWrite

setPreWriteSelector

postWrite

setPostWriteSelector

preDelete

setPreDeleteSelector

postDelete

setPostDeleteSelector

preInsert

setPreInsertSelector

postInsert

setPostInsertSelector

preUpdate

setPreUpdateSelector

postUpdate

setPostUpdateSelector

aboutToInsert

setAboutToInsertSelector

aboutToUpdate

setAboutToUpdateSelector

postClone

setPostCloneSelector

postMerge

setPostMergeSelector

Listener registration

Source object if it implements the listener interface

addListener (DescriptorEventListener 
listener)

Descriptor-Event reference (available methods on Descriptor-Event)

getSource()
getSession()
getQuery()
getDescriptor()

only; aboutToInsert/ Update,

/ Build

getRow()

only; postMerge / Clone / write events within a unit of work

getOriginalObject()


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Solution Area
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index