Skip navigation.
Downloads | Product Documentation | Support

Client Application Developer's Guide

# DSP's Data Programming Model and Update Framework

BEA AquaLogic Data Services Platform (DSP) implements the Service Data Objects (SDOs) as its data client-application programming model. SDO is an architecture and set of APIs for working with data objects while disconnected from their source. In DSP, SDOs—whether typed or untyped data objects—are obtained from data services by using the Mediator APIs, or through Data Service controls. (See Introducing Service Data Objects (SDO).)

Client applications manipulate the data objects as required for the business process at hand, and then submit changed objects to the data service, for propagation to the underlying data sources. Although the SDO specification does not define one, it does discuss the need for mediator services, in general, that can send and receive SDOs; the specification also discusses the need for handling updates to data sources, again, without specifying an implementation: The SDO specification leaves the details up to implementors as to how mediator services are implemented, and how they should handle updates to data objects.

As discussed in Update Frameworks and the Data Service Mediator, DSP's Mediator is the process that not only handles the back-and-forth communication between client applications and data services, it also facilitates updates to the various data sources that comprise any data service.

This chapter includes information about DSP's implementation of the SDO data programming model, as well as DSP's update framework. It includes:

- Data Services Platform and Service Data Objects (SDOs)
- The Data Services Platform Update Framework

# Data Services Platform and Service Data Objects (SDOs)

When you invoke a data service's read or navigation function (through the Data Service Mediator API or from a Data Service control), the data service returns a data graph comprising one or more data objects. Data objects and data graphs are two fundamental artifacts of the SDO data programming model. As shown in Figure 2-1, a data graph comprises:

- A root object that typically corresponds to the root data type of a data service's return type.
- One or more data objects.
- A change summary.
- Metadata about the data objects; for example, the XML structure of a "CUSTOMER," comprising a LAST_NAME and an EMAIL_ADDRESS.

Each of these can be described in more detail, as follows:

- Data Graph. A data graph is a data type, the primary construct for SDO-based data programming. It is a data structure that serves as something of a container for related data objects. Data graphs encompass the data objects as instantiated from the data service, and track all changes made to those data objects.
- Change Summary. An object that tracks changes to data objects. A change summary exists only in the context of an associated data graph. As changes are made to the data objects that comprise the data graph—adds, deletes, or changes to the data objects or any of their properties—the changes are captured in the change summary.

The change summary is used by the Mediator (in conjunction with a logical data service's decomposition map) to derive the update plan and ultimately, to update data sources. The change summary submitted with each changed SDO remains intact, regardless of whether or not the submit() succeeds, so it can support rollbacks when necessary.

- Data Object. A data object is a structure for containing property values. Properties can be simple types or complex types.

- Simple types. Simple types comprise primitive data types, such as string or int, and correspond to leaf nodes in XML document trees.
- Complex types. Complex types correspond to branch nodes in an XML document tree and may contain other data objects.

Figure 2-1 Client Applications and Data Service Mediator Send and Receive Data Graphs

Table 2-2 summarizes the various SDO data programming artifacts and lists an example of each (as shown in Figure 2-1).

Table 2-2 Data Graph Example

####

Data Graph and Related Artifacts | Example
--- | ---
DataGraph | `CUSTOMERDataGraph`
DataObject | `CUSTOMER0, ORDERS`
Root Object | `CUSTOMERDocument`
ChangeSummary | `CHANGESUMMARY`
Property | `CUSTOMERID, LAST_NAME`
Simple Type | `CUSTOMERID`
Complex Type | `ORDERS`
Metadata | `<CUSTOMER> <LAST_NAME></LAST_NAME> <EMAIL_ADDRESS/> </CUSTOMER>`

## Static and Dynamic Data APIs

SDO specifies both static (typed) and dynamic (untyped) interfaces for data objects:

- Static. The static data API is an XML-to-Java API binding that contains methods that correspond to each element of the data object returned by the data service. These generated interfaces provide both getters and setters; for example, getCustomer(), setCustomer(). For examples see Table 2-5.
- Dynamic. The dynamic data API provides generic getters and setters for working with data objects. Elements are passed as arguments to the generic methods. For example, get("Customer") or set("Customer").

The dynamic data API can be used with data types that have not yet been deployed at development time.

Table 2-3 summarizes the advantages of each approach.

Table 2-3 Static and Dynamic Data APIs

Data Model | Advantages...
--- | ---
Static Data API | Easy-to-implement interface; code is easy to read and maintain. Compile-time type checking. Enables code-completion in BEA WebLogic Workshop Source View.
Dynamic data API | Dynamic; allows discovery. Runtime type checking. Allows for a general-purpose coding style.

### Static Data API

SDO's static data API is a typed Java interface generated from a data service's XML schema definition. It is similar to JAXB or XMLBean static interfaces. The interface files, packaged in a JAR, are typically generated by the DSP data services developer using WebLogic Workshop, or by using one of the provided tools (see Generating SDO Client Classes for more information).

The generated interfaces extend both the dynamic data API (specifically, the DataObject interface) and the XmlObject interface. Thus, the generated interfaces provide typed getters and setters for all properties of the XML datatype.

An interface is also generated for each complex property (such as CREDIT and ORDER shown in Figure 2-4), with getters and setters for each of the properties that comprise the complex type.

In addition, for properties that may have multiple occurrences, getters and setters are also generated for manipulating arrays and array elements. A multiple-occurring property is an XML schema element that has its maxOccurs attribute set to either unbounded or greater than one. In the DSP Console Metadata Browser, such elements are flagged with an asterisk—for example, ORDER* and POITEM* (see Figure 2-4) indicate that an array or order data objects (ORDERS[]) will be returned. For results involving repeating objects, you can cast the root element to an array of returned objects (datatypename[])

Note: In prior releases of Data Services Platform, an "ArrayOf..." schema element was created to serve as a container for array types returned as part of a Data Graph. Some references to the ArrayOf mechanism may remain in code samples and documentation.

As an example of how static data APIs get generated, given the CUSTOMER data type shown in Figure 2-4, generating typed client interfaces results in:

- CUSTOMER, CUSTOMERDocument, CREDIT, ORDER, and POITEM interfaces, each of which includes getters, setters, and factory classes (for instantiating typed data objects and their Properties).
- An interface for the CUSTOMERNAME string attribute.
- Getters and setters for working with members of arrays of CREDIT, ORDER, and POITEM elements.

Figure 2-4 CUSTOMER Return Type Displayed in DSP Console's Metadata Browser

When you develop Java client applications that use SDO's static data APIs, you will import these XMLBeans-generated typed interfaces into your Java client code. For example:

>     import appDataServices.AddressDocument;

The SDO API interfaces use XMLBeans for object serialization and deserialization. As a client application developer, you rarely need to know such details. However, developers who are integrating DSP with WebLogic Integration workflow components (JPDs, or Java process definitions) will need to modify the default serialization-deserialization in their JPD code that uses data objects. For more information, see Using Workflow with DSP-Enabled Applications.

Since DSP uses XMLBeans, many features of the underlying XMLBeans technology are available in SDO as well. For example, DataObjects can be cast to Strings using the XmlObjects toString( ) method, for printing to output.

Table 2-5 Static (Typed) Data API Getters and Setters

####

Static Data API (Generated) | Description | Examples
--- | --- | ---
`Type get` PropertyName`()` | Returns the value of the property. A static getPropertyName( ) method is generated for each attribute or element that has a single occurrence. | `getCUSTOMER(), getCUSTOMERNAME(), getCREDITRATING(), getCREDITSCORE()`
`Type[] get` PropertyName `Array()` | For multiple occurrence elements, returns all PropertyName elements. | `getCREDITArray()`
`Type get` PropertyName `Array( int PropertyIndex)` | Returns the PropertyName child element at the specified index. | `getCREDITArray(int), setCREDITSCORE(int)`
`void set` PropertyName`(Type newValue)` | Sets the value of the property to the newValue. Generated when PropertyName is an attribute or an element with single occurrence. | `setCUSTOMER(CUSTOMER), setCUSTOMERNAME(String), setCREDITRATING(String)`
`void set` PropertyName `Array( Type[] newValue)` | Sets all PropertyName elements. | `setCREDITArray(CREDIT[])`
`void set` PropertyName `Array( Type newValue, int PropertyIndex)` | Sets the PropertyName child element at the specified index. | `setCREDITArray(int, CREDIT)`
`boolean isSet` PropertyName`()` | Determines whether the PropertyName element or attribute exists in the document. Generated for optional elements and attributes. (An optional element has a minOccurs attribute set to 0; an optional attribute has a use attribute set to optional.) | `isSetCustomerStreetAddress2()`
`void insert` PropertyName`(int index,` PropertyName `Type newValue)` | Inserts the specified PropertyName child element at the specified index. | `insertNewCREDIT(int)`
`int sizeOf` PropertyName `Array()` | Returns the current number of property child elements. | `sizeOfCREDITArray()`
`void unSet` PropertyName`()` | Removes the element or attribute of PropertyName from the document. Generated for elements and attributes that are optional. In schema, and optional element has an minOccurs attribute set to 0; an optional attribute has a use attribute set to optional. | `unSetCustomerStreetAddress2()`
`void remove` PropertyName`(int PropertyIndex)` | Removes the PropertyName child element at the specified index. | `removeCREDIT(int)`
`void add` PropertyName`( PropertyNameType newValue)` | Adds the specified PropertyName to the end of the list of PropertyName child elements. | addNewCREDIT(), addNewCUSTOMER()
`boolean isSet` PropertyName `Array(int PropertyIndex)` | Determines whether the PropertyName element at the specified index is null. | `isSetCustomerArray(3)`
`void unset` PropertyName `Array( int PropertyIndex)` | Sets the value of PropertyName element at the specified index to null. Note: After you call unset and then call set, the return value is false. | `unSetCustomerArray(3)`

### XML Schema-to-Java Type Mapping Reference

DSP client application developers can use the Data Services Platform Console to view the XML schema types associated with data services (see Figure 2-4, CUSTOMER Return Type Displayed in DSP Console's Metadata Browser, on page 2-6). The Return Type tab indicates the data type of each element—string, int, or complex type, for example. The XML schema data types are mapped to data objects in Java using the data type mappings shown in Table 2-6.

Table 2-6 XML Schema to Java Data Type Mapping

####

XML Schema Type | SDO Java Type | XML Schema Type | SDO Java Type
--- | --- | --- | ---
`xs:anyType` | `Sequence` | `xs:integer` | `java.math.BigInteger`
`xs:anySimpleType` | `String` | `xs:language` | `String`
`xs:anyURI` | `String` | `xs:long` | `long`
`xs:base64Binary` | `byte[]` | `xs:Name` | `String`
`xs:boolean` | `boolean` | `xs:NCName` | `String`
`xs:byte` | `byte` | `xs:negativeInteger` | `java.math.BigInteger`
`xs:date` | `java.util.Calendar (Date)` | `xs:NMTOKEN` | `String`
`xs:dateTime` | `java.util.Calendar` | `xs:NMTOKENS` | `String`
`xs:decimal` | `java.math.BigDecimal` | `xs:nonNegativeInteger` | `java.math.BigInteger`
`xs:double` | `double` | `xs:nonPositiveInteger` | `java.math.BigInteger`
`xs:duration` | `String` | `xs:normalizedString` | `String`
`xs:ENTITIES` | `String` | `xs:NOTATION` | `String`
`xs:ENTITY` | `String` | `xs:positiveInteger` | `java.math.BigInteger`
`xs:float` | `float` | `xs:QName` | `javax.xml.namespace.QName`
`xs:gDay` | `java.util.Calendar` | `xs:short` | `short`
`xs:gMonth` | `java.util.Calendar` | `xs:string` | `String`
`xs:gMonthDay` | `java.util.Calendar` | `xs:time` | `java.util.Calendar`
`xs:gYear` | `java.util.Calendar` | `xs:token` | `String`
`xs:gYearMonth` | `java.util.Calendar` | `xs:unsignedByte` | `short`
`xs:hexBinary` | `byte[]` | `xs:unsignedInt` | `long`
`xs:ID` | `String` | `xs:unsignedLong` | `java.math.BigInteger`
`xs:IDREF` | `String` | `xs:unsignedShort` | `Int`
`xs:IDREFS` | `String` | `xs:keyref` | `String`
`xs:int` | `int` |  |

### Dynamic Data API

The dynamic data API has generic property getters and setters, such as set( ) and get( ), as well as getters and setters for specific Java data types (String, Date, List, BigInteger, and BigDecimal, for example). Table 2-7 lists representative APIs from SDO's dynamic data API. The propertyName argument indicates the name of the property whose value you want to get or set; propertyValue is the new value. The dynamic data API also includes methods for setting and getting a DataObject's property by indexValue. This includes methods for getting and setting properties as primitive types, which include setInt( ), setDate( ), getString( ), and so on.

Unlike the static data API, which eliminates underscores in method names generated from types that might include such characters ("LAST_NAME" results in a getLASTNAME( ) method, for example), the dynamic data API requires that field names be referenced precisely, as in get("LAST_NAME"). As an example, assuming that you have a reference to a CUSTOMER data object, you can use the dynamic data API to get the LAST_NAME property as follows:

>     String lastName = (String) customer.get("LAST_NAME");

For a complete reference of the dynamic data API, see the DSP Javadoc (DSP Mediator API Javadoc on page 1-13). For documentation on the SDO 1.0 API see the DataObject interface in the commonj.sdo package. It is available at:

>     http://dev2dev.bea.com/technologies/commonj/sdo/index.jsp

Table 2-7 Dynamic Data API Getters and Setters

####

Dynamic Data API | Description | Example
--- | --- | ---
`get(int PropertyIndex)` | Returns the PropertyName child element at the specified index. | `get(5)`
`set(int PropertyIndex, Object newValue)` | Sets the value of the property to the newValue. | `set(5, CUSTOMER3)`
`set(String PropertyName, Object newValue)` | Sets the value of the PropertyName to the newValue. | `set("LAST_NAME", "Nimble")`
`set(commonj.sdo.Property PropertyName, Object newValue)` | Sets the value of PropertyName to the NewValue | `set(LASTNAME, "Nimble")`
`getType(String PropertyName)` | Returns the value of the PropertyName. Type indicates the specific data type to obtain. | `getBigDecimal("CreditScore")`
`unset(int PropertyIndex)` | Sets the value of PropertyName element at the specified index to null. | `unset(5)`
`unset(commonj.sdo.Property PropertyName)` | Sets the value of the specified PropertyName to null. | `unset(LASTNAME)`
`unset(String PropertyName)` | Sets the value of the specified PropertyName to null. | `unset("LAST_NAME")`
`createDataObject(commonj.sdo.Property PropertyName)` | Returns a new DataObject for the specified containment property. | `createDataObject(LASTNAME)`
`createDataObject(String PropertyName)` | Returns a new DataObject for the specified containment property. | `createDataObject("LAST_NAME")`
`createDataObject(int PropertyIndex)` | Returns a new DataObject for the specified containment property. | `createDataObject(5)`
`createDataObject(String PropertyName, String namespaceURI, String typeName)` | Returns a new DataObject for the specified containment property. | `createDataObject("LAST_NAME","http://namespaceURI_here", "String")`
`delete()` | Removes the object from its container and unsets all writeable properties. | `delete(CUSTOMER)`

#### XPath Support in the Dynamic Data API

One of the benefits of DSP's use of XMLBeans technology is support for XPath in the dynamic data API. XPath expressions give you a great deal of flexibility in how you locate data objects and attributes in the dynamic data API's accessors. For example, you can filter the results of a get() method invocation based on data elements and values:

>     	company.get("CUSTOMER[1]/POITEMS/ORDER[ORDERID=3546353]")

The SDO implementation goes beyond basic XPath 1.0 support by adding zero-based array index notation (".index_from_0") to XPath's standard bracketed notation ([n]). As an example, Table 2-8 compares the XPath standard and SDO augmented notations to refer to the same element, the first ORDER child node under CUSTOMER.

Table 2-8 XPath Standard and SDO Augmented Notation

####

XPath Standard Notation | SDO Augmented Notation
--- | ---
>     get("CUSTOMER/ORDER[1]");
| get("CUSTOMER/ORDER.0");

Zero-based indexing is convenient for Java programmers who are accustomed to zero-based counters, and may want to use counter values as index values without adding 1.

DSP fully supports both the traditional index notation and the augmented notation. However, note that the SDO pre-processor transparently replaces the zero-based form with one-based forms, to avoid conflicts with elements whose names include dot numbers, such as `<myAcct.12>.`

Keep in mind these other points regarding DSP's XPath support:

- Expressions with double adjacent slashes ("//") are not supported. As specified by XPath 1.0, you can use an empty step in a path to effect a wildcard. For example:

>     ("CUSTOMER//POITEM")

In this example, the wildcard matches all purchase order arrays below the CUSTOMER root, which includes either of the following:

>     CUSTOMER/ORDERS/POITEM

>     CUSTOMER/RETURNS/POITEM

Because this notation introduces type ambiguity (types can be either ORDERS or RETURNS), it is not supported by the DSP SDO implementation.

- Attribute notation ("@") cannot be used to identify elements. According to the SDO specification, the notation for denoting an attribute "@" can be used anywhere in the path because attributes and elements are used interchangeably as properties. However, because DSP implements SDO to XML data binding, the distinction between attributes and elements must be preserved. Attribute notation can be used to identify only the attributes that are in the DSP data type. For example, the ID attribute of the following element:

>     <ORDER ID="3434">

is accessed with the following path:

>     ORDER/@ID

Note: For more examples of using XPath expressions with SDOs, see Step 2: Accessing Data Object Properties.

#### Obtaining Type Information about Data Objects

The dynamic data API returns generic data objects. To obtain information about the properties of a data object, you can use methods available in SDO's Type interface. The Type interface (located in the `commonj.sdo` package) provides several methods for obtaining information, at runtime, about data objects, including a data object's type, its properties, and their respective types.

According to the SDO specification, the Type interface (see Table 2-9) and the Property interface (see Table 2-10) comprise a minimal metadata API that can be used for introspecting the model of data objects. For example, the following obtains a data object's type and prints a property's value:

>     DataObject o = ...;
>     Type type = o.getType();
>     if (type.getName().equals("CUSTOMER") {
>        System.out.println(o.getString("CUSTOMERNAME")); }

Once you have an object's data type, you can obtain all its properties (as a list) and access their values using the Type interface's get Properties() method, as shown in Listing 2-1.

Listing 2-1 Using SDO's Type Interface to Obtain Data Object Properties

>     public void printDataObject(DataObject dataObject, int indent) {
>        Type type = dataObject.getType();
>        List properties = type.getProperties();
>        for (int p=0, size=properties.size(); p < size; p++) {
>           if (dataObject.isSet(p)) {
>              Property property = (Property) properties.get(p);
>              // For many-valued properties, process a list of values
>              if (property.isMany()) {
>                 List values = dataObject.getList(p);
>                 for (int v=0; count=values.size(); v < count; v++) {
>                    printValue(values.get(v), property, indent);
>                 }
>              else { // Forsingle-valued properties, print out the value
>                 printValue(dataObject.get(p), property, indent);
>                 }
>              }
>           }
>        }

Table 2-9 lists other useful methods in the Type interface.

Table 2-9 Type Interface Methods

####

Method | Description
--- | ---
`java.lang.Class getInstanceClass()` | Returns the Java class that this type represents.
`java.lang.String getName()` | Returns the name of the type.
java.lang.List getProperties | Returns a list of the properties of this type.
`Property getProperty( java.lang.String propertyName)` | Returns from among all Property objects of the specified type the one with the specified name. For example, dataObject.get("name") or dataObject.get(dataObject.getType().getProperty("name"))
`java.lang.String getURI()` | Returns the namespace URI of the type.
`boolean isInstance( java.lang.Object object)` | Returns True if the specified object is an instance of this type; otherwise, returns false.

Table 2-10 lists the methods of the Property interface.

Table 2-10 Property Interface Methods

####

Method | Description
--- | ---
`Type getContainingType()` | Returns the containing type of this property.
`java.lang.Object getDefault()` | Returns the default value this property will have in a data object where the property hasn't been set
java.lang.String getName() | Returns the name of the property.
`Type getType()` | Returns the type of the property.
`boolean isContainment()` | Returns True if the property represents by-value composition.
`boolean isMany()` | Returns True if the property is many-valued.

## Role of the Mediator and SDOs

In DSP, data graphs are passed between data services and client applications: when a client application invokes a read function on a data service, for example, a data graph is sent to the client application. The client application modifies the content as appropriate—adds an order to a customer order, for example—and then submits the changed data graph to the data service. The Data Service Mediator is the process that receives the updated data objects and propagates changes to the underlying data sources.

The Data Service Mediator is the linchpin of the update process. It uses information from submitted SDOs (change summary, for example) in conjunction with other artifacts to derive an update plan for changing underlying data sources. For relational data sources, updates are automatic. The artifacts that comprise DSP's update framework, including the Mediator, and how the default update process works, are described in more detail below.

# The Data Services Platform Update Framework

As mentioned previously, the SDO specification does not define any specific mediators, but allows for the variety needed to support any type of back-end data sources. DSP's implementation of an SDO mediator service is the Data Service Mediator (or DSP Mediator) shown in Figure 2-1. The DSP Mediator plays an important role in facilitating updates to the various data sources that comprise any data service. It is the core mechanism for the DSP update framework; the update framework also encompasses several programming artifacts, as follows:

- Decomposition function. The decomposition function is the first read function contained in a data service, unless a different function has been specified by the data service architect through the Property Editor. The decomposition function is used by the Mediator to create a decomposition map (for logical data services only) that identifies the constituent data services. From these constituent data services, the Mediator instantiates data objects corresponding to the changed values in the updated data object.
- Decomposition map. A decomposition map (associated with logical data services only) provides information about how a data object based on that data service is constructed (from the underlying data sources or other data services).
- Update plan. The indicates the physical resources that should be modified, and how they should be modified. An update plan is generated for any changed data objects bound to logical data services (see Figure 2-11). The update plan does not include unchanged objects, nor does it have access to any data services that are not included in the update plan: only changed objects are included in the update plan.
- KeyPair. A keypair is an object used by DSP to keep track of primary-foreign key relationships, and the relationship of properties of data objects that have been populated from various layers of a multi-layer data service. (A keypair is sometimes described as a property map.)

Figure 2-11 DSP's Decomposition Process Populates an Update Plan with Constituent Data Objects

From a lower-level perspective, an update plan is a Java object that comprises a tree of DataServiceToUpdate instances — the names of the data services that comprise the changed data objects. DataServiceToUpdate, KeyPair, UpdatePlan, and DataServiceMediatorContext have been implemented as classes in the SDO Mediator APIs, specifically in:

>     com.bea.ld.dsmediator.update package

See DSP Mediator API Javadoc on page 1-13 for information on product Javadocs.

## How It Works: The Decomposition Process

An important characteristic of the SDO model is that back-end data sources associated with modified objects are not changed until the submit() method is called on the data service bound to the objects.

After receiving a data object (the changed SDO) from a calling client application, the Mediator always looks for an update override class first (regardless of whether the data service is a physical or logical data service). If an update override class is available, it is instantiated and executed.

Note: Update overrides are covered in detail in Customizing Data Service Update Behavior. This chapter covers the basics of the default update processing only.

The Mediator first determines the data lineage—the origins of the data—by using the data service's decomposition function to map each constituent in a data object to its underlying data source or data service. In addition, any inverse functions specified for the data service are used by the Mediator to define a complete decomposition map.

Note: The usage of inverse functions is described in "Best Practices and Advanced Topics", Data Services Developer's Guide.

As discussed above, for any logical data service, DSP's Mediator uses the decomposition function to create a decomposition map that identifies constituent data services and then instantiates data objects that correspond to the data objects' changed values. For example, as shown in Figure 2-11, a customersDocument object that comprises updated customer information (from a Customer data service) and three updated Orders (from an Orders data service) would be decomposed into four objects.

An important distinction between logical and physical data service updates is as follows:

- Physical Data Service Update Process. The data source is updated immediately. No decomposition is required.
- Logical Data Service Update Process. A logical data service must be decomposed into its constituent data services.

### Physical Data Service Update Process

For a physical data service, changes to the data sources are propagated immediately (unless an update override class is associated with the data service).

Note: Neither a decomposition map nor an update plan is needed for a physical data service.

Upon receiving an SDO (whether from a submit( ) method invocation, or as a projection from a higher-level data service), the Mediator first checks for an UpdateOverride class associated with the data service.

- No update override. If there is no UpdateOverride the Mediator simply propagates the changes to the underlying data sources.
- With update override. If there is an UpdateOverride the Mediator executes the update override class.

Note: For non-relational data sources, an update override is always required, since there is no automatic update processing for non-relational data sources.

For relational data sources without an update override, updates are handled automatically. However, non-relational data sources such as Web services, flat files, XML files, require an update override class that contains the processing logic necessary to make changes to the data source.

### Logical Data Service Update Process

A logical data service can comprise any number of logical or physical data services. When a top-level data service function executes, the lower-level logical data services that it comprises are "folded in" so that the function appears to be written directly against physical data services. Only information that has been projected in the top-level data service is passed to the next lower-level data service.

Figure 2-12 provides an overview of the steps involved in updating a logical data service:

1. The client application invokes the submit() method, passing the changed data object and its associated data graph to the Mediator. The data graph has a change summary detailing the changes to the object.
2. The Mediator receives the submitted data object and begins the decomposition process by first checking for an update override class. The two possible logic branches are described below:

- No update override. The Mediator decomposes the updated object into submit() calls against the underlying physical data services.
- With update override. The Mediator instantiates mid-level data objects from the top-level SDO, then calls update override routine. The submit() on the mid-level data service is then processed as usual.

Note: An update override class can exist at each layer of a multi-layered data service. Thus, a logical data service comprising several layers of other logical data services checks for an update override at each constituent layer. If a mid-layer data service has no update override, the update framework bypasses the instantiation of an SDO object, instead directly creating the SDO objects for the underlying data service. This is true in the case of a logical data service with an update override or a physical data service.

The performChange( ) method can access and modify the update plan and decomposition map, or perform any other custom processing, including taking over complete processing.

The performChange( ) method returns a Boolean value that either continues or aborts processing by the Mediator, as follows:

- True. After control returns from the method, the Mediator resumes its normal course of processing. A new update plan is automatically generated so that any new changes against the passed-in SDO made in the update override plan can be accounted for. The new plan combines the previously indicated changes with any new change.
- False. The Mediator does not attempt to apply the changes. The method would return false, for example, if all changes have already been made. (If you want to handle an error that would require the update to be aborted, your method should throw an exception.)

Note: See Customizing Data Service Update Behavior, for complete information about customizing behavior.

3. The Mediator determines the origins of the data sources that must be changed and how to change them. The Mediator calls the decomposition function associated with the data service and receives a decomposition map for the data service. By default, the Mediator uses the data service's first read function to create its decomposition map (if no other decomposition function is specified).

1. The Mediator uses the information in the change summary and the data service's decomposition map to derive an update plan. The update plan comprises a tree of data service objects ("SDO objects to update") for each instance of a changed data source.
2. For any lower-level data service, the Mediator also checks for an update override, and executes the update override class if one is present.

4. The Mediator iterates (walks) through the update plan, submitting changes to each of the lower level data services. The Mediator applies changes based on the order of objects in the tree and their container-containment relationships, as follows:

1. Objects within the same level (sibling objects) are processed in the order in which they are encountered in the data object.
2. Container objects are processed before contained objects—unless the container is being deleted, in which case changes are applied to the contained object before the containing object.
3. If an object has a KeyPair specified, the values are mapped from its container before submitting the change. (Changes made to an SDO container during its update, such as primary key computations, are visible in the contained object.)

Figure 2-12 Logical Data Service Update Process

### Primary-Foreign Key Relationships Mapped Using a KeyPair

Most RDBMSs can automatically generate primary keys, which means that if you are adding new data objects to a data service that is backed by a relational database, you may want or need to handle a primary key as a return value in your code. For example, if a submitted data graph of objects includes a new data object, such as a new Customer, DSP generates the necessary primary key.

For data inserts of autonumber primary keys, the new primary key value is generated and returned to the client. Only primary keys of top-level data objects (top-level of a multi-level data service) are returned; nested data objects that have computed primary keys are not returned.

By returning the top-level primary key of an inserted tuple, DSP allows you to re-fetch tuples based on their new primary keys, if necessary.

The Mediator saves logical primary-foreign keys as a KeyPair (see the `KeyPair` class in the Mediator API). A KeyPair object is a property map that is used to populate foreign-key fields during the process of creating a new data object:

The value of the property will be propagated from the parent to the child, if the property is an autonumber primary key in the container, which is a new record in the data source after the autonumber has been generated.

The KeyPair object is used to identify corresponding data elements at adjacent levels of a decomposition map; it ensures that a generated primary key value for a parent (container) object will be mapped to the foreign key field of the child (contained) element.

As an example, Figure 2-13 shows property mapping for the decomposition of a Customers data service.

Figure 2-13 Logical Data Services Use KeyPairs for Property Mapping (Primary-Foreign Key Mapping)

DSP manages the primary-foreign key relationships between data services; how the relationship is managed depends on the layer (of a multi-layered data service), as follows:

- Top-level data service. Inserts generate a new primary key, which is returned to the client. Adding a data object at the top-level of a data service data objects have been added which have primary keys that are automatically generated by the RDBMS, the values of the primary keys for the inserted tuples will be returned as an array of Java properties (XPath name/value pairs) after a successful update submit:

>     Properties[] keys = ds.submit(doc);

A tuble is basically a record; in the context of data services, a tuble may comprise data that spans several layers of data services.

- Nested data objects. Generates and inserts a new primary key, but does not return to the client.

DSP propagates the effects of changes to a primary or foreign key.

For example, given an array of Customer objects with a primary key field CustID into which two customers are inserted, the submit would return an array of two properties with the name being CustID, relative to the Customer type, and the value being the new primary key value for each inserted Customer.

### Managing Key Dependencies

DSP manages primary key dependencies during the update process. It identifies primary keys and can infer foreign keys in predicate statements. For example, in a query that joins data by comparing values, as in:

>     where customer/id = order/id

The Mediator performs various services given the inferred key/foreign key relationship when updating the data source.

If a predicate dependency exists between two SDOToUpdate instances (data objects in the update plan) and the container SDOToUpdate instance is being inserted or modified and the contained SDOToUpdate instance is being inserted or modified, then a key pair list is identified that indicates which values from the container SDO should be moved to the contained SDO after the container SDO has been submitted for update.

This Key Pair List is based on the set of fields in the container SDO and the contained SDO that were required to be equal when the current SDO was constructed, and the key pair list will identify only those primary key fields from the predicate fields.

The KeyPair maps a container primary key to container field only. If the KeyPair does not container's complete primary key is not identified by the map then no properties are specified to be mapped.

A Key Pair List contains one or more items, identifying the node names in the container and contained objects that are mapped.

#### Foreign Keys

When computable by SDO submit decomposition, foreign key values are set to match the parent key values.

Foreign keys are computed when an update plan is produced.

### Transaction Management

Each submit() to the Mediator operates as a transaction. Depending upon whether the submit() succeeds or fails, you should do one of two things:

- Submit() succeeds. You can re-query the SDO to be sure it matches the current data because side effects of the update may have changed the result of the query. (Re-querying the data service to obtain a new data object also clears the change summary.)
- Submit() fails. You can reinvoke submit() on the data object to execute the same updates (since the original data objects and change summary still exist).

#### Nested Transactions

All submits perform immediate updates to data sources. If a data object submit occurs within the context of a broader transaction, commits or rollbacks of the containing transaction have no effect on the submitted data object or its change summary, but they will affect any data source updates that participated in the transaction.