|Oracle Dynamic Services User's and Administrator's Guide
Part Number A88783-01
This chapter describes how to use the Java and PL/SQL Web application development interfaces.
In Section 5.1.1, directory paths often show only the UNIX path "/" specification. If you are running a Windows NT system, the path specification is "\" and you must make this change, as needed, for configurations to be successful.
The client library provides service consumers (application developers) with a Java application programming interface (API) that can be used to access the functions of the Dynamic Services engine. This section illustrates some examples for writing client Java code to create a service request for some of the sample services supplied with Oracle Dynamic Services, and executing them. Before proceeding, make sure the Dynamic Services engine is properly installed, and that you can register and execute services as described in Chapter 3. Also, using the DSAdmin utility, make sure the YahooPortfolio service is registered, because it is used in these examples.
For more information, refer to the supplied sample code in the <ORACLE_HOME>
/ds/demo/consumer directory on UNIX systems or <ORACLE_HOME>
\ds\demo\consumer directory on Windows NT systems and to the supplied Javadoc API (
apidoc.zip file) in the <ORACLE_HOME>
/ds/doc directory on UNIX systems or in the <ORACLE_HOME>
\ds\doc directory on Windows NT systems.
Make sure your classpath includes all the necessary libraries shown in Example 5-1 (that is, concatenate these paths together with a colon (:) in your classpath, (a semicolon (;) on Windows NT)):
<ORACLE_HOME>/ds/lib/ds.jar <ORACLE_HOME>/lib/xmlparserv2.jar <ORACLE_HOME>/lib/xschema.jar <ORACLE_HOME>/ds/jlib/providerutil.jar <ORACLE_HOME>/ds/jlib/ldap.jar <ORACLE_HOME>/ds/jlib/jndi.jar <ORACLE_HOME>/rdbms/jlib/xsu12.jar <ORACLE_HOME>/lib/oraclexsql.jar <ORACLE_HOME>/ds/lib/jcert.jar <ORACLE_HOME>/ds/lib/jnet.jar <ORACLE_HOME>/ds/lib/jsse.jar <ORACLE_HOME>/jdbc/lib/classes12.zip <ORACLE_HOME>/rdbms/jlib/jmscommon.jar <ORACLE_HOME>/rdbms/jlib/aqapi.jar
Registering an service consumer application in the Dynamic Services application profile registry is a two-step process.
Step 1: Create a new database user in the database instance where the DSSYS schema was installed during the installation process. Example 5-2 shows how a new database user can be created by issuing SQL statements.
CONNECT SYSTEM/<system-password>; CREATE USER serviceconsumer1 IDENTIFIED BY serviceconsumer1; GRANT CONNECT TO serviceconsumer1; GRANT DSUSER_ROLE to serviceconsumer1;
The third SQL statement lets the service consumer application named
serviceconsumer1 start using Dynamic Services.
Step 2: Using the DSAdmin utility, register the user identity as a new Dynamic Services service consumer application with the following commands:
dsadmin -u DSSYS/<DSSYS-password>
The following code example shows how to add a service consumer application named
serviceconsumer1 associated with the database user created previously.
In Example 5-3,
urn:com.yahoo:finance.portfolio03 is the service ID of the YahooPortfolio service that is granted to the new user named
serviceconsumer1 that was created in Step 1.
You can try to connect to the Oracle Dynamic Services engine as the new user,
serviceconsumer1, by executing the command shown in Example 5-4.
You can display a list of service IDs in the same registry subshell by entering Search or S. See Section 3.3 for more information.
The first step that a service consumer application must perform to work with the Dynamic Services engine is to open a connection to it. This is similar to opening a JDBC connection. There are multiple connection drivers available with Dynamic Services that allow different connection paths from service consumer applications to the engine. Service consumer applications must specify the desired driver, and then operate with the returned connection. The communication protocol used in the driver implementation is completely hidden from service consumer application developers, who will be always writing code using the same API. Some drivers allow asynchronous service requests. Example 5-5 shows how to specify a driver and open a connection for a service consumer application.
// First open the connection with the Direct driver DSDriverManager.registerDriver("oracle.ds.driver.DSDirectDriver"); DSConnection dsconn = DSDriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL"); dsconn.connect("ServiceConsumer1", "ServiceConsumer1");
The following drivers are supplied by Dynamic Services:
The following sections describe some important function differences of which service consumer application developers must be aware when using these drivers.
Use of the Direct driver means the service consumer application assumes the Dynamic Services engine is available in its own classpath, and therefore accessible through direct Java method calls. Through the DSConnection acquired using the Direct driver, service consumer applications can perform service lookup operations as well as synchronous service executions. The URL specified in the getConnection call has to be a valid Oracle JDBC connection string, pointing to the database instance where the DSSYS schema is installed.
DSHTTPDriver permits submission of service requests to a remote Dynamic Services engine using HTTP as a communication protocol. DSHTTPDriver assumes the existence of a gateway in the form of a Web server with an installed servlet that can accept service requests. The servlet is installed using the oracle.ds.comm.protocol.http.DSServlet class. See Section 4.3 for more information.
DSHTTPSDriver is similar to DSHTTPDriver except that it goes through a secure HTTP (HTTPS) channel when communicating with the remote Dynamic Services engine. In addition, it assumes that the Web server hosting the oracle.ds.comm.protocol.http.DSServlet servlet has the HTTPS option enabled.
DSJMSDriver permits remote synchronous and asynchronous access to services using a Dynamic Services gateway in the form of a JMS daemon. The mode of operation with this driver lets it submit requests asynchronously to an AQ/JMS queue in a remote database. The driver assumes the existence of this JMS daemon and it listens asynchronously to the same queue where requests are submitted. The daemon takes on the role of the Dynamic Services engine and processes the request, generates a response, and submits that response to another queue to which the DSJMSDriver asynchronously listens. On the service consumer application side, therefore, listeners can be registered to be informed when the response is returned.
It is important to note that alternating between the supplied drivers requires no modifications in the service consumer application code other than the registration of the driver itself.
The steps required to execute any service involve:
Example 5-6 illustrates these steps.
// Create a request with a default request context from the DSConnection. // Alternatively, the user can create a default request context himself // and redirect the debugger to somewhere else. DSRequest dsReq = dsconn.createDSRequest(myServiceID, new FileReader(myReqFile)); // Execute synchronously, get the response and print it. DSResponse dsResp = dsconn.executeSynch(dsReq);
In Example 5-6, the service request is read from a file. Any
java.io.Reader can be used to supply the XML request document.
Example 5-7 describes the example request of the
YahooPortfolio service in the
pfl_req_ex.xml file in the
ds/demo/services/YahooPortfolio directory on UNIX systems or in the
ds\demo\services\YahooPortfolio directory on Windows NT systems.
<?xml version="1.0"?> <!-- Example request of the YahooPortfolio service --> <PortfolioReq xmlns="http://www.portfolio.org/Portfolio/Request" xmlns:xsi = "http://www.w3.org/1999/XMLSchema/instance" xsi:schemaLocation = "http://www.portfolio.org/Portfolio/Request http://www.portfolio.org/Portfolio/Request pfl_req.xsd"> <Symbol>ORCL</Symbol> <Symbol>AAPL</Symbol> </PortfolioReq>
The supplied XML request document has to comply with request syntax defined for the YahooPortfolio service.
Once a service response has been obtained, its content can be parsed by the Oracle XML parser and printed as shown in Example 5-8.
StringWriter sw = new StringWriter(); dsResp.writeResponse(sw); DOMParser xmlp = new DOMParser(); xmlp.parse( new StringReader(sw.toString())); XMLDocument xmldoc = xmlp.getDocument(); xmldoc.print( new PrintWriter(System.err));
Within the life cycle of a Dynamic Services connection, service consumer applications can execute multiple services. Each of these services can actually create a session with the remote service provider. For example, a service connecting to a Web site can receive as part of the response an HTTP cookie that has to be supplied with every request that follows.
Before executing a set of services, Dynamic Services allows service consumer applications to create a session and execute a set of services within the session so that all the session context (for example, HTTP cookies or database connections) are preserved for that session only. By calling the DSConnection.openSession() method, service consumer applications obtain an opaque session identifier. To continue the session, service consumer applications must set the session identifier in the header of those service requests that are to be executed within the session. Corresponding DSResponses contain header information about the session to which they belong. To close a session, service consumer applications can use the DSConnection.closeSession() method, which releases all the resources related to the specified session. Refer to the sample Java code for details.
The information stored for the session (for example, HTTP cookies and database connections) is not persistent across startup and shutdown of the Dynamic Services engine. This information is stored in memory and it persists only through the life cycle of the host JVM where the Dynamic Services engine is running.
It is the responsibility of the service consumer (application) to close any session that it created so the associated resources are released. Closing a Dynamic Services connection does not close the service consumer sessions and release their resources.
The PL/SQL DynamicServices package defines the PL/SQL interface for service execution. The PL/SQL DynamicServices package is defined with invoker's privileges; therefore, to access it in a PL/SQL block that is defined with definer's privileges, the package and related types must be explicitly granted to service consumers as shown in Example 5-9.
GRANT EXECUTE ON DSSYS.DYNAMICSERVICES TO serviceconsumer1; GRANT EXECUTE ON DSSYS.XML_ELEM_NAMES TO serviceconsumer1; GRANT EXECUTE ON DSSYS.XML_ELEM_VALS TO serviceconsumer1;
To easily create a service consumer application that uses Dynamic Services, you can inspect the
createPLSQLConsumer.sql file in the
demo/consumer directory. For more details about users and the database, refer to Oracle9i documentation.
As described in Section 1.3.2, in a PL/SQL deployment of Dynamic Services, the Dynamic Services engine runs in the Oracle9i JVM, and its functions are exposed as a set of Java stored procedures through a PL/SQL interface (see Example 5-10). A service consumer application makes use of the services through PL/SQL calls to these procedures and functions shown in Example 5-10.
-- This procedure initializes the Dynamic Services engine within JServer -- and opens a Dynamic Services connection. It is a prerequisite before any -- kind of execution is done. PROCEDURE open; -- This closes the Dynamic Services connection opened by the open function. -- If no connection is opened, this will throw a TearDownException error. PROCEDURE close; -- This function executes a service with a given service identifier and -- a request in the form of an XML document. -- It synchronously executes the service and -- returns the response in the form of an XML document as a VARCHAR2 type. FUNCTION execute(service_id VARCHAR2, request VARCHAR2) RETURN VARCHAR2; -- This executes a service with a given service identifier and -- two CLOB locators. It reads in the request CLOB and starts -- a synchronous execution. Upon finishing, it writes the result -- into the response CLOB locator that is passed in. PROCEDURE execute(service_id VARCHAR2, request CLOB, response CLOB); -- Utility method: The supplied string has to be an XML element. -- It will take the XML document and traverse down an entry -- in the supplied arrays for each element in the document. -- In the keys array, it will store the path of the element where the slash -- (/) is used to separate the child files. The corresponding entry -- in the VALS array will have the value of the element. PROCEDURE flatXML(szXML VARCHAR2, keys IN OUT DSSYS.XML_ELEM_NAMES, vals IN OUT DSSYS.XML_ELEM_VALS); -- Utility method to handle the array returned by flat XML. -- It will take the supplied key, iterate over the -- keys arrays, and if it finds a match, return the -- corresponding value from the VALS array. FUNCTION getXMLValue(key VARCHAR2, keys IN DSSYS.XML_ELEM_NAMES, vals IN DSSYS.XML_ELEM_VALS) RETURN VARCHAR2;
Example 5-11 shows some PL/SQL sample code from the
sample.sql file in the
demo/consumer directory that illustrates a typical scenario where the PL/SQL DynamicServices package can be used.
-- Some output specifications SET SERVEROUTPUT ON SIZE 20000; CALL DBMS_JAVA.SET_OUTPUT(20000); -- Anonymous block DECLARE -- Service Execution ds_req VARCHAR2(512); -- A request in the form of an XML document. ds_resp VARCHAR2(4000); -- A response in the form of an XML document. ds_svcid VARCHAR2(128); -- A string that tells which service to execute. -- For response processing ds_elem_names DSSYS.XML_ELEM_NAMES; -- Element Names VARRAY ds_elem_vals DSSYS.XML_ELEM_VALS; -- Element Values VARRAY BEGIN -- First connect; must do this before any execution DSSYS.DynamicServices.open(); -- Set up the service ID ds_svcid := 'urn:com.yahoo:finance.portfolio03'; -- Set up the service request ds_req := '<PortfolioReq xmlns="http://www.portfolio.org/Portfolio/Request">'|| ' <Symbol>ORCL</Symbol>'|| '</PortfolioReq>'; -- Execute the service ds_resp := DSSYS.DynamicServices.execute(ds_svcid, ds_req); -- Close connection DSSYS.DynamicServices.close(); -- Print the response (Banner) DBMS_OUTPUT.PUT_LINE('-------------------------'); DBMS_OUTPUT.PUT_LINE('Dynamic Services Response'); DBMS_OUTPUT.PUT_LINE('-------------------------'); -- First flatten out the XML DSSYS.DynamicServices.flatXML(ds_resp, ds_elem_names, ds_elem_vals); -- Which symbol did we try to check? DBMS_OUTPUT.PUT_LINE('Value of "/PortfolioResp/Quote/Symbol" is '|| DSSYS.DynamicServices.getXMLValue('/PortfolioResp/Quote/Symbol', ds_elem_names, ds_elem_vals)); -- What's its price? DBMS_OUTPUT.PUT_LINE('Value of "/PortfolioResp/Quote/Price" is '|| DSSYS.DynamicServices.getXMLValue('/PortfolioResp/Quote/Price', ds_elem_names, ds_elem_vals)); END; /
The connected database user is the service consumer application connecting to the service engine. Refer to Section 5.1.2 on how to register a service consumer application with the Dynamic Services application profile registry.
For a more extensive sample that makes use of the currency service, refer to the
demo/consumer/currency.sql file on UNIX systems or to the
demo\consumer\currency.sql file on Windows NT systems.