Client Application Developer's Guide
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
This chapter describes how to access data services in Java client applications. It covers the following topics:
The Data Service Mediator API gives Java client applications an easy-to-use programmatic interface for accessing information from Liquid Data data services. To use the Mediator API, Java applications simply instantiate a remote data service interface and invoke any public functions on the interface, including read, submit, and navigate functions. When a read function or navigation function is invoked through the Mediator API, the client application gets back information as an SDO data object, also known as a data graph.
As discussed in the Enabling SDO Data Source Updates, SDO is the client-side data programming model for Liquid Data. The SDO API consists primarily of functions for getting and manipulating data objects and their properties.
Note: For more information on working with Data Objects, see Client Programming with Service Data Objects (SDO).
Like the SDO data programming interfaces, the Mediator API enables client applications to use either a typed or untyped approach to using data services. The untyped interface lets client applications use data services that are either unknown or not created at client development time.
A data object acquired through the untyped mediator API can be cast to a typed object, as long as its structure is compatible with the schema of the type to which it is being cast. In fact, a development pattern that can streamline programming when working with multiple data services is to use untyped APIs for invoking data service functions and subsequently casting the acquired objects to their appropriate types.
This chapter discusses the typed and untyped Mediator interfaces. The Mediator API contains several more advanced features as well. These are discussed in Advanced Topics. They include:
The Mediator API exposes data service functionality to Liquid Data clients. It contains interfaces and classes for instantiating remote interfaces to the data services and executing functions on the interface. The functions defined for the data service are available in the Mediator API.
The generic, untyped Mediator API classes and interfaces are in the following JAR file:
ld-client.jar
The Data Service Mediator package is named as follows:
com.bea.ld.dsmediator.client
The API consists of the classes and interfaces listed in the following table.
The static mediator interface extends the generic mediator interface, and gives clients a typed approach for instantiating and invoking data service functions. For example, the following class definition represents a typed data service interface:
public class dataservices.Customer extends
com.bea.ld.dsmediator.client.XMLDataServiceBase { ... }
The typed data service interface is in the SDO Mediator Client JAR files generated from a Liquid Data project.
The exception class for mediator errors is in the following package:
com.bea.ld.dsmediator.client.exception
In addition to an exception for general mediator errors (SDOMediatorException
) there are exceptions for ad hoc queries (ServerPrepareException
) and streaming access (StreamingException
).
Exceptions that are generated by the data source (such as SQLException
) are wrapped in an SDO Exception, and can be accessed at the label #sdoException.detail
.
To develop mediator client programs, include the preceding JARs in the system CLASSPATH of the development computer.
For example, on Microsoft Windows operating system, the command for setting the class path would be:
set CLASSPATH=%CLASSPATH%;Demo-ld-client.jar;
C:\bea\weblogic81\server\lib\weblogic.jar;
C:\bea\weblogic81\liquiddata\lib\wlsdo.jar;
C:\bea\weblogic81
\server\lib\xbean.jar;
C:\bea\weblogic81\liquiddata\lib\ld-client.jar;
Note that this assumes that the first item, Demo-ld-client.jar
, is in the current directory and that the WebLogic home directory is C:\bea\weblogic81
. If different on your system, modify the path to the locations where these resides on your system.
Also note that when developing your own applications, you will need to substitute the name of Demo-ld-client.jar
with the name of the JAR file generated from your Liquid Data-enabled application.
Client applications can access the classes representing the typed data service interface using a JAR (Java Archive) file generated from the Liquid Data project. The JAR file needs to be on the client application development machine. The file is named in the form:
There are two ways to generate the JAR file:
In most cases, the JAR file would be generated by the Liquid Data administrator and distributed to data client programmers.
This section describes how to generate the client JAR from the command line. To perform the procedure, first build the EAR file and then the client JAR file.
To create a mediator client JAR file, you first need to create an EAR (Enterprise Archive) file from the Liquid Data application. An EAR file is similar to a JAR file—it contains a set of deployable application artifacts.
To build an EAR file, perform the following steps:
For more information about building an EAR file, refer to the Data Services Developer's Guide.
To use data service of a Liquid Data project in a client application, you need to generate a client version of the Liquid Data project Java archive. The client version includes wrapper classes that allow the client to call the data service functions through a dynamic API.
Generate the client JAR file from the EAR file you created earlier (see Build an EAR File above) by performing the following steps:
<
bea_home
>\weblogic81\liquiddata\lib\sdoclientmediator
The directory contains several files, including a build script and a ANT build configuration file. You should not have to modify these files.
ld_client_gen <LocationOfArchive> [<LocationOfDirectory>] [<LocationForTempDir>]
Where <LocationOfArchive>, <LocationOfDirectory>, and <LocationForTempDir> arguments are defined as described in the following table.
The fully qualified name of the EAR file you generated in step 4 of the Build an EAR File instructions. |
|
The folder where you want the generated client JAR file to be placed. This is an optional parameter. If not specified, the current directory is used. |
|
The folder where you want the temporary, expanded EAR directory to be placed. This is an optional parameter. If not specified, the current directory is used. |
ld_client_gen C:\bea\user_projects\applications\danube\Demo\Demo.ear C:\test
When you run ld_client_gen
, the following file is produced:
C:\test\Demo-ld-client.jar
When working with your own applications, "Demo" in the generated name will be replaced by a name derived from your EAR file.
To use the Data Service Mediator API to invoke data services, follow these general steps in your application:
com.bea.ld.dsmediator.client
package. For complete information, see:
http://download.oracle.com/docs/cd/E13222_01/wls/docs81/javadocs/weblogic/jndi/WLInitialContextFactory.html
DataService ds = DataServiceFactory.newXmlService(
JndiCntxt, "RTLApp", "ld:DataServices/RTLServices/Customer");
Object params[] = {"CUSTOMER1"};
DataObject myCustomer =
(DataObject) ds.invoke("getCustomerByCustID", params);
Here is the same operation using the typed interface:
Customer ds = Customer.getInstance(JndiCntxt, "RTLApp");
When a read or navigate function is invoked, the function returns an SDO data object. For more information, see Client Programming with Service Data Objects (SDO).
In general, WebLogic JNDI services allow client applications to access named objects on a WebLogic Server. For Liquid Data, you use JNDI calls to obtain references to remote data services. (Only one JNDI call is needed because the call is created in the context and is passed to the data services factory.) Once you have the server context, you can invoke functions and acquire information from data services.
To get the WebLogic server context, set up the JNDI initial context by specifying the INITIAL_CONTEXT_FACTORY and PROVIDER_URL environment properties:
weblogic.jndi.WLInitialContextFactory
t3://localhost:7001
). A local client (that is, a client that resides on the same computer as the WebLogic Server) may bypass these steps by using the settings in the default context obtained by invoking the empty initial context constructor; that is, by calling new InitialContext()
.
At this stage, the client may also authenticate itself by passing its security context to the corresponding JNDI environment properties SECURITY_PRINCIPAL and SECURITY_CREDENTIALS.
The code excerpt below is an example of a remote client obtaining a JNDI initial context using a hashtable.
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>
);
Be sure to replace the machine name and username/password with values appropriate for your environment.
Once you have obtained an initial context to the server containing Liquid Data artifacts, you can instantiate a remote interface for a data service. If you know the data service type at development time, you can use the static data service interface, which uses strongly typed data objects. Alternatively, the dynamic interface lets you use data services specified at runtime. The static interface gives you a number of advantages, including type validation and code completion when using development tools, such as Eclipse or your favorite development tool.
To use the static data service interface, you must have the SDO Mediator Client JAR file that was generated from the desired Liquid Data enabled application. If you do not have the JAR file, contact your administrator to acquire it.
Add the JAR file to your client application's build path and import the data service package into your application. For example, to use a data service named Customer in a Liquid Data project named data services, use the following import statement:
import dataservices.Customer;
From there, you can instantiate the desired data service interface using the getInstance()
function. In the function call, pass the following arguments:
Once you have a remote data service instance, you can invoke functions on the data service. Any public function defined on the data service is available in the generated class. For example, consider the public data service functions shown in Figure 4-2.
Figure 4-2 Customer Data Service
The list of methods that are generated for the typed data service are listed below. Notice that methods are created for each function in the data service, such as getCustomer()
and getApplOrder()
Customer(Context, String)
getInstance(Context, String)
prepareExpress(Context, String, String)
submit(DataObject)
getCustomer()
getCustomerToFile(String)
getCustomerByCustID(String)
getCustomerByCustIDToFile(String, String)
getCustomerByZip(String)
getCustomerByZipToFile(String, String)
getCase(CUSTOMERPROFILEDocument)
getCaseToFile(CUSTOMERPROFILEDocument, String)
getCreditCard(CUSTOMERPROFILEDocument)
getCreditCardToFile(CUSTOMERPROFILEDocument, String)
getApplOrder(CUSTOMERPROFILEDocument)
getApplOrderToFile(CUSTOMERPROFILEDocument, String)
getElecOrder(CUSTOMERPROFILEDocument)
getElecOrderToFile(CUSTOMERPROFILEDocument, String)
getCustomerByLoginID(String)
getCustomerByLoginIDToFile(String, String)
Several additional functions are generated as well. The submit()
function is used to save changes to the data objects served by the data service. The ToFile functions, such as getCustomerToFile()
and getAllCustomersToFile()
, are also generated for each function defined in the data service. It allows a client to write results returned from the function call to a file specified as an argument. For more information, see Consuming Large Result Sets (Streaming API), in Consuming Large Result Sets (Streaming API).
Another function that is automatically provided is the prepareExpression(
) function. This function is for creating ad hoc queries against the data provided by the data service.
Listing 4-1 shows a small but complete example of using the typed interface.
Listing 4-1 Mediator Client Sample Using the Static Interface to a Data Service
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import dataservices.rtlservices.Customer;
import retailerType.ArrayOfCUSTOMERPROFILEDocument;
public class MyTypedCust
{
public static void main(String[] args) throws Exception {
//Get access to Liquid Data
Hashtable h = new Hashtable();
h.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
h.put(Context.PROVIDER_URL,"t3://localhost:7001");
h.put(Context.SECURITY_PRINCIPAL,"weblogic");
Context context = new InitialContext(h);
// Use the Mediator API
Customer customerDS = xds.getInstance(context, "RTLApp");
ArrayOfCUSTOMERPROFILEDocument myCust =
(ArrayOfCUSTOMERPROFILEDocument)xds.getCustomerByCustID("CUSTOMER2");
System.out.println(" CUST" + myCustomer);
}
}
The dynamic data service interface is useful for programming with data services that are unknown or do not exist at development time. It is useful, for example, for developing tools and user interfaces that work across data services.
In the dynamic interface, specific data service names are passed as parameters of the function calls instead of explicitly reflected in the function call names themselves. Like the Mediator API, the SDO API has both static (or strongly typed) and dynamic interfaces for working with data. In most cases, the static Mediator API would be used alongside the equivalent dynamic SDO interfaces. Both have the same use case—working with data when the type is unknown beforehand, for example:
DataService ds =
DataServiceFactory.newDataService(
context, "RTLApp", "ld:DataServices/RTLServices/Customer");
Object params = {"CUSTOMER2"};
DataObject myCustomer =
(DataObject) ds.invoke("getCustomerByCustomerID", params);
println(myCustomer.get("Customer/LastName"));
A data object returned by the dynamic interface can be down cast to a typed object, as follows:
DataService ds =
DataServiceFactory.newDataService(
context, "RTLApp", "ld:DataServices/Customer");
Object params = {"CUSTOMER2"};
CUSTOMERDocument myCustomer =
(CUSTOMERDocument) ds.invoke("getCustomer", params);
println(myCustomer.getCUSTOMER().getCUSTOMERNAME());
For an dynamic data service, use the newDataService()
method of the DataServiceFactory class. In the method call, pass the following arguments:
Listing 4-2 shows a full example.
Listing 4-2 Mediator Client Sample Using the Dynamic Interface to a Data Service
import com.bea.ld.dsmediator.client.DataService;
import com.bea.ld.dsmediator.client.DataServiceFactory;
import commonj.sdo.DataObject;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
public class MyUntypedCust
{
public static void main(String[] args) throws Exception {
//Get access to Liquid Data
Hashtable h = new Hashtable();
h.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
h.put(Context.PROVIDER_URL,"t3://localhost:7001");
h.put(Context.SECURITY_PRINCIPAL,"weblogic");
h.put(Context.SECURITY_CREDENTIALS,"weblogic");
Context context = new InitialContext(h);
// Use the Mediator API
DataService ds =
DataServiceFactory.newXmlService(context, "RTLApp",
"ld:DataServices/RTLServices/Customer");
DataObject myCustomer = (DataObject) ds.invoke("getCustomer", null);
System.out.println(" Customer Information: \n" + myCustomer);
}
}
A navigation function lets you get data from a related data service. Relationships between data services serve to model a logical connection between them. They also streamline your client programming because you can invoke the relationship function from an instance of the current data service. For example, from a Customer data service you can get a credit card list for a customer instance, as in the following:
Customer myCustomer = Customer.getInstance(ctx, "RTLApp");
CUSTOMERPROFILEDocument custProfileDoc =
CUSTOMERPROFILEDocument.Factory.newInstance();
ArrayOfCREDITCARDDocument cc = myCustomer.getCreditCard(custProfileDoc);
A navigation function is called with an object of the calling data service being passed as an argument, as shown in the sample.
To use a navigation function, include the interface for the related data service in the import statements of your application, as shown in Listing 4-3.
Listing 4-3 Calling a Navigation Function Sample
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import dataservices.rtlservices.Customer;
import retailerType.CUSTOMERPROFILEDocument;
import retailerType.CUSTOMERPROFILETYPE;
import retailerType.ArrayOfCREDITCARDDocument;
public class CustomerClientNavigation
{
public static void main(String[] args) throws Exception {
Hashtable h = new Hashtable();
h.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
h.put(Context.PROVIDER_URL,"t3://localhost:7001");
h.put(Context.SECURITY_PRINCIPAL,"weblogic");
h.put(Context.SECURITY_CREDENTIALS,"weblogic");
Context context = new InitialContext(h);
Customer myCustomer = Customer.getInstance(context, "RTLApp");
CUSTOMERPROFILEDocument custProfileDoc =
CUSTOMERPROFILEDocument.Factory.newInstance();
CUSTOMERPROFILETYPE newCustProfile =
custProfileDoc.addNewCUSTOMERPROFILE();
CUSTOMERPROFILETYPE myCustPfl =
myCustomer.getCustomerByCustID("CUSTOMER0").
getArrayOfCUSTOMERPROFILE().
getCUSTOMERPROFILEArray(0);
newCustProfile.setFirstName(myCustPfl.getFirstName());
newCustProfile.setLastName(myCustPfl.getLastName());
newCustProfile.setADDRESSArray(myCustPfl.getADDRESSArray());
newCustProfile.setCustomerID(myCustPfl.getCustomerID());
newCustProfile.setCustomerSince(myCustPfl.getCustomerSince());
newCustProfile.setEmailAddress(myCustPfl.getEmailAddress());
newCustProfile.setEmailNotification(myCustPfl.getEmailNotification());
newCustProfile.setDefaulShippmentMethod(
myCustPfl.getDefaulShippmentMethod());
newCustProfile.setOnlineStatement(myCustPfl.getOnlineStatement());
newCustProfile.setLoginID(myCustPfl.getLoginID());
custProfileDoc.setCUSTOMERPROFILE(newCustProfile);
// Navigate to CreditCard data service
ArrayOfCREDITCARDDocument cc = myCustomer.getCreditCard(custProfileDoc);
System.out.println(cc);
}
}
![]() ![]() |
![]() |
![]() |