# Client Application Developer’s Guide

# Invoking Data Services from Java Clients

This chapter discusses the Data Services Mediator API, a Java API for invoking data service operations from Java applications. This chapter explains in detail how to use the Mediator API and includes working sample applications to help you get started.

Using the Mediator API is one of several techniques for invoking data services from client applications. See Chapter 1, “Introducing Data Services for Client Applications” for a summary of these techniques.

This chapter includes these topics:

- Introducing the Mediator API
- Getting Started
- Sample Static Mediator Application
- Sample Dynamic Mediator Application
- Creating New DataObjects
- Mediator API Basics
- Mapping Data Service Types to Java Types
- Web Services Support
- Advanced Topics

## Introducing the Mediator API

The Mediator API is the Java API for retrieving Service Data Object (SDO) artifacts from a data service and returning them to their source. In your Java client, you call Mediator API methods to connect to a data service, invoke data service methods, and send updated data objects back to the server. You use SDO API methods to manipulate the data objects within your Java client.

For example, you might call a Mediator API method getAllCustomers() to retrieve a collection of customer data objects from the data service. Then, you could call an SDO method such as setCustomerName() to modify a customer object. Finally, you might call another Mediator API method, such as updateCustomers() to return the modified data object to the data source on the server.

Topics in this section include:

- What is SDO?
- What is the Mediator API?
- Dynamic and Static Mediator APIs
- Summary

### What is SDO?

The Java programming model provided by Oracle Data Service Integrator for invoking data service operations is based on Service Data Objects (SDO). SDO, a specification proposed jointly by Oracle, IBM, SAP, and others, is a Java-based architecture and API for data programming. Oracle Data Service Integrator lets programmers uniformly access data objects from heterogeneous data sources, including relational databases, XML data sources, web services, and enterprise information systems.

Tip: | See “Introducing Service Data Objects (SDO)” on page 1-6 for a general overview of SDO. For a more in-depth discussion of SDO, see “Data Programming Model and Update Framework” on page 2-1. Finally, see the dev2dev article Service Data Objects, which provides links to the SDO specifications and Javadoc.

### What is the Mediator API?

While the SDO specification does not specify a mechanism for updating data objects, it does discuss the need for update services, called mediator services. The Mediator API is an Oracle Data Service Integrator implementation of a mediator service. The Mediator API lets you gain access to SDO-compliant objects, called DataObjects, and return them to their source data store.

The important points to remember are that the Mediator API lets you connect to a data service and invoke data service operations. Results are returned as SDO-compliant data objects. Using methods of the SDO API, you can then change or manipulate the data objects. Finally, you use the Mediator API to perform the update.

See “Oracle Data Service Integrator and SDO” on page 2-2 for a general overview of SDO data objects and other artifacts.

### Dynamic and Static Mediator APIs

The Oracle Data Service Integrator Mediator API comprises two main interfaces: dynamic and static. As an application developer, you need to choose one of these approaches.

- The Dynamic Mediator API is useful for programming with data services that are unknown or do not exist at development time. This API is useful, for example, for developing tools and user interfaces that work across data services. The Dynamic Mediator API lets you invoke data service operations directly by name. Clients that use the Dynamic Mediator API are not bound to use specific data services: a dynamic client can use any available data service. See Sample Dynamic Mediator Application.
- The Static Mediator extends the Dynamic Mediator with pre-generated Java classes that have type-safe named methods for accessing data service operations. A Static Mediator API must be explicitly generated using either the IDE or a command line utility. The generated API classes are placed in a JAR file that must be accessible by your client application. See Sample Static Mediator Application.

Tip: | For most use cases, the Static Mediator API is your best choice. The Static Mediator inherits from the Dynamic Mediator and therefore includes all of the functionality of the Dynamic Mediator API. In addition, the static API is type-safe at compile-time. Generally speaking, the static API is simpler and more convenient to use than the Dynamic Mediator API.

### API Overview

The Dynamic Mediator API consists of the classes and interfaces listed in Table 3-1. Refer to the Javadoc on e-docs for more information on these classes and interfaces.

Table 3-1 Oracle Data Service Integrator Mediator API
Interface or Class Name | Description
--- | ---
DataAccessService | The interface for interacting with a data service. The invoke() method of this interface is used to call data service operations. If a data service operation returns a result, the invoke() method returns a DASResult object– a collection of SDO data objects or simple types. (Package: com.bea.dsp.das)
DASResult | The Mediator APIs that return data sets return an object called DASResult (Data Access Service Result). DASResult is similar to a Java Iterator. See Understanding DASResult. (Package: com.bea.dsp.das)
PreparedExpression | The interface for preparing and executing ad hoc queries. An ad hoc query is one that is defined in the client program, not in the data service. See Making Ad Hoc Queries. (Package: com.bea.dsp.das)
DataAccessServiceFactory | The factory class for creating local interfaces to data services. Can be used for dynamic data service instantiation and ad hoc queries. (Package: com.bea.dsp.das)
HelperContextCache | Oracle Data Service Integrator maintains a global cache of SDO HelperContext objects. These objects can be used, for instance, to create new data objects. This class contains methods that let you query and manipulate this cache. See Creating New DataObjects. (Package: com.bea.dsp.das)
RequestConfig | This class encapsulates a collection of attributes that control how a data service method is to be invoked from a client. This class also serves as a way to return arbitrary information to the client. (Package: com.bea.dsp)
SDOUtil | This utility class contains methods for manipulating SDO data objects in the context of Oracle Data Service Integrator. While not part of the Mediator API, this utility class is commonly used in programs that use the Mediator API. (Package: com.bea.dsp.sdo)

Sample of both Static and Dynamic Mediator clients applications are provided. See Sample Static Mediator Application and Sample Dynamic Mediator Application.

### Summary

It may be confusing at first discussing SDO and the mediator APIs together. You can think of SDO as the standard enabling technology that allows client applications to access and update data through Oracle Data Service Integrator data services. SDO has a Java API for handling DataObjects and collections of DataObjects. SDO DataObjects can be either dynamic or static.

The SDO APIs are standard implementations. You can read the full SDO specification, “SDO for Java Specification V2.1” here:

    http://www.osoa.org/display/Main/Service+Data+Objects+Specifications

The mediator APIs, on the other hand, are Oracle Data Service Integrator-specific implementations. The mediator APIs are designed to let you access SDO DataObjects and return them to the server. For more information on the how Oracle Data Service Integrator uses SDO, see Chapter 2, “Data Programming Model and Update Framework.”

## Getting Started

This section lists the basic steps to get started writing a Java client application that interacts with a data service.

Topics in this section include:

- Basic Steps
- Setting the CLASSPATH
- Running the Sample Applications

### Basic Steps

These are the basic steps to follow when developing a Java client that uses the Mediator APIs.

1. The first thing you need is a data service to call. To use a data service, you need to know its name and the names and signatures of its operations. The mediator API method signatures will be the same as the signatures for the data service operations.

Tip: | You can discover data services that are available to you by using the Oracle Data Service Integrator Console. See Viewing Metadata Using the Service Explorer in the Oracle Data Service Integrator Administration Guide.

2. Decide whether to use the Static or Dynamic Mediator API to interact with the data service from your Java client. See Dynamic and Static Mediator APIs for a summary of each API. To use the Static Mediator API, you need to generate or obtain the Static Mediator Client JAR file. For instructions on generating a Static Mediator Client JAR, see the Data Services Developer’s Guide.

Tip: | The Static Mediator API is generally recommended for most use cases. The static API is type safe and generally easier to use than the Dynamic Mediator API.

3. Set up your Java build environment. You need certain JAR files in your CLASSPATH. See Setting the CLASSPATH for details.
4. Write and test your client application. This document provides working sample applications that demonstrate both the Static and Dynamic Mediator API. See Running the Sample Applications.

### Setting the CLASSPATH

You can set the CLASSPATH by either adding the Oracle Data Service Integrator client library to the project or by manually setting the CLASSPATH.

#### Adding the Oracle Data Service Integrator Client Library

You can add the Oracle Data Service Integrator client library to your project by doing either of the following:

- Adding the library to an existing project
- Adding the library when creating a new project

##### Adding the Library to an Existing Project

You can add the Oracle Data Service Integrator client library to an existing project.

Complete the following steps:

1. Right-click the project and choose Properties. A dialog showing the properties for the project appears.
2. Select Java Build Path.
3. Click the Libraries tab, and click Add Library.
4. Select Oracle Data Service Integrator client library, click Next, and click Finish.

Alternatively, you can do the following:

1. Right-click the project and choose Build Path > Configure Build Path. A dialog showing the properties for the project appears.
2. Select Java Build Path.
3. Click the Libraries tab, and click Add Library.
4. Select Oracle Data Service Integrator client library, click Next, and click Finish.

##### Adding the Library When Creating a New Project

You can add the Oracle Data Service Integrator client library when creating a new Java project.

Complete the following steps:

1. Right-click in the Project Explorer, and choose New > Project. The New Project wizard appears.
2. Select Java Project and click Next.
3. Type a name for the project and click Next.
4. Click the Libraries tab, and click Add Library.
5. Select Oracle Data Service Integrator client library, click Next, and click Finish.
6. Click Finish to create the new project.

#### Manually Setting the CLASSPATH

You can optionally set the CLASSPATH manually, if required. The CLASSPATH settings depend on whether you are using the Static or Dynamic Mediator API.

Note: | You can use the Java Mediator API with either the weblogic.jar or the wlfullclient.jar file. For more information about choosing between weblogic.jar or wlfullclient.jar, see Overview of Stand-alone Clients in the Oracle WebLogic Server documentation. For more information about creating the wlfullclient.jar file, see Using the WebLogic JarBuilder Tool.

##### Static Java Mediator API Client CLASSPATH

The following JARs must be in the CLASSPATH of your Java application if you are using the Static Mediator API.

Listing 3-1 Static Java Mediator API Client Classpath (with weblogic.jar)

    CLASSPATH=
       <dataspace-dsp-client>.jar <= this is the generated static client jar
       <ALDSP_HOME>/lib/ld-client.jar
       <BEA_HOME>/modules/com.bea.core.sdo_1.1.0.0.jar
       <WL_HOME>/server/lib/weblogic.jar

Listing 3-2 Static Java Mediator API Client Classpath (with wlfullclient.jar)

    CLASSPATH=
       <dataspace-dsp-client>.jar <= this is the generated static client jar
       <ALDSP_HOME>/lib/ld-client.jar
       <BEA_HOME>/modules/com.bea.core.sdo_1.1.0.0.jar
       <BEA_HOME>/modules/com.bea.core.xml.xmlbeans_1.0.0.0_2-4-0.jar
       <WL_HOME>/server/lib/wlfullclient.jar

##### Dynamic Java Mediator API Client CLASSPATH

The following JARs must be in the CLASSPATH of your Java application if you are using the Dynamic Mediator API.

Listing 3-3 Dynamic Mediator API Classpath (with weblogic.jar)

    CLASSPATH=
       <ALDSP_HOME>/lib/ld-client.jar
       <BEA_HOME>/modules/com.bea.core.sdo_1.1.0.0.jar
       <WL_HOME>/server/lib/weblogic.jar

Listing 3-4 Dynamic Mediator API Classpath (with wlfullclient.jar)

    CLASSPATH=
       <ALDSP_HOME>/lib/ld-client.jar
       <BEA_HOME>/modules/com.bea.core.sdo_1.1.0.0.jar
       <BEA_HOME>/modules/com.bea.core.xml.xmlbeans_1.0.0.0_2-4-0.jar
       <WL_HOME>/server/lib/wlfullclient.jar

#### Specifying the Class Loader Directly

Certain application contexts, such as web applications, employ their own class loaders. In these cases, you must take steps to ensure that the static mediator classes use the correct class loader. If you do not take these steps, class cast exceptions can occur.

To ensure that your static mediator classes resolve properly in such contexts, you can pass the appropriate class loader object to com.bea.dsp.das.HelperContextCache.setClassLoader() before creating DataAccessService or PreparedExpression objects in your code. The example code in Listing 3-5 shows one possible variation on this approach, where the class loader is obtained from the current thread object. This variation works well for web applications deployed on WebLogic Server.

Listing 3-5 Example Code: Getting and Setting the Class Loader

    import com.bea.dsp.das.HelperContextCache;
    ...
    ClassLoader sdoCompiledSchemaLoader =
       Thread.currentThread().getContextClassLoader();
    HelperContextCache.setClassLoader(dataSpaceName, sdoCompiledSchemaLoader);
    ...
    DataAccessService das = DataAccessServiceFactory.newDataAccessService(ctx,
       dataSpaceName, dsUri);
    ...

Note: | In Listing 3-5, you could use the following code to obtain a PreparedExpression object:

Note: | PreparedExpression pe = DataAccessServiceFactory.prepareExpression(ctx, dspDataSpace, adhoc);

Other possible approaches to obtaining the class loader object include:

- this.getClass().getClassLoader() – This option is typically used when invoking code from JPD, JPF, and JWS applications.
- classname.class.getClassLoader() – This option can be used in place of the previous option inside a static method (where you cannot use the `this` keyword to refer to the current object).
- fully-qualified-name-of-compiled-sdo-class-or-interface.class.getClassLoader() – This is the most general-purpose option.
- external-Java-function-class.class.getClassLoader() – Use this option for external Java functions.

### Running the Sample Applications

A good way to get started is to run the sample application code that is provided in this chapter. Samples that use both the Static and the Dynamic Mediator APIs are included. The samples illustrate simple but common use cases: retrieving data, modifying it, and updating it. See Sample Static Mediator Application and Sample Dynamic Mediator Application.

## Sample Static Mediator Application

This section presents a simple Java program that you can copy, compile, and run. The program uses the Static Mediator API to perform these basic tasks: authenticating the client, retrieving data, modifying data, and updating data on the server. For a basic overview of the Static Mediator API, see Dynamic and Static Mediator APIs. See also Mediator API Basics and Advanced Topics.

Topics include:

- Setting Up the Sample Data Service
- Generating the Mediator Client JAR File
- Setting Up the Java Project
- Running and Testing the Code
- Examining the Sample Code

### Setting Up the Sample Data Service

Before you can build and test the sample Java application, you need to set up an Oracle Data Service Integrator data service. The instructions assume that you are familiar with the Oracle Data Service Integrator perspective in the Eclipse IDE, as described in the Data Services Developer’s Guide.

Note: | The sample Java client that is presented in this section calls operations in this sample data service. The sample Java code is designed to work with this specific data service.

1. Install Oracle Data Service Integrator.
2. In Workshop for WebLogic, create a server that uses the Oracle Data Service Integrator samples domain.
3. Start the server.
4. Create an Oracle Data Service Integrator dataspace called MediatorSamples.
5. Copy the sample data service ( Listing 3-6, CUSTOMER.ds, on page 3-13) into a file called MediatorSamples/Retail/CUSTOMER.ds.
6. Copy the schema file ( Listing 3-7, CUSTOMER_KEY.xsd, on page 3-16) into a file called MediatorSamples/Retail/schemas/CUSTOMER_KEY.xsd.
7. Copy the schema file ( Listing 3-8, CUSTOMER.xsd, on page 3-16) into a file called MediatorSamples/Retail/schemas/CUSTOMER.xsd.

Figure 3-2 shows the resulting Dataspace configuration:

Figure 3-2 Sample Dataspace Configuration

Note: | Listing 3-6 is a simple data service file, containing the XQuery code that defines the service and its operations. Listing 3-7 and Listing 3-8 are schema files that are required by the data service. The Mediator API lets you invoke the data service operations from a Java client. For more information on data services, see Data Services Developer’s Guide.

Listing 3-6 CUSTOMER.ds

    xquery version "1.0" encoding "UTF-8";

    (::pragma  xds <x:xds targetType="t:CUSTOMER" xmlns:x="urn:annotations.ld.bea.com" xmlns:t="ld:Retail/CUSTOMER">
        <creationDate>2007-11-08T17:13:51</creationDate>
        <relationalDB name="dspSamplesDataSource" providerId="Pointbase"/>
        <field xpath="CUSTOMER_ID" type="xs:short">
            <extension nativeXpath="CUSTOMER_ID" nativeTypeCode="5"
            nativeType="SMALLINT" nativeSize="5" nativeFractionalDigits="0"
            nativeKey="true">
                <autoNumber type="identity"/>
            </extension>
            <properties nullable="false"/>
        </field>
        <field xpath="FIRST_NAME" type="xs:string">
            <extension nativeXpath="FIRST_NAME" nativeTypeCode="12"
            nativeType="VARCHAR" nativeSize="64" nativeFractionalDigits="0"/>
            <properties nullable="false"/>
        </field>
        <field xpath="LAST_NAME" type="xs:string">
            <extension nativeXpath="LAST_NAME" nativeTypeCode="12"
            nativeType="VARCHAR" nativeSize="64" nativeFractionalDigits="0"/>
            <properties nullable="false"/>
        </field>
        <field xpath="CUSTOMER_SINCE" type="xs:date">
            <extension nativeXpath="CUSTOMER_SINCE" nativeTypeCode="91"
            nativeType="DATE" nativeSize="10" nativeFractionalDigits="0"/>
            <properties nullable="false"/>
        </field>
        <field xpath="EMAIL_ADDRESS" type="xs:string">
            <extension nativeXpath="EMAIL_ADDRESS" nativeTypeCode="12"
            nativeType="VARCHAR" nativeSize="32" nativeFractionalDigits="0"/>
            <properties nullable="false"/>
        </field>
        <field xpath="TELEPHONE_NUMBER" type="xs:string">
            <extension nativeXpath="TELEPHONE_NUMBER" nativeTypeCode="12"
            nativeType="VARCHAR" nativeSize="32" nativeFractionalDigits="0"/>
            <properties nullable="false"/>
        </field>
        <field xpath="SSN" type="xs:string">
            <extension nativeXpath="SSN" nativeTypeCode="12" nativeType="VARCHAR"
            nativeSize="16" nativeFractionalDigits="0"/>
            <properties nullable="true"/>
        </field>
        <field xpath="BIRTH_DAY" type="xs:date">
            <extension nativeXpath="BIRTH_DAY" nativeTypeCode="91" nativeType="DATE"
            nativeSize="10" nativeFractionalDigits="0"/>
            <properties nullable="true"/>
        </field>
        <field xpath="DEFAULT_SHIP_METHOD" type="xs:string">
            <extension nativeXpath="DEFAULT_SHIP_METHOD" nativeTypeCode="12"
            nativeType="VARCHAR" nativeSize="16" nativeFractionalDigits="0"/>
            <properties nullable="true"/>
        </field>
        <field xpath="EMAIL_NOTIFICATION" type="xs:short">
            <extension nativeXpath="EMAIL_NOTIFICATION" nativeTypeCode="5"
            nativeType="SMALLINT" nativeSize="5" nativeFractionalDigits="0"/>
            <properties nullable="true"/>
        </field>
        <field xpath="NEWS_LETTTER" type="xs:short">
            <extension nativeXpath="NEWS_LETTTER" nativeTypeCode="5"
            nativeType="SMALLINT" nativeSize="5" nativeFractionalDigits="0"/>
            <properties nullable="true"/>
        </field>
        <field xpath="ONLINE_STATEMENT" type="xs:short">
            <extension nativeXpath="ONLINE_STATEMENT" nativeTypeCode="5"
            nativeType="SMALLINT" nativeSize="5" nativeFractionalDigits="0"/>
            <properties nullable="true"/>
        </field>
        <field xpath="LOGIN_ID" type="xs:string">
            <extension nativeXpath="LOGIN_ID" nativeTypeCode="12" nativeType="VARCHAR"
            nativeSize="50" nativeFractionalDigits="0"/>
            <properties nullable="true"/>
        </field>
        <key name="CUSTOMER_0_SYSTEMNAMEDCONSTRAINT__PRIMARYKEY"
        type="cus:CUSTOMER_KEY" inferredSchema="true"
        xmlns:cus="ld:Retail/CUSTOMER"/>
    </x:xds>::)

    declare namespace f1 = "ld:Retail/CUSTOMER";

    import schema namespace t1 = "ld:Retail/CUSTOMER" at "ld:Retail/schemas/CUSTOMER.xsd";

    import schema "ld:Retail/CUSTOMER" at "ld:Retail/schemas/CUSTOMER_KEY.xsd";

       (::pragma function <f:function xmlns:f="urn:annotations.ld.bea.com"
       visibility="public" kind="read" isPrimary="false" nativeName="CUSTOMER"
       nativeLevel2Container="SAMPLECUSTOMER" style="table">
       <nonCacheable/>   </f:function>::)

       declare function f1:CUSTOMER() as schema-element(t1:CUSTOMER)* external;

       (::pragma function <f:function xmlns:f="urn:annotations.ld.bea.com"
       visibility="public" kind="create" isPrimary="true" nativeName="CUSTOMER"
       nativeLevel2Container="SAMPLECUSTOMER" style="table">
       <nonCacheable/>   </f:function>::)

       declare procedure f1:createCUSTOMER($p as element(t1:CUSTOMER)*)as
       schema-element(t1:CUSTOMER_KEY)* external;

       (::pragma function <f:function xmlns:f="urn:annotations.ld.bea.com"
       visibility="public" kind="update" isPrimary="true" nativeName="CUSTOMER"
       nativeLevel2Container="SAMPLECUSTOMER" style="table">
       <nonCacheable/>   </f:function>::)

       declare procedure f1:updateCUSTOMER($p as changed-element(t1:CUSTOMER)*) as
       empty()  external;

       (::pragma function <f:function xmlns:f="urn:annotations.ld.bea.com"
       visibility="public" kind="delete" isPrimary="true" nativeName="CUSTOMER"
       nativeLevel2Container="SAMPLECUSTOMER" style="table">
       <nonCacheable/>   </f:function>::)

       declare procedure f1:deleteCUSTOMER($p as element(t1:CUSTOMER)*) as empty()
       external;

Listing 3-7 CUSTOMER_KEY.xsd

    <?xml version="1.0" encoding="UTF-8" ?>
    <xs:schema targetNamespace="ld:Retail/CUSTOMER" xmlns:xs="http://www.w3.org/2001/XMLSchema">
       <xs:element name="CUSTOMER_KEY">
          <xs:complexType>
             <xs:sequence>
                <xs:element name="CUSTOMER_ID" type="xs:short"/>
             </xs:sequence>
          </xs:complexType>
       </xs:element>
    </xs:schema>

Listing 3-8 CUSTOMER.xsd

    <xs:schema targetNamespace="ld:Retail/CUSTOMER" xmlns:xs="http://www.w3.org/2001/XMLSchema">
       <xs:element name="CUSTOMER">
          <xs:complexType>
             <xs:sequence>
                <xs:element name="CUSTOMER_ID" type="xs:short" minOccurs="0"/>
                <xs:element name="FIRST_NAME" type="xs:string"/>
                <xs:element name="LAST_NAME" type="xs:string"/>
                <xs:element name="CUSTOMER_SINCE" type="xs:date"/>
                <xs:element name="EMAIL_ADDRESS" type="xs:string"/>
                <xs:element name="TELEPHONE_NUMBER" type="xs:string"/>
                <xs:element name="SSN" type="xs:string" minOccurs="0"/>
                <xs:element name="BIRTH_DAY" type="xs:date" minOccurs="0"/>
                 <xs:element name="DEFAULT_SHIP_METHOD"
                    type="xs:string" minOccurs="0"/>
                <xs:element name="EMAIL_NOTIFICATION" type="xs:short" minOccurs="0"/>
                <xs:element name="NEWS_LETTTER" type="xs:short" minOccurs="0"/>
                <xs:element name="ONLINE_STATEMENT" type="xs:short" minOccurs="0"/>
                <xs:element name="LOGIN_ID" type="xs:string" minOccurs="0"/>
             </xs:sequence>
          </xs:complexType>
       </xs:element>
    </xs:schema>

### Generating the Mediator Client JAR File

The sample Java application listed later in this section requires that you first generate a Mediator Client JAR from the data service. The classes in this JAR contain type-safe methods that call the data service functions and procedures. The generated Java methods have the same names as their corresponding data service functions and procedures.

Tip: | You can generate a Mediator Client JAR file using the IDE, the Oracle Data Service Integrator Console, or an Ant script. These methods are described in detail in the Data Services Developer’s Guide. For this example, we will use the IDE.

To generate a mediator client JAR file using the IDE:

1. Select File > Export.
2. In the Select dialog, select Oracle Data Service Integrator > Mediator Client JAR File and click Next.
3. Complete the Mediator Client JAR File dialog as follows:

- Select the Dataspace project to export. For this example, the Dataspace project is called MediatorSamples.
- Specify a directory in which to place the exported JAR file. You can select any location on your system. By default, the exported JAR will be named: MediatorSamples-dsp-client.jar.

1. Click Finish.

Tip: | For detailed information on how generated class names in the JAR file are derived, see Naming Conventions for Generated Classes.

### Setting Up the Java Project

Listing 3-10 lists the sample Java program that uses the Static Mediator API. The application simply retrieves a DataObject from a data store, modifies the object, and returns it to the data store. This example assumes you are using the Eclipse IDE, but you can use the IDE or build environment of your choice. For this example, we set up an Eclipse Java project called MediatorClient.

To set up the project:

1. Create a Java project called MediatorClient.
2. Set up your Java Build Path to include the JAR files listed in Setting the CLASSPATH. To do this, select Project > Properties > Java Build Path. Be sure to include the Mediator Client JAR file, as discussed in Generating the Mediator Client JAR File.
3. Create a package called com.bea.dsp.sample in your Java project. To do this, right-click the Java project in the Package Explorer and select New > Package.
4. Create a Java class called StaticSampleApp.java in the package. To do this, right-click the package in the Package Explorer and select New > Class.
5. Delete the default contents of the new source file and copy the entire file listed in Listing 3-9 into the source file.
6. Save the file. Figure 3-3 shows the completed project configuration in the Eclipse IDE.
Figure 3-3 Completed Project Configuration

Note: | The imported classes CUSTOMERDAS and CUSTOMER (see Listing 3-9) are located in the Static Mediator Client JAR file, which must be in the CLASSPATH.

Listing 3-9 StaticSampleApp.java

    package com.bea.dsp.sample;

    import das.ejb.retail.CUSTOMERDAS;
    import retail.customer.CUSTOMER;

    import com.bea.dsp.das.DASResult;
    import com.bea.dsp.sdo.SDOUtil;

    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class StaticSampleApp {
        public static void main(String[] args) throws Exception {
            // Create InitialContext for mediator
            Hashtable<String, String> hash = new Hashtable<String, String>();
            hash.put(Context.INITIAL_CONTEXT_FACTORY,
                     "weblogic.jndi.WLInitialContextFactory");
            hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
            hash.put(Context.SECURITY_PRINCIPAL,"weblogic");
            hash.put(Context.SECURITY_CREDENTIALS,"weblogic");
            Context ctx = new InitialContext(hash);

            // Create DataAccessService handle with Context and dataspace name
            CUSTOMERDAS das = CUSTOMERDAS.getInstance(ctx, "MediatorSamples");

            // Invoke the basic 'get all customers' function
            DASResult<CUSTOMER> result = das.CUSTOMER();

            // Obtain the first CUSTOMER DataObject - also be sure to
            // always dispose() any DASResults
            try {
                CUSTOMER customer = result.next();

                // Enable change-tracking for that CUSTOMER
                SDOUtil.enableChanges(customer);

                // Modify customer
                customer.setFIRST_NAME("New First Name");
                customer.setEMAIL_ADDRESS("first_name@example.com");

                // Send changes back to DSP - update function takes an array
                // of CUSTOMERs
                das.updateCUSTOMER(new CUSTOMER[] { customer });
            }
            finally {
                result.dispose();
            }
        }
    }

### Running and Testing the Code

To test the application:

1. Start the server.
2. Run the Java client as a Java application. In Eclipse, this is commonly done by right-clicking the Java file and selecting Run As > Java Application.

To verify that the Java client worked, simply test the data service:

1. Open the data service in the Data Service editor.
2. Click the Test tab (see Figure 3-4).
3. Select an operation from the drop down menu. For this example, select the CUSTOMER() operation.
4. Click Run (see Figure 3-4).
5. Inspect the first row of the data table. The client application changes the first customer’s name and email address to “New First Name” and “first_name@example.com” as shown in Figure 3-4.
Figure 3-4 Testing the Client

### Examining the Sample Code

This section examines the parts of the Java sample in Listing 3-9. This section discusses:

- Importing Packages
- Obtaining a Data Access Service Handle
- Retrieving Data from the Service
- Obtaining a DataObject from the Result
- Disposing the Result Object
- Modifying the DataObject
- Returning Changes to the Server

#### Importing Packages

The first two classes are located in the generated Mediator Client JAR file, which must be in your build path. The CUSTOMERDAS class is the generated DataAccessService class for the data service. This class contains type-safe methods that map to the actual data service operations. The CUSTOMER class provides the SDO interface for manipulating DataObjects returned from the data service.

    import das.ejb.retail.CUSTOMERDAS;
    import retail.customer.CUSTOMER;

    import com.bea.dsp.das.DASResult;
    import com.bea.dsp.sdo.SDOUtil;

    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.InitialContext;

#### Obtaining a Data Access Service Handle

A DataAccessService object lets you call methods on a data service. See the Javadoc for more information on this class. For the Static Mediator API, DataAccessService (DAS) classes have a factory method named getInstance() to return the handle.

The getInstance() method requires two parameters to return the handle:

- A WebLogic JNDI Context object. The Context object allows the Java client to connect to the data service running through WebLogic Server. See Obtaining the WebLogic JNDI Context for Oracle Data Service Integrator. For more information on WebLogic JNDI context objects, see Programming WebLogic JNDI on e-docs.
- The name of the Dataspace project in which the data service is deployed. In this sample, the project is called MediatorSamples.

Hashtable<String, String> hash = new Hashtable<String, String>();
hash.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
hash.put(Context.SECURITY_PRINCIPAL,"weblogic");
hash.put(Context.SECURITY_CREDENTIALS,"weblogic");
Context ctx = new InitialContext(hash);
CUSTOMERDAS das = CUSTOMERDAS.getInstance(ctx, "MediatorSamples");

#### Retrieving Data from the Service

The generated DataAccessService method CUSTOMER() retrieves the result set from the data service. This method returns all customer objects from the data service. The return type is a DASResult object, which works like an iterator. For more information on this return type, see Understanding DASResult.

DASResult<CUSTOMER> result = das.CUSTOMER();

Note: | The method CUSTOMER() is mapped directly from the original no-argument data service operation of the same name. The operation definition as specified in the data service file looks like this:

Note: | (::pragma function <f:function xmlns:f="urn:annotations.ld.bea.com" visibility="public" kind="read" isPrimary="false" nativeName="CUSTOMER" nativeLevel2Container="SAMPLECUSTOMER" style="table"> <nonCacheable/> </f:function>::) declare function f1:CUSTOMER() as schema-element(t1:CUSTOMER)* external;

Note: | The entire data service file is shown in Listing 3-6.

#### Obtaining a DataObject from the Result

The DASResult.next() method works very much like the Java method Iterator.next(). It returns the next CUSTOMER, which is an SDO DataObject. SDO is a Java-based data programming model (API) and architecture for accessing and updating data. For details on SDO, see Using Service Data Objects (SDO) in the Oracle Data Service Integrator Concepts Guide.

CUSTOMER customer = result.next();

#### Disposing the Result Object

You must call DASResult.dispose() whenever you are finished iterating through a result object. For more information on dispose(), see Disposing of DASResult Objects.

    result.dispose();

Tip: | Placing the dispose() call in a try/finally block is a recommended best practice.

#### Modifying the DataObject

After you obtain a DataObject, you can modify it; however, if you intend to submit these changes back to the Oracle Data Service Integrator server, you must enable change-tracking on the DataObject before making any modifications. The SDOUtil.enableChanges() method lets you enable change-tracking for a single DataObject or an array of DataObjects. For more information on this method, see Working with Data Objects. After the customer object has change-tracking enabled, the generated setters are called to modify certain values in the customer object.

Tip: | Note that the set method below is called on an SDO DataObject. Technically, such methods are part of the SDO API, not the Mediator API. See Chapter 2, “Data Programming Model and Update Framework” for information on SDO.

    SDOUtil.enableChanges(customer);

    // Modify customer
    customer.setFIRST_NAME("New First Name");
    customer.setEMAIL_ADDRESS("first_name@example.com");

#### Returning Changes to the Server

Finally, the generated DataAccessService.updateCUSTOMER() method is called with a single parameter: an array of CUSTOMER objects. The method calls its equivalent data service operation to update the database with the newly modified row of data.

das.updateCUSTOMER(new CUSTOMER[] { customer });

Tip: | In this example, the update method generated by Oracle Data Service Integrator accepts an array of DataObjects. It accepts an array because the data service operation (created by the data service developer) accepts an array of data objects. If the data service developer had created an additional update method that accepted a single CUSTOMER, it would not be necessary to put the customer DataObject into an array.

## Sample Dynamic Mediator Application

This section presents a simple example that you can copy, compile, and run. This example uses the Dynamic Mediator API to perform these basic tasks: authenticating the client, retrieving data, modifying data, and updating data on the server.

The topics in this section include:

- Setting Up and Running the Sample Code
- Sample Java Client Code (Dynamic Mediator API)
- Examining the Sample Code

### Setting Up and Running the Sample Code

To set up and run this sample code, follow the basic instructions in Sample Static Mediator Application. The procedures for creating a sample data service, setting up the Java project, and running the program are the same as the Static Mediator sample; however, when using the Dynamic Mediator API, you do not need to generate or reference the Static Mediator Client JAR file. Use the sample Java code shown in Listing 3-10 in your project.

### Sample Java Client Code (Dynamic Mediator API)

Listing 3-10 DynamicSampleApp.java

    package com.bea.dsp.sample;

    import com.bea.dsp.das.DataAccessServiceFactory;
    import com.bea.dsp.das.DataAccessService;
    import com.bea.dsp.das.DASResult;
    import com.bea.dsp.sdo.SDOUtil;

    import commonj.sdo.DataObject;

    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class DynamicSampleApp {
        public static void main(String[] args) throws Exception {
            // Create InitialContext for mediator
            Hashtable<String, String> hash = new Hashtable<String, String>();
            hash.put(Context.INITIAL_CONTEXT_FACTORY,
                     "weblogic.jndi.WLInitialContextFactory");
            hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
            hash.put(Context.SECURITY_PRINCIPAL,"weblogic");
            hash.put(Context.SECURITY_CREDENTIALS,"weblogic");
            Context ctx = new InitialContext(hash);

            // Create DataAccessService handle with Context, dataspace
            // name, and data service URI
            DataAccessService das = DataAccessServiceFactory.newDataAccessService
                (ctx, "MediatorSamples", "ld:Retail/CUSTOMER");

            // Invoke the basic 'get all customers' function, which takes
            // no arguments
            DASResult<Object> result = das.invoke("CUSTOMER", new Object[0]);

            // Obtain the first CUSTOMER DataObject - also be sure to
            // always dispose() any DASResults
            try {
                DataObject customer = (DataObject) result.next();

                // Enable change-tracking for that CUSTOMER
                SDOUtil.enableChanges(customer);

                // Modify customer
                customer.set("FIRST_NAME", "DynamicClient");
                customer.set("EMAIL_ADDRESS", "dynamic@example.com");

                // Send changes back to DSP - update function takes an array
                // of CUSTOMERs
                das.invoke("updateCUSTOMER", new Object[] { customer });
            }
            finally {
                result.dispose();
            }
        }
    }

### Examining the Sample Code

This section examines the parts of the Java sample in Listing 3-10. This section discusses:

- Importing Classes
- Obtaining a DataAccessService Handle
- Retrieving Data from the Service
- Obtaining a DataObject from the Result
- Disposing the Result Object
- Modifying the DataObject
- Returning Changes to the Server

#### Importing Classes

These classes are required by the sample. For detailed information on the classes, refer to the Javadoc on e-docs.

    import com.bea.dsp.das.DataAccessServiceFactory;
    import com.bea.dsp.das.DataAccessService;
    import com.bea.dsp.das.DASResult;
    import com.bea.dsp.sdo.SDOUtil;
    import commonj.sdo.DataObject;
    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.InitialContext;

#### Obtaining a DataAccessService Handle

A DataAccessService object lets you call methods on a data service. See the Javadoc for more information on this class. The DataAccessServiceFactory class requires three parameters to return the handle:

- A WebLogic JNDI Context object. The Context object allows the Java client to connect to the data service running through WebLogic Server and provides security attributes. See Obtaining the WebLogic JNDI Context for Oracle Data Service Integrator. For more information on WebLogic JNDI context objects, see Programming WebLogic JNDI on e-docs.
- The name of the Dataspace project in which the data service is deployed.
- The name of the data service as based on its location in the Dataspace’s folder hierarchy.

Here is the code:

Hashtable<String, String> hash = new Hashtable<String, String>();
hash.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
hash.put(Context.SECURITY_PRINCIPAL,"weblogic");
hash.put(Context.SECURITY_CREDENTIALS,"weblogic");
Context ctx = new InitialContext(hash);
DataAccessService das = DataAccessServiceFactory.newDataAccessService
(ctx, "MediatorSamples", "ld:Retail/CUSTOMER");

#### Retrieving Data from the Service

In this example, the invoke() method calls the data service CUSTOMER operation. This operation returns all customer objects from the data service. The invoke() method returns a DASResult object, which works like an iterator. For more information on this return type, see Understanding DASResult. Note that the CUSTOMER operation takes no arguments.

DASResult<Object> result = das.invoke("CUSTOMER", new Object[0])

Note: | The generic type parameter for DASResult is <Object> because data of any type can be returned by the invoke() method of the Dynamic Mediator API.

#### Obtaining a DataObject from the Result

The DASResult.next() method works very much like the Java method Iterator.next(). It returns the next object in the result set. Because the CUSTOMER data service method returns SDO-compliant DataObjects, you can cast the return value to DataObject. SDO is a Java-based data programming model (API) and architecture for accessing and updating data. For details on SDO, see Using Service Data Objects (SDO) in the Oracle Data Service Integrator Concepts Guide. See also What is SDO?.

DataObject customer = (DataObject) result.next();

#### Disposing the Result Object

You must call DASResult.dispose() whenever you are finished iterating through a result object. For more information on dispose(), see Disposing of DASResult Objects.

        result.dispose();

Tip: | Placing the dispose() call in a try/finally block is a recommended best practice.

#### Modifying the DataObject

After you obtain a DataObject, you can modify it; however, if you intend to submit these changes back to the Oracle Data Service Integrator server, you must enable change-tracking on the DataObject before making any modifications. The SDOUtil.enableChanges() method lets you enable change-tracking for a single DataObject or an array of DataObjects. For more information on this method, see Working with Data Objects. After the customer object has change-tracking enabled, the Dynamic SDO set() method is called to modify certain values in the customer object. For more information on SDO methods, see Chapter 2, “Data Programming Model and Update Framework.”

SDOUtil.enableChanges(customer);
customer.set("FIRST_NAME", "DynamicClient");
customer.set("EMAIL_ADDRESS", "dynamic@example.com");

#### Returning Changes to the Server

Finally, the DataAccessService method invoke() calls the update method on the data service with a single parameter: an array of CUSTOMER objects. The data service operation updates the database with the newly modified row of data.

das.invoke("updateCUSTOMER", new Object[] { customer });

Tip: | In this example, the update method accepts an array of DataObjects. It accepts an array because the data service operation (created by the data service developer) accepts an array of data objects. If the data service developer had created an additional update method that accepted a single CUSTOMER, it would not be necessary to put the customer DataObject into an array.

## Creating New DataObjects

This section explains how to use the Data Services Mediator and SDO APIs to create new data objects and submit them to the Oracle Data Service Integrator server. As with previous examples, both the static and dynamic APIs are illustrated.

### Creating a New DataObject with the Static API

The Java program in Listing 3-11 creates a new DataObject, modifies it, and updates it on the Oracle Data Service Integrator server.

#### Setting Up and Running the Sample

The sample code in Listing 3-11 is designed to work in the same Java project and with the same data service project that are described in Sample Static Mediator Application. You can run the sample code presented here by following the setup instructions in that section. When you test the data service, you will see a new row has been added to the table.

Listing 3-11 StaticCreateSample.java

    package com.bea.dsp.sample;

    import das.ejb.retail.CUSTOMERDAS;
    import retail.customer.CUSTOMER;
    import retail.customer.CUSTOMER_KEY;

    import com.bea.dsp.das.DASResult;
    import com.bea.dsp.sdo.SDOUtil;

    import commonj.sdo.helper.HelperContext;
    import commonj.sdo.helper.DataFactory;

    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class StaticCreateSample {
        public static void main(String[] args) throws Exception {
            // Create InitialContext for mediator
            Hashtable<String, String> hash = new Hashtable<String, String>();
            hash.put(Context.INITIAL_CONTEXT_FACTORY,
                     "weblogic.jndi.WLInitialContextFactory");
            hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
            hash.put(Context.SECURITY_PRINCIPAL,"weblogic");
            hash.put(Context.SECURITY_CREDENTIALS,"weblogic");
            Context ctx = new InitialContext(hash);

            // Create DataAccessService handle with Context and dataspace name
            CUSTOMERDAS das = CUSTOMERDAS.getInstance(ctx, "MediatorSamples");

            // Obtain the SDO HelperContext for this dataspace
            HelperContext hctx = das.getHelperContext();
            // Could also use:
            // HelperContext hctx = HelperContextCache.get("MediatorSamples");

            // Get DataFactory from HelperContext
            DataFactory factory = hctx.getDataFactory();

            // Create an "empty" CUSTOMER DataObject by naming the XML
            // schema *type*. For schema global elements that do not
            // explicitly specify a type, their type name will be the same
            // as the element name.
            CUSTOMER customer = (CUSTOMER) factory.create
                ("ld:Retail/CUSTOMER", "CUSTOMER");

            // Have to provide this DataObject with its own name. Note
            // that this is the XML schema *name*, not the *type* -
            // although as noted, when the global element does not
            // explicitly specify a type, the type that is provided for it
            // has the same name as the element.
            SDOUtil.setElementName(customer, "ld:Retail/CUSTOMER", "CUSTOMER");

            // Note that you must NOT enable change-tracking for this
            // DataObject using enableChanges(). Change-tracking is only
            // for tracking changes to data originally received from the
            // DSP server.

            // Set fields on new DataObject. Don't set auto-generated
            // fields, such as CUSTOMER_ID. May omit optional fields or
            // those with default values
            customer.setFIRST_NAME("New First Name");
            customer.setLAST_NAME("New Last Name");
            customer.setCUSTOMER_SINCE("2007-10-18");
            customer.setEMAIL_ADDRESS("first_name@example.com");
            customer.setTELEPHONE_NUMBER("867-5309");

            // Send new DataObject to DSP - create function takes an array
            // of CUSTOMERs, and returns CUSTOMER_KEYs
            DASResult<CUSTOMER_KEY> result =
                das.createCUSTOMER(new CUSTOMER[] { customer });

            // Can obtain new customer ID from the returned key - also be
            // sure to always dispose() any DASResults.
            try {
                CUSTOMER_KEY key = result.next();
                System.out.println("New customer key: " + key.getCUSTOMER_ID());
            }
            finally {
                result.dispose();
            }

            // Note that the created DataObject is NOT automatically
            // updated based on the generated key values. If you want to
            // get a DataObject populated with the new CUSTOMER_ID, you
            // need to re-read. This is easier if the data service
            // architect provides a getByID() function on the data
            // service.
        }
    }

#### Importing Packages

Two SDO classes are required by this program. A HelperContext provides access to a consistent set of instances of SDO helpers. It represents a helper execution context. The set of helpers returned by the methods in this interface have visibility to the same SDO metadata, that is, they execute in the same “scope.” A DataFactory is a helper for the creation of DataObjects. The created DataObjects are not connected to any other DataObjects. Only Types with DataType false and abstract false may be created.

#### Obtaining a Data Access Service Handle

A DataAccessService object lets you call methods on a data service. See the Javadoc for more information on this class. For the Static Mediator API, DataAccessService (DAS) classes have a factory method named getInstance() to return the handle.

The getInstance() method requires two parameters to return the handle:

- A WebLogic JNDI Context object. The Context object allows the Java client to connect to the data service running through WebLogic Server. See Obtaining the WebLogic JNDI Context for Oracle Data Service Integrator. For more information on WebLogic JNDI context objects, see Programming WebLogic JNDI on e-docs.
- The name of the Dataspace project in which the data service is deployed. In this sample, the project is called MediatorSamples.

Hashtable<String, String> hash = new Hashtable<String, String>();
hash.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
hash.put(Context.SECURITY_PRINCIPAL,"weblogic");
hash.put(Context.SECURITY_CREDENTIALS,"weblogic");
Context ctx = new InitialContext(hash);
CUSTOMERDAS das = CUSTOMERDAS.getInstance(ctx, "MediatorSamples");

#### Creating a DataFactory

To create a DataFactory, you need to first obtain a HelperContext object for the Dataspace.

        HelperContext hctx = das.getHelperContext();

        DataFactory factory = hctx.getDataFactory();

You could also use this call to return the HelperContext:

        HelperContext hctx = HelperContextCache.get("MediatorSamples");

#### Create and Name the DataObject

After you create a DataObject, you must explicitly name it. The factory.create() method takes two String parameters. The first is a URI, the location of the data service in the Dataspace project. The second parameter is the XML schema type of the DataObject you are creating. For schema global elements that do not explicitly specify a type, their type name will be the same as the element name.

    CUSTOMER customer = (CUSTOMER) factory.create("ld:Retail/CUSTOMER", "CUSTOMER");

Next, you must provide the new DataObject with a name. The SDOUtil.setElementName() method takes these parameters: the DataObject, the namespace URI of the element QName, and the local part of the element QName.

Note that this name is the XML schema name, not the type. However, as noted, for global elements that do not specify a type, the type that is provided has the same name as the element.

    SDOUtil.setElementName(customer, "ld:Retail/CUSTOMER", "CUSTOMER");

#### Modifying the DataObject

After you create a new DataObject, you can modify it before submitting it to the server.

Note: | You must not enable change-tracking in this new DataObject using the SDOUtil.enableChanges() method. Change-tracking is only used for tracking changes to data that was originally received from the Oracle Data Service Integrator server.

    customer.setFIRST_NAME("New First Name");
    customer.setLAST_NAME("New Last Name");
    customer.setCUSTOMER_SINCE("2007-10-18T12:27:41Z");
    customer.setEMAIL_ADDRESS("first_name@example.com");
    customer.setTELEPHONE_NUMBER("867-5309");

Tip: | You can omit optional fields or fields with default values.

#### Returning New DataObject to the Server

After the new object is created, the data service operation createCUSTOMER is called from the Static Mediator API. The data service create operation takes an array of objects as input. The Mediator API method returns a CUSTOMER_KEY objects in a DASResult.

    DASResult<CUSTOMER_KEY> result = das.createCUSTOMER(new CUSTOMER[] { customer });

#### Returning the New DataObject Key

To return the CUSTOMER_KEY for the new CUSTOMER object, call the next() method on the DASResult object. Be sure to dispose the DASResult object (result) after it is returned. Placing dispose() in a try/finally block is a recommended best practice.

try {
CUSTOMER_KEY key = result.next();
System.out.println("New customer key: " + key.getCUSTOMER_ID());
}
finally {
result.dispose();
}

Tip: | The newly created local copy of the DataObject (`customer`, in this example) is not automatically updated with generated keys such as CUSTOMER_ID. If you want to obtain a DataObject populated with CUSTOMER_ID, you need to retrieve the new DataObject from the server by invoking the data service’s read operation. This is easier if the data service developer provides a getByID() operation on the data service.

### Creating a New DataObject with the Dynamic API

The Java program in Listing 3-11 creates a new DataObject, modifies it, and updates it on the Oracle Data Service Integrator server.

#### Running the Sample

The sample code in Listing 3-12 is designed to work in the same Java project and with the same data service project that are described in Sample Dynamic Mediator Application. You can run the sample code presented here by following the setup instructions in that section.

Listing 3-12 DynamicCreateSample.java

    package com.bea.dsp.sample;

    import com.bea.dsp.das.DataAccessService;
    import com.bea.dsp.das.DataAccessServiceFactory;
    import com.bea.dsp.das.DASResult;
    import com.bea.dsp.das.HelperContextCache;
    import com.bea.dsp.sdo.SDOUtil;

    import commonj.sdo.helper.HelperContext;
    import commonj.sdo.helper.DataFactory;
    import commonj.sdo.DataObject;

    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.InitialContext;

    public class DynamicCreateSample {
        public static void main(String[] args) throws Exception {
            // Create InitialContext for mediator
            Hashtable<String, String> hash = new Hashtable<String, String>();
            hash.put(Context.INITIAL_CONTEXT_FACTORY,
                     "weblogic.jndi.WLInitialContextFactory");
            hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
            hash.put(Context.SECURITY_PRINCIPAL,"weblogic");
            hash.put(Context.SECURITY_CREDENTIALS,"weblogic");
            Context ctx = new InitialContext(hash);

            // Obtain the SDO HelperContext for this dataspace. As with
            // StaticCreateSample, I could obtain this from the
            // DataAccessService. However, here I'm demonstrating how to
            // create an all-new DataObject prior to creating any
            // DataAccessService instance. In this case, since I'm using
            // the dynamic mediator, I need to first ensure that the
            // global HelperContext cache is populated with the schemas
            // for my data service.
            HelperContextCache.loadSchemasForDataspace
                (ctx, "MediatorSamples", "ld:Retail/CUSTOMER");

            // Now that the schemas are loaded, I can get the
            // HelperContext for the dataspace
            HelperContext hctx = HelperContextCache.get("MediatorSamples");

            // Get DataFactory from HelperContext
            DataFactory factory = hctx.getDataFactory();

            // Create an "empty" CUSTOMER DataObject by naming the XML
            // schema *type*. For schema global elements that do not
            // explicitly specify a type, their type name will be the same
            // as the element name.
            DataObject customer = factory.create("ld:Retail/CUSTOMER", "CUSTOMER");

            // Have to provide this DataObject with its own name. Note
            // that this is the XML schema *name*, not the *type* -
            // although as noted, when the global element does not
            // explicitly specify a type, the type that is provided for it
            // has the same name as the element.
            SDOUtil.setElementName(customer, "ld:Retail/CUSTOMER", "CUSTOMER");

            // Note that you must NOT enable change-tracking for this
            // DataObject using enableChanges(). Change-tracking is only
            // for tracking changes to data originally received from the
            // DSP server.

            // Set fields on new DataObject. Don't set auto-generated
            // fields, such as CUSTOMER_ID. May omit optional fields or
            // those with default values
            customer.set("FIRST_NAME", "Dynammic");
            customer.set("LAST_NAME", "Mediator");
            customer.set("CUSTOMER_SINCE", "2007-10-18");
            customer.set("EMAIL_ADDRESS", "dynamic@example.com");
            customer.set("TELEPHONE_NUMBER", "867-5309");

            // Create DataAccessService handle with Context and dataspace name
            DataAccessService das = DataAccessServiceFactory.newDataAccessService
                (ctx, "MediatorSamples", "ld:Retail/CUSTOMER");

            // Send new DataObject to DSP - create function takes an array
            // of CUSTOMERs, and returns CUSTOMER_KEYs
            DASResult<Object> result =
                das.invoke("createCUSTOMER", new Object[] { customer });

            // Can obtain new customer ID from the returned key. Always be
            // sure to dispose() any DASResults you get.
            try {
                DataObject key = (DataObject) result.next();
                System.out.println("New customer key: " + key.get("CUSTOMER_ID"));
            }
            finally {
                result.dispose();
            }

            // Note that the created DataObject is NOT automatically
            // updated based on the generated key values. If you want to
            // get a DataObject populated with the new CUSTOMER_ID, you
            // need to re-read. This is easier if the data service
            // architect provides a getByID() function on the data
            // service.
        }
    }

#### Importing Packages

Three SDO classes are required by this program. A DataObject is a representation of some structured data. It is the fundamental component in the SDO (Service Data Objects) package. A HelperContext provides access to a consistent set of instances of SDO helpers. It represents a helper execution context. The set of helpers returned by the methods in this interface have visibility to the same SDO metadata, that is, they execute in the same “scope.” A DataFactory is a helper for the creation of DataObjects. The created DataObjects are not connected to any other DataObjects. Only Types with DataType false and abstract false may be created.

This example also uses the com.bea.dsp.das.HelperContextCache class, which provides access to the global cache of SDO HelperContext objects maintained by Oracle Data Service Integrator. The use of HelperContextCache is described in the next section Creating a DataFactory.

#### Creating a DataFactory

As with the static mediator example discussed previously, we need to obtain the SDO HelperContext for this Dataspace. In the static example, we created the HelperContext from the DataAccessService. However, in this example, we create a new DataObject before we create the DataAccessService instance. To do this, you need to ensure that the global HelperContext cache is populated with the data service schemas.

HelperContextCache.loadSchemasForDataspace
(ctx, "MediatorSamples", "ld:Retail/CUSTOMER");
// Now that the schemas are loaded, get the HelperContext for the dataspace.
HelperContext hctx = HelperContextCache.get("MediatorSamples");
DataFactory factory = hctx.getDataFactory();

Tip: | For detailed information on HelperContextCache, refer to the Javadoc.

#### Create and Name the DataObject

When you create a DataObject, you must explicitly name it. The factory.create() method takes two String parameters. The first is a URI, the location of the data service in the Dataspace project. The second parameter is the XML schema type of the DataObject you are creating. For schema global elements that do not explicitly specify a type, their type name will be the same as the element name.

    DataObject customer = factory.create("ld:Retail/CUSTOMER", "CUSTOMER");

Next, you must provide the new DataObject with a name. The SDOUtil.setElementName() method takes these parameters: the DataObject, the namespace URI of the element QName, and the local part of the element QName.

Note that this name is the XML schema name, not the type. However, as noted, for global elements that do not specify a type, the type that is provided has the same name as the element.

    SDOUtil.setElementName(customer, "ld:Retail/CUSTOMER", "CUSTOMER");

#### Modifying the DataObject

After you create a new DataObject, you can modify it before submitting it to the server.

Note: | You must not enable change-tracking in this new DataObject using the SDOUtil.enableChanges() method. Change-tracking is only used for tracking changes to data that was originally received from the Oracle Data Service Integrator server.

        customer.set("FIRST_NAME", "New First Name");
        customer.set("LAST_NAME", "New Last Name");
        customer.set("CUSTOMER_SINCE", "2007-10-18T12:27:41Z");
        customer.set("EMAIL_ADDRESS", "first_name@example.com");
        customer.set("TELEPHONE_NUMBER", "867-5309");

Tip: | You can omit optional fields or fields with default values.

#### Returning New DataObject to the Server

You need a DataAccessService handle to call methods on the data service. A DataAccessService object lets you call methods on a data service. See the Javadoc for more information on this class. The DataAccessServiceFactory class requires three parameters to return the handle:

- A WebLogic JNDI Context object. The Context object allows the Java client to connect to the data service running through WebLogic Server and provides security attributes. See Obtaining the WebLogic JNDI Context for Oracle Data Service Integrator. For more information on WebLogic JNDI context objects, see Programming WebLogic JNDI on e-docs.
- The name of the Dataspace project in which the data service is deployed.
- The name of the data service as based on its location in the Dataspace’s folder hierarchy.

The DataAccessServiceFactory returns the handle.

// Create DataAccessService handle with Context and dataspace name
DataAccessService das = DataAccessServiceFactory.newDataAccessService
(ctx, "MediatorSamples", "ld:Retail/CUSTOMER");

The DataAccessService.invoke() method is used to call the createCUSTOMER data service operation on the server. Note that the createCUSTOMER data service operation is designed to take an array of objects as input. The function returns a CUTOMER_KEYS objects in the DASResult object.

DASResult<Object> result =
das.invoke("createCUSTOMER", new Object[] { customer });

#### Returning the New DataObject Key

To return the key for the new CUSTOMER object, call the next() method on the DASResult object. Be sure to dispose the DASResult object (result) after it is returned. Placing dispose() in a try/finally block is a recommended best practice.

try {
DataObject key = (DataObject) result.next();
System.out.println("New customer key: " + key.get("CUSTOMER_ID"));
}
finally {
result.dispose();
}

Tip: | The newly created local copy of the DataObject (`customer`, in this example) is not automatically updated with generated keys such as CUSTOMER_ID. If you want to obtain a DataObject populated with CUSTOMER_ID, you need to retrieve the new DataObject from the server by invoking the data service’s read operation. This is easier if the data service developer provides a getByID() operation on the data service.

## Mediator API Basics

This section discusses various Mediator API topics.

- Beyond the Sample Applications
- More on the Static Mediator API
- More on the Dynamic Mediator API
- Naming Conventions for Generated Classes
- Understanding DASResult
- Obtaining the WebLogic JNDI Context for Oracle Data Service Integrator
- Working with Data Objects

### Beyond the Sample Applications

It is recommended that you review and run the sample applications provided in this chapter:

- Sample Static Mediator Application
- Sample Dynamic Mediator Application

Although the sample code is very basic, it demonstrates common use cases of retrieving, modifying, and updating data. The samples also include details to help you understand the code.

The rest of this chapter discusses additional features of the APIs as well as advanced topics and important reference material.

### More on the Static Mediator API

When called through the Static Mediator API, data service operations that return empty() or that return a single item do not return DASResult; instead, they return void or the single item. See also Understanding DASResult.

### More on the Dynamic Mediator API

This section provides additional information on the Dynamic Mediator API.

- Invoking Data Service Operations
- Getters and Setters

#### Invoking Data Service Operations

The invoke(String method, Object[] args) method dynamically invokes data service operations. When an operation is invoked (getCustomerByCustID(), for example), it returns a DASResult object. All data service functions return a DASResult when called through the Dynamic Mediator API. See also Understanding DASResult.

You can see the invoke() method in use in the Dynamic Mediator API sample in Listing 3-10, DynamicSampleApp.java, on page 3-26:

      DASResult<Object> result = das.invoke("updateCustomer", new Object[0]);

More information on the invoke() method is available in Javadoc on e-docs.

#### Getters and Setters

SDO provides generic getters and setters for working with data objects. The SDO API can be used with data types that have not yet been deployed at development time. XPath expressions are passed as arguments to the generic methods. For example:

customer.set("EMAIL_ADDRESS", "first_name@example.com");

or

String name = customer.get("EMAIL_ADDRESS");

See also Specifying XPath Expressions as Arguments and Chapter 2, “Data Programming Model and Update Framework.”

### Naming Conventions for Generated Classes

When you generate a Mediator Client JAR file or a Web Services Mediator Client JAR file, the generated DataAccessService subclasses and packages are named according to the following conventions:

#### Mediator Client JAR Naming Convention

Generated DataAccessService subclasses are named <Data_Service_Name>DAS.class. For example, if you generate a Mediator Client JAR file from a data service called Customer.ds, a class called CustomerDAS.class is generated in the JAR file. Package names contain das.ejb.

#### Web Services Mediator Client JAR Naming Convention

Generated DataAccessService subclasses are named <Data_Service_Name>DAS.class. For example, if you generate a Web Services Mediator Client JAR from a web service map file called Customer.ws, a class called CustomerDAS.class is generated in the JAR file. Package names contain das.ws.

### Understanding DASResult

The mediator APIs that return data sets return an object called DASResult (Data Access Service Result). DASResult is similar to a Java Iterator.

This section includes these topics:

- Overview of DASResult
- Disposing of DASResult Objects
- Dynamic Mediator APIs and DASResult
- Static Mediator APIs and DASResult
- Retrieving an Array of Objects

#### Overview of DASResult

By default, data is returned to the Mediator from the Oracle Data Service Integrator server in small blocks. This “streaming” behavior means that large result sets are never held in memory all at once on either the Oracle Data Service Integrator server or the client application, which optimizes memory utilization. However, this requires that resources on the server be held open until all results have been returned to the client. See Support for Stateless Operations.

For example, the signature for the invoke() method is:

DASResult<Object> invoke(String operation, Object[] args) throws DASException;

Like an Iterator object, DASResult is forward-only; there is no way to return to a previous item nor to restart the iteration.

DASResult includes these standard Java Iterator methods:

- Object next() throws DASException;
- boolean hasNext();

Note: | The Java Iterator remove() method is not included because DASResult is a read-only object.

All complex XML items in the DASResult object are represented as DataObjects. All simple items (which can be returned from library data service operations) in the result are represented by a corresponding Java object, such as Integer, Long, and so on. For information on how types are mapped to schema types, see Mapping Data Service Types to Java Types. See also Making Ad Hoc Queries.

Tip: | All mediator methods that return DASResult never return NULL; if the data service function returns no results, then the DASResult iterates through zero items. That is, hasNext() immediately returns false and next() returns NULL.

#### Disposing of DASResult Objects

The server is required to hold open resources such as database handles until the code finishes iterating through all of the results. Therefore, you are required to dispose of returned DASResult objects to tell the server to release the resources.

DASResult includes the following methods:

void dispose() – Disposes of resources required by DASResult on the Oracle Data Service Integrator server.

boolean isDisposed() – Returns whether the connection to the Oracle Data Service Integrator server has been closed.

Note: | You must call dispose() when you are finished iterating through a DASResult. If you call dispose() on a result object that has already been disposed, nothing happens, and no error is generated.

The dispose() method is automatically called for you in the following two cases:

- You use the FETCH_ALL_IMMEDIATELY feature of the RequestConfig object. For more information this feature, see Support for Stateless Operations.
- You use the DASResult.getItems() method. For more information, see Retrieving an Array of Objects.

#### Dynamic Mediator APIs and DASResult

All Dynamic Mediator API methods that return XQuery results return a DASResult object. These methods include:

- The basic invoke() method
- The form of invoke() that takes a RequestConfig object. See API Overview for information on RequestConfig.
- All forms of PreparedExpression.executeQuery() for ad-hoc queries. For details on forming ad-hoc queries, see “Using Ad Hoc Queries to Fine-tune Results from the Client” on page 8-25.

#### Static Mediator APIs and DASResult

In the Static Mediator API, all generated methods for data service operations that have plural results are declared to return a DASResult<T>. Plural results are results of data service operations whose XQuery return type is `type*` (zero or more instances of the type) or `type+` (one or more instances of the type). T is the class of DataObjects that are returned by the DASResult.next().

Generated methods for data service operations that have a maximum of one return value (that is, data service operations whose XQuery return type is `type` or `type?`) will be declared to return the corresponding Java type directly, rather than a DASResult object. In addition, a data service operation whose return type is empty() will generate a static mediator method with a return type of void. See Mapping Data Service Types to Java Types for more information.

#### Retrieving an Array of Objects

DASResult includes a method T[] getItems(). This method returns the results as an array. This method immediately disposes the DASResult. See Disposing of DASResult Objects.

- You must call getItems() before any calls to DASResult.next(). If you call getItems() after any calls to next() an IllegalStateException is thrown.
- If you call next() after calling getItems(), an IllegalStateException is thrown.
- When you call getItems(), all results are materialized in memory on the client at once.

### Obtaining the WebLogic JNDI Context for Oracle Data Service Integrator

Java client applications use JNDI to access named objects, such as data services, on a Oracle WebLogic Server. To use any of the Mediator APIs, you need to obtain the WebLogic Server JNDI context for Oracle Data Service Integrator. This context allows the mediator APIs to call data service operations and acquire information from data services. For more information on WebLogic JNDI context objects, see Programming WebLogic JNDI on e-docs.

Use the following call to obtain the JNDI context. The hashtable parameter is explained below.

InitialContext jndiCtxt = new InitialContext(hashtable);

Table 3-5 lists the keys and values that you can insert into the hashtable parameter.

Table 3-5 JNDI Context Keys and Values
Key | Value
Context.INITIAL_CONTEXT_FACTORY | weblogic.jndi.WLInitialContextFactory
Context.PROVIDER_URL | URL of the WebLogic Server hosting Oracle Data Service Integrator. For example: `t3://localhost:7001`.
Context.SECURITY_PRINCIPAL | (optional) A username
Context.SECURITY_CREDENTIALS | (optional) A password

Listing 3-13 shows example code for obtaining the JNDI context.

Listing 3-13 Obtaining the JNDI Context

    Hashtable h = new Hashtable();
       h.put(Context.INITIAL_CONTEXT_FACTORY,
       "weblogic.jndi.WLInitialContextFactory");
       h.put(Context.PROVIDER_URL,"t3://machinename:7001");
       h.put(Context.SECURITY_PRINCIPAL,<username>);
       h.put(Context.SECURITY_CREDENTIALS,<password>);
      InitialContext jndiCtxt = new InitialContext(h);

### Working with Data Objects

When you invoke a data service operation using the Mediator API, a collection of SDO-compliant data objects is returned in a DASResult object. (See also Understanding DASResult.)

This section discusses working with DataObjects within the context of a Java client. For more details on SDO data objects and the SDO API, see Chapter 2, “Data Programming Model and Update Framework.”

#### Enabling Data Objects for Change Tracking

Before you make any changes to a DataObject, you must enable it for change tracking. To do this, pass the DataObject to the com.bea.dsp.sdo.SDOUtil.enableChanges() method. For example:

    SDOUtil.enableChanges(customer);

There are two forms of enableChanges(). One takes a DataObject and the other takes an array of DataObjects:

    com.bea.dsp.sdo.SDOUtil.enableChanges(DataObject);

    com.bea.dsp.sdo.SDOUtil.enableChanges(DataObject[]);

Tip: | When a DataObject that is enabled for changes is returned to the server, it contains its original data and its changed data. The mechanics of handling changed data is somewhat complex; therefore, the SDOUtil.enableChanges() utility method was created to handle those details.

#### Modifying Data Object Properties

After you pass a DataObject to enableChanges(), you can make any allowable modifications to the DataObject using the standard SDO APIs. See Chapter 2, “Data Programming Model and Update Framework” for detailed information on the SDO API interfaces.

SDO provides static (typed) and dynamic (untyped) interfaces. For details, see “Static Data Object API” on page 2-4 and “Dynamic Data Object API” on page 2-8.

Example static (typed) method call:

customer.setFIRST_NAME("New First Name");

Example dynamic (untyped) method call:

customer.set("FIRST_NAME", "New First Name");

After an SDO object is enabled for change and modified, it can be passed as an argument to an update method. Oracle Data Service Integrator then handles the details of performing the update. For example, from Listing 3-9, StaticSampleApp.java, on page 3-19:

    das.updateCUSTOMER(new CUSTOMER[] { customer });

#### Creating a New Data Object

You can use the API to create a completely new data object. In RDBMS terms this would be considered creating a new record. Data object creation is an advanced topic. For detailed information, see Creating New DataObjects.

## Mapping Data Service Types to Java Types

This section explains how types in data services are mapped to Java types by the Mediator API. For example, the Static Mediator API generator makes these type conversions when creating a Mediator Client JAR file. This section also helps you understand how argument types passed to Mediator API methods are mapped to corresponding XQuery types.

Topics in this section include:

- Conversion of Simple Types
- Conversion of Date/Time Types
- Passing Empty Sequence Arguments
- Quantified Return Types
- What is Autoboxing?

### Conversion of Simple Types

Table 3-6 specifies how simple XQuery types are converted to Java types by the Mediator API. For example, a data service operation that returns xs:int produces a Java method that returns a Java Integer object. An operation that returns xs:int* (zero or more ints) returns a DASResult<Integer> object. (See also Static Mediator APIs and DASResult.)

Note: | Simple types in are mapped to Java Objects when returned from the mediator in a manner that is identical to the SDO for Java Specification V2.1. You can find this specification online at: www.osoa.org/display/Main/Service+Data+Objects+Specifications.

Note: | The following XQuery types are discussed by the SDO specification but are not supported for input or output from the Mediator API: xs:ENTITIES, xs:ENTITY, xs:ID, xs:IDREF, xs:IDREFS, xs:language, xs:Name, xs:NCName, xs:NMTOKEN, xs:NMTOKENS, xs:NOTATION.

Table 3-6 Simple XQuery to Java Type Conversion
XQuery Type | Mediator Accepts | Mediator Returns
xs:boolean | Boolean | Boolean
xs:byte | Byte | Byte
xs:short | Short | Short
xs:int | Integer | Integer
xs:long | Long | Long
xs:integer | BigInteger | BigInteger
xs:negativeInteger xs:positiveInteger xs:nonNegativeInteger xs:nonPositiveInteger | BigInteger | BigInteger
xs:unsignedByte | Short | Short
xs:unsignedShort | Integer | Integer
xs:unsignedInt | Long | Long
xs:unsignedLong | BigInteger | BigInteger
xs:float | Float | Float
xs:double | Double | Double
xs:decimal | BigDecimal | BigDecimal
xs:string | String | String
xs:anyURI | String, java.net.URI | String
xs:base64Binary | byte[] | byte[]
xs:hexBinary | byte[] | byte[]
xs:QName | javax.xml.namespace.QName | String This string is formed by concatenating a URI, a # symbol, and the local name of the QName. Input can be a string of that form or a QName object.

### Conversion of Date/Time Types

The mediator APIs handle date/time conversions in a manner that is consistent with the SDO specification. In the SDO for Java Specification V2.1, all date/time values are mapped to Java Strings. You can find this specification online at: www.osoa.org/display/Main/Service+Data+Objects+Specifications.

Note: | The form of these Strings is the same as the canonical lexical representation of the corresponding schema type according to the XML Schema specification.

Table 3-7 XQuery Date/Time Types to Java Conversions
XQuery Type | Mediator Accepts | Mediator Returns
--- | --- | ---
xs:date | String, java.sql.Date | String
xs:time | String, java.sql.Time | String
xs:dateTime | String, java.sql.Timestamp, java.util.Date, java.util.Calendar | String
xs:duration, xs:gDay, xs:gMonth, xs:gMonthDay, xs:gYear, xs:gYearMonth | String | String

### Passing Empty Sequence Arguments

If a data service operation takes an optional argument (for example `CUSTOMER?`), you can pass a NULL parameter to a Static or Dynamic Mediator method. You can pass NULL in these situations:

- As an entry in the Object[] of arguments passed to methods such as DataAccessService.invoke() or as one of the arguments to the Static Mediator method.
- As a value to PreparedExpression.bindObject(QName variable, Object value).

### Quantified Return Types

In the Static Mediator API, quantified return types from data service operations are generated based on the following rules:

Any data service parameters that are quantified with `*` or `+` (for example, `xx:int*`) have static mediator methods that are declared to return DASResult<type>.

For example, a data service operation with the following signature:

        declare function t1:someFunc($a as xs:int*, $b as xs:double+) as xs:int*
        external;

is converted to a method like this:

        DataObject<java.lang.Integer> someFunc(Integer[] a, Double[] b);

Data service operations that return unquantified or `?`-quantified types have Static Mediator methods that are declared to return the type directly. In the case of `?`, it is possible that the result of the operation will be 0 instances of the type, in which case the static mediator method returns NULL.

### What is Autoboxing?

Autoboxing is a Java 1.5 language feature that can help simplify your code when working with Java primitive types and their object wrappers. Autoboxing automatically casts between object wrappers such as Integer and their primitive countertypes. With autoboxing, for instance, you can use an Integer object returned from a Mediator API method in a mathematical expression and you can pass an int to a Mediator API method that takes an Integer object. For detailed information on autoboxing, refer to the Sun’s Java documentation.

In Listing 3-14, an Integer object is retrieved from a DASResult is auto-cast to an int.

Note: | If you use an Integer returned from a static mediator method as an int, but the static mediator method actually returns null, you will get a NullPointerException. This can only occur from a data service operation that is declared to return `xs:int?` – that is, 0 or 1 integers. (This is not unique to int, but to any use of autoboxing.)

Listing 3-14 Autoboxing Example

    CustomerDAS custdas = CustomerDAS.getInstance(..);
    // Invoke a 0-argument procedure that returns xs:int*
    DASResult<Integer> result = custdas.getIDs();
    while (result.hasNext()) {
        int cust = result.next(); // Note use of autoboxing.
    }
    result.dispose();

### Support for Derived Simple Types

Oracle Data Service Integrator enables you to employ user-derived simple types as parameters or return types in data service operations accessed through the Oracle Data Service Integrator Mediator API.

The Mediator API is the Java API for retrieving artifacts from a data service and returning them to their source. In your Java client, you can call Mediator API methods to connect to a data service and invoke data service operations.

This enables you to create a simple type in a schema which restricts a built-in schema type, and use that type as either a parameter type or a return type for a data service operation, successfully invoking the operation through the Oracle Data Service Integrator Mediator API.

For example, you might declare a simple type called ZipCode that derives from xsd:string, as shown in the following:

    <xs:simpleType name="ZipCode">
       <xs:restriction base="xs:string">
          <xs:pattern value="[0-9]{5}(-[0-9]{4})?"/>
       </xs:restriction>
    </xs:simpleType>

Oracle Data Service Integrator enables you to use this type as a parameter type or return type for a data service operation.

#### Mapping Derived Schema Types to Java Types

The mapping of derived schema types to Java types is defined by the SDO specification and, with one exception, is identical to the mapping of the corresponding built-in schema types. For example, if a user type is derived from xs:string, the Java class is java.lang.String. Similarly, if a user type is derived from xs:byte, the Java class is java.lang.Byte.

The single exception involves using XSD types that are derived from xs:integer and include facets (such as minInclusive, maxInclusive, minExclusive, maxExclusive, or enumeration) constraining the range to be within the range of the Java data type int. Oracle Data Service Integrator maps these XSD types to the Java type java.lang.Integer instead of the default type java.math.BigInteger.

Note that this is also true for user XSD types that derive from the following schema built-in types (which are themselves derived from xs:integer):

- xs:positiveInteger
- xs:negativeInteger
- xs:nonPositiveInteger
- xs:nonNegativeInteger
- xs:long
- xs:unsignedLong

Note: | You cannot use types derived from xs:QName. Attempting to use these types in data service operations may cause an exception.

## Web Services Support

The Oracle Data Service Integrator native web services feature lets you map data services to web services directly. Client applications access data through web services using the Mediator API. Both the Dynamic and Static Mediator APIs support native web services. See Chapter 4, “Invoking Data Services Through Web Services” for detailed information on the native web services feature.

## Advanced Topics

This section includes these topics:

- Schema Management
- Support for Stateless Operations
- Cache Management
- Specifying XPath Expressions as Arguments
- Making Ad Hoc Queries

### Schema Management

SDO provides a series of APIs that assist with schema management. These APIs include:

- XMLHelper – Creates DataObjects from XML.
- DataFactory – Creates DataObjects from scratch.
- XSDHelper – Loads the SDO type system with schemas.
- HelperContext – Obtains instances of all the various helpers.

#### Schema Scope

A HelperContext object represents SDO’s concept of scope; all schemas loaded into a particular XSDHelper are available and used when creating DataObjects from the XMLHelper or DataFactory of the same HelperContext.

.A Dataspace represents the basic unit of scope for schemas. A Dataspace will not contain any schemas with conflicting type declarations.

For the web services-based mediator, the scope is defined by the WSDL. All schemas necessary for all operations in a WSDL are included in that WSDL, so the WSDL itself forms a reasonable scope for schemas. See Chapter 4, “Invoking Data Services Through Web Services” for more information.

The Mediator automatically keeps a global cache of HelperContexts, and the key to that cache will be either the Dataspace name or, for the web services case, the WSDL URL. The Mediator will automatically use the HelperContext for the appropriate Dataspace/WSDL when creating new DataObjects for the return values of operations.

You can obtain the HelperContext for a given Dataspace/WSDL and use this HelperContext to create your own DataObjects, query the type system, and so on. See Schema Cache Management for more information on the HelperContext API.

#### Schema Download

This section describes the process of downloading schemas for DataAccessService objects instantiated from data services and WSDLs (web services).

Note: | Schemas are only downloaded when creating a dynamic DataAccessService. Creating an instance of the Static Mediator API never downloads schemas, because the schemas are already compiled into the Static Mediator Client JAR file.

- Data Services Case – When a DataAccessService is instantiated for a data service, a HelperContext object is automatically populated with all schemas imported by the data service (and all schemas imported or included by those schemas, recursively).
- WSDL Case – When a DataAccessService is instantiated for a WSDL, the mediator automatically populates the HelperContext for that WSDL with all schemas in that WSDL.

Schemas are only loaded if they have not previously been loaded. You can set an optional boolean flag on the newDataAccessService() method that requests the mediator not to download schemas. Use this flag if you intend to download schemas manually using methods described in the next section, or if you plan to load them manually using SDO XSDHelper methods.

Tip: | The schema download feature ensures that you do not need to worry about schemas. The default behavior ensures that schemas are available to clients at the appropriate times.

#### Schema Cache Management

Use the following methods for querying and manipulating the mediator cache of HelperContexts. These are static methods on the class com.bea.dsp.das.HelperContextCache.

- HelperContext get(String key) – Returns (or creates, if necessary) the HelperContext for the given Dataspace name/WSDL URL. You may wish to obtain this object to load schemas that are only available on the client. For example, this technique is useful if you have a schema for the return type of an ad-hoc query that you intend to execute.
- void flush(String key) – Instructs the mediator to remove the HelperContext for the given Dataspace name/WSDL URL from its cache All DataAccessServices created in the future will use a new HelperContext. You can use this technique if you know the state of schemas has changed on the Oracle Data Service Integrator server.

Note: | It is not possible in SDO 2.1 to “unload” schemas from a HelperContext; therefore the only way to change schema information is to create an entirely new HelperContext.

- boolean loadSchemasForDataspace(Context ctx, String dataspace, String dsname) – Instructs the Mediator to download all appropriate schemas for the given Dataspace and data service. This download mechanism is similar to the one used by the Mediator when creating a DataAccessService instance. This method allows you to “pre-load” schemas, for instance, so you do not have to create a DataAccesssService instance just to obtain the schemas to create DataObjects. (See also Creating New DataObjects.) This method is also the only way to achieve server schema download when you intend to use PreparedExpression for executing an ad-hoc query. Finally, if you pass NULL for the data service name, this method automatically downloads schemas for all data services in the Dataspace. This may be slow, but is useful for certain ad-hoc query circumstances.
- boolean loadSchemasForWSDL(String wsdl) – Instructs the mediator to load all schemas from the WSDL into the corresponding HelperContext. This download mechanism is similar to the one used by the Mediator when creating a DataAccessService instance. As ad-hoc queries are not feasible over the web service transport, this method is typically not used.

Note: | Both loadSchemasForDataspace() and loadSchemasForWSDL() return a boolean indicating whether they actually loaded any schemas; they return false if the schemas for the requested data service or WSDL were previously loaded.

### Support for Stateless Operations

By default, the Mediator API holds resources on the Oracle Data Service Integrator server open while data is being returned. As discussed in Understanding DASResult, data objects are returned through DASResult one object at a time. Oracle Data Service Integrator refers to this strategy as stateful.

Generally, stateful operations are desirable. Stateful behavior allows both the client and the server to minimize memory consumption. The Oracle Data Service Integrator server will only hold open resources as long as is absolutely necessary, and the client will not use more network round trips than are necessary to transfer data to the server.

However, in some cases, you may want to guarantee that the client uses exactly one network round trip. For instance, if your network connection to the Oracle Data Service Integrator server is highly latent or potentially unreliable, using one round trip minimizes response time and ensures that there is no possibility of resources being left open on the server longer than necessary.

To override the default stateful behavior and return results immediately, use the RequestConfig flag FETCH_ALL_IMMEDIATELY. When this flag is specified, the Mediator uses exactly one network round trip to retrieve all the results at once. In addition, server resources are closed immediately.

Note: | The client must have enough memory to materialize the entire result set immediately. In addition, the Oracle Data Service Integrator server will need to fully materialize the result set in memory when this flag is specified. Therefore, it is very important to use this flag when there is any possibility that the result set cannot be held comfortably in memory on both the client and the server.

Note: | WebLogic Server specifies a maximum amount of data which can be sent in a single network operation. By default, this amount is 10 MB. If you use FETCH_ALL_IMMEDIATELY and the results are larger than this block size, you may receive a weblogic.socket.MaxMessageSizeExceededException. You can change this 10 MB limit in the WebLogic Server Console by selecting:

Note: | Environment > Servers > (server) > Protocols > General > Maximum Message Size

When this flag is enabled, all methods that return a DASResult will return one which is already disposed, as explained in Disposing the Result Object.

If you use FETCH_ALL_IMMEDIATELY, you can still use the normal iterator methods of DASResult, or use getItems() to read all the results at once.

### Cache Management

This section discusses API features that let you manage data caching through the Mediator APIs.

#### Forcing Data Cache Read-through and Update

Data retrieved by data service operations can be cached for quick access. This is known as a data caching. (See “Configuring the Query Results Cache”, in the Oracle Data Service Integrators Administration Guide for details.) Assuming the data changes infrequently, it’s likely that you’ll want to use the cache capability.

When the RequestConfig.GET_CURRENT_DATA attribute is set to true:

- All data cache access is bypassed in favor of the physical data source. Function values are recalculated based on the underlying data and the cache is refreshed. If a call involves access to several cacheable functions, all will be refreshed with current data.
- The audit property:

    evaluation/cache/data/forcedrefresh

indicates that a GET_CURRENT_DATA operation has been invoked.

- The REFRESH_CACHE_EARLY attribute property setting is ignored.

##### SETTING the REFRESH_CACHE_EARLY Attribute

You can control the data cache using the RequestConfig.REFRESH_CACHE_EARLY attribute.

If the RequestConfig.GET_CURRENT_DATA property is not enabled, you can use the RequestConfig.REFRESH_CACHE_EARLY property to control whether cached data is used based on the remaining TTL (time-to-live) available for the function’s data cache.

The REFRESH_CACHE_EARLY attribute is of type integer. It is set by invoking the RequestConfig.setIntegerAttribute() method. The setting of REFRESH_CACHE_EARLY to a particular value requires that a cached record must have at least n seconds of remaining TTL before it can be used. If the record is set to expire in less than n seconds, it will not be retrieved. Instead its value is recalculated based on the underlying data and the data cache associated with that function is refreshed. The same REFRESH_CACHE_EARLY value applies to all cache operations during a query evaluation.

Note: | The supplied integer value of REFRESH_CACHE_EARLY should always be positive. Negative values are ignored.

### Specifying XPath Expressions as Arguments

Oracle Data Service Integrator supports a limited subset of XPath expressions called SDO path expressions. SDO path expressions offer flexibility in how you locate data objects and attributes in the dynamic data API’s accessors.

SDO path uses only SDO property names (which can be different from the element/attribute name from schema/xml) in the selector. If there are alias names assigned, those are also used to match. Each step of the path before the last must return a single DataObject.

For example:

    customer.get("CUSTOMER_PROFILE[1]/ADDRESS[AddressID=\"ADDR_10_1\"]")

The example gets the ADDRESS at the specified path with the specified addressID. If element identifiers have multiple values, all elements are returned.

The get() method returns an Object. If the result of the expression is a property that isMany, the method returns a List of DataObjects.

You can get a data object’s containing parent data object by using the get() method with XPath notation:

       myCustomer.get("..")

You can get the root containing the data object by using the get() method with XPath notation:

    	myCustomer.get("/")

This is similar to executing myCustomer.getRootObject().

Oracle Data Service Integrator fully supports both the traditional index notation and the augmented notation. See “XPath Expressions in the Dynamic Data Object API” on page 2-9 for details.

### Making Ad Hoc Queries

The DataAccessServiceFactory.prepareExpression() method lets you create ad hoc queries against the data service. Listing 3-15 shows an example of the preparedExpression() method. For more information on ad hoc queries, see “Using Ad Hoc Queries to Fine-tune Results from the Client” on page 8-25.

Listing 3-15 Example of preparedExpression Method

    PreparedExpression pe = DataAccessServiceFactory.prepareExpression
       (ctx, appname, "18 + 25");
    DASResult<Object> result = pe.executeQuery();
    int answer = (int) result.next();
    result.dispose();

## Understanding Transaction Behavior

This section discusses the transaction behavior of read/write and read-only operations and queries.

### Transaction Behavior for Read/Write Operations

The Oracle Data Service Integrator server always creates a new transaction if necessary when executing read/write operations, such as create, update, or delete.

### Transaction Behavior for Read-Only Operations

By default, read operations make use of a transaction if one is currently active on the client; however, if no transaction is open, one will not be created. You can change this default by setting an attribute on RequestConfig and passing RequestConfig as a parameter to invoke(). (For detailed information on invoke() see the Javadoc.)

The attribute RequestConfig.ReadTransactionMode lets you set one of the following values to configure transaction behavior of read-only operations.

- SUPPORTS – Read operations will make use of a transaction if one is active on the client. If no transaction is open, however, one will not be created. This is the default setting.
- REQUIRED – Read operations will make use of a transaction if one is active on the client. If no transaction is open on the client, one will be created on the server for the duration of the read operation.
- NOT_SUPPORTED – Read operations will not use a transaction if one is active on the client, and no transaction will be created.

Use the RequestConfig.setEnumAttribute() method to set the ReadTransactionMode attribute. For example, the following code sets the ReadTransactionMode mode to SUPPORTS.

    RequestConfig config = new RequestConfig();
    config.setEnumAttribute(RequestConfig.ReadTransactionMode.SUPPORTS);