Chapter 15. Database as Web Services Provider Service

This chapter describes exposing database functionality as Web services, and the next chapter takes you through calling external Web services from within the database.

Rationales for Database as Web Services Provider

As database developers, DBAs, and data architects know, the Oracle database furnishes a rich set of functionality and APIs for building data-centric applications; if you visit the popular askTom[1] Web site, you will get a feel for the depth and breadth of the possibilities. It is no surprise then that, as already mentioned in Chapter 14, an Evans Data survey (Winter 2004) found that, “more than two out of three respondents, 68 percent, say they are in the process of exposing or invoking their database operations through standard Web services mechanisms.” The question is no longer “Why?” but “How can I amortize my investment in the Oracle Database 10g and expose some of these application modules as Web services?”

How Does Database as Web Services Provider Work?

This section first discusses the implementation of Web services with RDBMSs in general, and then looks more specifically at the Oracle’s implementation of database as Web service provider.

Implementation and Packaging

Simply put, Web services consist of a service client and service provider exchanging SOAP messages. As depicted in Figure 15.1,[2] the Web service provider is composed of a Web service layer and the service implementation. These two parts usually live within the same container (Figure 15.1). However, these parts may also sit in separate entities (Figure 15.2) such as a Java EE container for the Web service layer and an RDBMS for the service implementation. This is how the Oracle database as Web service provider is currently implemented (Figure 15.3).

Simple View of Web Services

Figure 15.1. Simple View of Web Services

Two-Tier Web Services Provider

Figure 15.2. Two-Tier Web Services Provider

The Oracle Implementation of Database as Service Provider

Figure 15.3. The Oracle Implementation of Database as Service Provider

Some developers prefer a native support for Web services framework integrated within the RDBMS, while others are unwilling to directly expose their database to the Web and prefer the separation of the Web services framework from the RDBMS mostly for security reasons (i.e., peace of mind). Even though this book is not the place to discuss product packaging and strategy, here are some thoughts on the pros and cons of each implementation:

  1. It is technically possible to support the core Web services framework directly in most RDBMSs, including the Oracle database, and this can be useful for bare Web services.

  2. Web services and SOA players are actively beefing up existing technologies and adding new specifications, recommendations, and initiatives all the time. It is therefore desirable to use and maintain a single Web services, and SOA stack, so as to furnish consistent development, deployment, management, and quality of services, irrespective of where the module implementing the service is deployed (i.e., database or middle tier).

How Does Oracle Database as Web Services Provider Work?

Assume you have published selected database resources as Web services. The following software pieces come into play during the invocation of the service operations:

  1. A SOAP request for a database Web service is received at the service endpoint in the Oracle AS OC4J Web Services layer.

  2. A SOAP Servlet processes the message.

  3. The Servlet transfers the request to the Java proxy within the OC4J container, which represents the service implementation (i.e., PL/SQL packages, Java in the database, SQL queries, SQL DML, AQ streams). The Java proxy is generated by the JPublisher utility invoked under the covers by the Web Services Assembler utility (WSA).

  4. The Java proxy invokes the operations on the service implementation in the database through JDBC.

  5. The database executes the requested operation and passes the response back to the Java proxy.

  6. The Java proxy transfers the response to the SOAP Servlet.

  7. The SOAP Servlet encodes the SOAP response in accordance with the WSDL and returns it to the client (service requester).

Because the Web services framework is constantly evolving, and independent of the Oracle Database release, I strongly suggest using the latest release of the Oracle Application Server (OC4J) Web Services stack whenever possible. For development purposes, you can just download the standalone OC4J.

Web Services and SOA Features in Oracle Application Server 10.1.3

What do you get when deploying database functionality as Web services through the Oracle AS Web services and SOA layer? As depicted in Figure 15.3, Release 10.1.3 brings the following new Web services features: interoperability, security, reliability, management, auditing, logging, BPEL integration, WSIF support, and other enhancements.

Web Services Interoperability

Interoperability is the key to fulfillment of the Web services promises. In heterogeneous environments, incompatibility issues might be encountered at the protocol level (beyond basic HTTP), the message level (data type conversion across platforms), or the WSDL level (quality of services). The WS-I organization specifies what it means for a Web services framework to be interoperable via the WS-I Basic Profile. The WS-I Basic Profile 1.0[3]mandates support for SOAP 1.1, WSDL 1.1, HTTP 1.1, HTTP binding (or HTTPS), and XML Schema (Parts 1 and 2). The Oracle AS Web Service framework is compliant with WS-I Basic Profile 1.0, but also focuses pragmatically on interoperability with the specifics of other vendors and open source frameworks.

Web Services Security

Web Services security ensures transport-level security (TLS), as well as message-level security (MLS) and furnishes the following services: identification, authentication, authorization, data integrity, confidentiality, and nonrepudiation. The Oracle AS (OC4J) 10.1.3 Web services implements WS-Security and integrates it with the Oracle Web Services Manager (see later) and enterprise security frameworks, such as JAAS Security Provider (Oracle SSO integration), Oracle Identity Management (SAML token propagation, SSO support), third-party LDAP, COREid Access, and COREid Identity. The Oracle Web Services Manager tool lets you secure database Web services via WS-Security using agents and gateways and/or Oracle Enterprise Manager.

Web Services Management

The Oracle Web Services Manager (OWSM) furnishes Web services access control, single sign-on, centralized security policy management, enforcement of regulations (e.g., Sarbanes-Oxley, Gramm-Leach-Bliley, and HIPAA), monitoring of WS-Security, and Web Services Reliable Messaging. These features are exposed through a series of Java Management Extensions (JMX) Management beans (Mbeans). The Policy Manager allows configuring operational rules and propagating them to the enforcement components. The Monitoring Dashboard collects data from gateways and agents and displays results in a graphical format.

Web Services Reliable Messaging

Reliable messaging for SOAP-based Web services ensures that the message is sent at least once (guaranteed delivery), sent at most once (guaranteed duplicate elimination), sent exactly once (guaranteed delivery and duplicate elimination), and received in the same sequence (message ordering). The Oracle Application Server Web Services currently implements the OASIS standard WS-Reliability, and Oracle is working as part of the OASIS WSReliableExchange group to converge WS-Reliability with WS-ReliableMessaging to ensure an interoperable, industry-wide adopted reliable messaging standard (WS-RX). In the meantime, the Oracle database as Web services provider can benefit from WS-Reliability; however, the Web Services requester’s framework must also support WS-Reliability.

SOAP Message Auditing and Logging

Auditing allows saving and accessing copies of SOAP requests, responses, and fault messages at both the client and server ends.

Logging allows administrators to log parts of the SOAP messages at the provider end. The configuration is accomplished as follows:

  1. Register the different namespaces at the port level.

  2. Create the XPath expression on request, response, or fault messages.

BPEL Integration

BPEL is the emerging standard for business process definition; think of it as the workflow for Web services. The Oracle BPEL Process Manager[4] (BPEL PM) supports RPC encoded and document literal message formats. A database Web service can be part of a complex Web service workflow process orchestrated by the BPEL PM.

Web Services Invocation Framework (WSIF) Support

WSIF provides a standard API allowing the Web service client to use native protocols such as RMI, IIOP, or JDBC, instead of SOAP, for interacting with the server (in connected environments). Adding WSIF binding to the WSDL enables supporting other protocols, in addition to HTTP, JMS, and UDP. Database Web services can be reached directly through WSIF. See Chapter 9 of the Oracle Application Server, Advanced Web Services Developer’s Guide 10 g Release 3 (10.1.3) for more details.

Other Web Services Features

The other new features and enhancements in 10.1.3 include the following:

  • Support for REST Web services

  • Enhanced Web service home page for testing with the addition of REST, security, and reliability testing

  • Support for JSR-181 Web services annotation (requires J2SE 5.0)

  • Ant tasks for configuration and scripting

  • Custom type-mapping framework for serialization

  • Enhanced database Web services support

  • WS-I swaRef (in addition to SwA)

  • MIME and DIME document support

  • JMS transport as an alternative to HTTP

See the Oracle Application Server, Web Services Developer’s Guide 10 g Release 3 (10.1.3) for more details.

Turning Oracle Database Functionality into Web Services

The database functionality to be exposed as Web services (i.e., PL/SQL packages, Java classes in the database, queries, DML, and streams AQ queues) usually already exists in your database. Creating a database Web service from an existing resource is called a bottom-up approach as opposed to a top-down approach consisting of creating/generating the service implementation from the WSDL.

There are two approaches for assembling, deploying, testing database Web services, and generating their client proxy: using the JDeveloper Web Services Wizard and using the Web Services Assembler (wsa) command-line tool (which is used under the covers by JDeveloper). For each approach, we’ll look at the installation and configuration of the required software pieces.

We’ll start with an overview of type conversion between SQL types and XML types, then installing and configuring OC4J stand-alone, assembling PL/SQL Web services using JDeveloper, introducing the Web Service Assembler and the steps for assembling database Web services, deploying PL/SQL Web services, deploying Java DB Web services, deploying SQL queries Web services, deploying DML Web services, and deploying streams AQ Web services.

Type Conversions and Result Set Representation

Type Conversion between SQL Types and XML Types

The service implementation in the database manipulates SQL types while the Web services manipulate XML types. Table 15.1 summarizes SQL types mapping to XML types according to the message style (i.e., Literal or Encoded).

Table 15.1. SQL Type to XML Type Mapping

SQL Type

XML Type (Literal)

XML Type (Encoded)

INT

int

int

INTEGER

int

int

FLOAT

double

double

NUMBER

decimal

decimal

VARCHAR2

string

string

DATE

dateTime

dateTime

TIMESTAMP

dateTime

dateTime

BLOB

byte[]

byte[]

CLOB

string

string

LONG

string

string

RAW

byte[]

byte[]

SQL object

complexType

complexType

PL/SQL RECORD

complexType

complexType

Index-by-Table of Scalar types

Array

Array

SQL table

complexType

complexType

Index-by-Table of Complex types

complexType

complexType

PL/SQL Boolean

boolean

boolean

REF CURSOR (<name>Beans)

Array

Array

REF CURSOR (<name>XMLSource)

any

text_xml

REF CURSOR (<name>XMLRowSet)

swaRef

text_xml

SYS.XMLTYPE

any

text_xml

SQL Result Sets Representations

A PL/SQL stored procedure or a SQL statement can be mapped into one or several Web service operations. Typically, a SQL query or a PL/SQL function (i.e., <name>), which returns a REF CURSOR, will be mapped to the following methods: <name>Beans, <name>XMLRowSet, and<name>XMLSource:

  • <name>Beans: Returns an array of instances of XSD complex types, each element representing one row in the cursor. Each subelement corresponds to a column in a row.

  • <name>XMLRowSet: Returns a swaRef or text_xml response that contains an OracleWebRowSet instance in XML format. See “Working with MIME Attachments” in the Oracle Application Server Advanced Web Services Developer’s Guide for more details on the swaRef MIME format.

  • <name>XMLSource: Returns XML any or text_xml response that contains XMLType row set.

Setting up the Oracle AS OC4J for Database as Web Services Provider

As explained earlier, we utilize the Web services framework in the Oracle AS for exposing database functionality as Web services. For development purposes, you can download a stand-alone OC4J from the Oracle Technology Network (OTN).[5]

Once you’ve downloaded the oc4j_extended.zip:

  • Unzip into a location on your file system (i.e., a directory); let’s call it OC4J_HOME.

  • Set the J2EE_HOME environment variable to $OC4J_HOME/j2ee/ home.

  • Provide a JNDI location for the JDBC datasource by modifying the data-sources.xml entry under $J2EE_HOME/config/ with your own hostname, port, and global database name as follows.

Note

The datasource jdbc/OracleDS must point to a running database.

data-sources.xml
================

<?xml version="1.0" standalone='yes'?>

<data-sources
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/
oracleas/schema/data-sources-10_1.xsd"
  schema-major-version="10"
  schema-minor-version="1"
>
  <connection-pool name="Example Connection Pool">
    <connection-factory factory-
class="oracle.jdbc.pool.OracleDataSource"
      user="scott"
      password="tiger"
      url="jdbc:oracle:thin:@//<hostname>:<port>/<global
database name>">
    </connection-factory>
  </connection-pool>

  <managed-data-source name="OracleDS"
    connection-pool-name="Example Connection Pool"
    jndi-name="jdbc/OracleDS"/>

</data-sources>
  1. Go to the J2EE_HOME and start the OC4J instance as follows:

    $ java -jar oc4j.jar

    Oracle Containers for J2EE 10g (10.1.3.0.0) initialized

Assembling PL/SQL Web Services Using JDeveloper Wizard

PL/SQL packages are the typical service implementation, since Oracle database users have built or inherited PL/SQL packages over years and would like to reuse these. Even though we’ll be using a Java/J2EE-based Web services framework, DBAs, database developers, and data architects will be shielded from the need to know Java or Web services; conversely, Java and Web services developers won’t need to know PL/SQL; however, a functional knowledge of each package (i.e., what it does), its functions/procedures, and their signatures and parameters, is useful. Luckily, JDeveloper inspects the package to be published and furnishes such information.

Let’s create a purchase order table (PO_TAB) storing XML documents representing purchase orders (XMLType column). Then let’s create a PL/ SQL package (PORDER), which has a function (GETPO), takes a PO number, and returns the XML document representing the purchase order.

Setup

po_tab.sql
==========

set echo on
drop table po_tab;
create table po_tab (po XMLType);
insert into po_tab values (XMLTYPE(' <PORDER PONUM="2004"> <CLIENT>
<CLNUM>2000</CLNUM> <CLNAME>Bobo Lafleur</CLNAME> <ADDRESS>
<STREET>24 Cartoon Drive </STREET> <CITY>San Francisco</CITY>
<STATE>CA</STATE> <ZIP>94313</ZIP> </ADDRESS> <PHONES> <VARCHAR2>415-
666-0000</VARCHAR2> </PHONES> </CLIENT> <ORDERDATE>10-FEB-06</
ORDERDATE> <SHIPDATE>12-FEB-06</SHIPDATE> <LITEMS> <LITEM_TYP
ItemNum="1"> <ITEM StockNo="1324"> <PRICE>199</PRICE> <TAXRATE>8</
TAXRATE> </ITEM> <QUANTITY>11</QUANTITY> <DISCOUNT>10</DISCOUNT> </
LITEM_TYP> <LITEM_TYP ItemNum="2"> <ITEM StockNo="2324"> <PRICE>299</
PRICE> <TAXRATE>8</TAXRATE> </ITEM> <QUANTITY>22</QUANTITY>
<DISCOUNT>20</DISCOUNT> </LITEM_TYP> </LITEMS> <SHIPTOADDRESS /> </
PORDER>'));
commit;
rem
set long  10000
set pagesize 80
select x.po.getCLOBVal() from po_tab x;
exit;


porder.sql
==========
create or replace package porder as
   function getpo (PONO number) return XMLTYPE;
end porder;
/
show errors
/

create or replace package body porder as
  function getpo (PONO number) return XMLTYPE is
   xmldoc XMLTYPE;
   begin
    select x.PO into xmldoc from po_tab x
       where x.po.EXTRACT('/PORDER/@PONUM').getNumberVal() = PONO;
       return xmldoc;
   end getpo;
end porder;
/
show errors
/

Generating the PL/SQL Web Service

First, download the latest release of JDeveloper (i.e., jdevstudio1013.zip) from the Oracle Technology Network (see OC4J download link). JDeveloper installation consists of unzipping the download object. Upon the installation, launch the IDE by clicking on its icon.

Assume you have a running JDeveloper, and now you need to:

  • Create an application (DBWS.jws) and a new project (PLSQLWS.jpr).

  • Create a connection to an Oracle database where the table and package have been created.

  • Create a connection to the stand-alone OC4J (installed previously) or to an Oracle application. For development purposes, you can just use the embedded OC4J in JDeveloper.

The following screenshots illustrate the various steps for assembling the PL/SQL Web service from the package; alternatively, you may create the Web service from a project.

Step 0: This initial step consists of opening the database schema by right-clicking on the database connection in the navigator and locating the existing packages.

Step 1: Right-click on the desired package and select “Publish as Web Service” to launch the PL/SQL Web Services wizard. Accept or set the Web services name and the Java package.

Step 2: As Figure 15.4 depicts, the wizard lets you specify the Web service name, the Java package for the service wrapper, and the binding options: SOAP 1.1, SOAP 1.2, and WSIF. For this demo, accept or edit the default and go to the next step.

PL/SQL Web Services: Name,Package, and Binding

Figure 15.4. PL/SQL Web Services: Name,Package, and Binding

Step 3: As depicted by Figure 15.5, the wizard lets you choose the message format; accept the default SOAP message format (i.e., Document Wrapped).

PL/SQL Web Services: Message Format

Figure 15.5. PL/SQL Web Services: Message Format

Step 4: As depicted by Figure 15.6, the wizard lists all the functions in the package. Select/check the ones you want to be accessible as service operations and go to the next step.

JDeveloperPL/SQL Web services operations selectionPL/SQL Web serviceoperations selectionPL/SQL Web Services: Operations Selection

Figure 15.6. PL/SQL Web Services: Operations Selection

Step 5: As depicted by Figure 15.7, the wizard lets you specify the type mappings. Click on the Help button at the bottom of the screen for more details on the various choices. For this demo, we’ll accept the default settings and go to the next step.

PL/SQL Web Services: Type-Mapping Options

Figure 15.7. PL/SQL Web Services: Type-Mapping Options

Step 6: Optionally, as depicted by Figure 15.8, you may specify the user-defined type mapping between SQL or PL/SQL types and Java wrapper classes, as discussed in Chapter 13 and summarized in Table 13.2. You may also specify the mapping of the PL/SQL types unsupported by JDBC or the Web services framework, using the in-database conversion approach covered in Chapter 13. This demo does not have such a requirement, so you can go to the next step.

PL/SQL Web Services: User-Defined Type Mapping

Figure 15.8. PL/SQL Web Services: User-Defined Type Mapping

Step 7: During this step, as depicted by Figure 15.9, you may specify user-defined SOAP message handlers. These classes are used to process request messages (client handlers) and response messages (server handlers) and implement logging, auditing, and encryption/decryption. There is no user-defined handler for this demo, so click on the Next or Finish button to trigger the generation of the Web service.

JDeveloperPL/SQL Web services SOAP message handlerJDeveloperPL/SQL Web services WSDL structurePL/SQL Web serviceSOAP message handlerPL/SQL Web serviceWSDL structureJDeveloperPL/SQL Web services typemapping optionsJDeveloperPL/SQL Web services userdefined type mappingPL/SQL Web servicetype-mapping optionsPL/SQL Web serviceuser-defined type mappingPL/SQL Web Services: SOAP Message Handler

Figure 15.9. PL/SQL Web Services: SOAP Message Handler

At this stage, the WSDL has been generated, as depicted by Figure 15.10, which shows a nice structure of the WSDL, including the services, bindings, port types, and messages. Chapter 14 explains the meaning of each component of the WSDL. See, in the following text, the actual values of the services, bindings, port types, and message components of the PL/ SQL Web Services WSDL.

PL/SQL Web Services: WSDL Structure

Figure 15.10. PL/SQL Web Services: WSDL Structure

  • Service:

    <service name="PLSQLWS">
          <port name="PLSQLWSSoapHttpPort" binding="tns:PLSQLWSSoapHttp">
             <soap:address location="http://141.144.72.251:8888/DBWS-
              PLSQLWS-context-root/PLSQLWSSoapHttpPort"/>
          </port>
    </service>
  • Binding:

    <binding name="PLSQLWSSoapHttp" type="tns:PLSQLWS">
       <soap:binding style="document"
            transport="http://schemas.xmlsoap.org/soap/http"/>
       <operation name="getpo">
           <soap:operation
                 soapAction="http://dbconnection1/PLSQLWS.wsdl/getpo"/>
              <input>
                  <soap:body use="literal" parts="parameters"/>
               </input>
               <output>
                   <soap:body use="literal" parts="parameters"/>
              </output>
        </operation>
      </binding>
  • Port type:

     <portType name="PLSQLWS">
            <operation name="getpo">
                <input message="tns:PLSQLWS_getpo"/>
                <output message="tns:PLSQLWS_getpoResponse"/>
            </operation>
     </portType>
  • Message:

    <message name="PLSQLWS_getpo">
            <part name="parameters" element="tns0:getpoElement"/>
    </message>
    
    <message name="PLSQLWS_getpoResponse">
            <part name="parameters"
    element="tns0:getpoResponseElement"/>
    </message>
  • Types: (see Table 15.1 for SQL type to XML type mapping).

The following XML fragment specifies the mapping of SQL NUMBER to XML decimal:

<element name="pono" type="decimal" nillable="true"/>

The following XML fragment specifies the mapping of SYS.XMLTYPE to XML any (literal style):

 <element name="result" nillable="true">
       <complexType>
           <sequence> <any/> </sequence>
        </complexType>
 </element>

Step 8: Deploy the PL/SQL Web service; as depicted in Figure 15.11, right-clicking and selecting Run on the WSDL results in the deployment of the generated Java proxy representing the PL/SQL package at the returned endpoint. In this example, the Web service has been deployed against the embedded OC4J in JDeveloper, but, depending on the application server connection specified, you may deploy against a stand-alone OC4J or a full-fledged Oracle Application Server.

PL/SQL Web Services Deployment

Figure 15.11. PL/SQL Web Services Deployment

The wizard returns the endpoint at which the PL/SQL Web service is listening:

http://kmensah-lap1:8988/DBWS-PLSQLWS-context-root/
PLSQLWSSoapHttpPort

Step 9 (Optional): At this stage, you may add quality of services, such as security, reliability, logging, auditing, and analyze the WSDL for WS-I interoperability, using the Web Services Editor, as depicted in Figures 15.12 and 15.13.

Web Services Editor: Reliability

Figure 15.12. Web Services Editor: Reliability

Web Services Editor: Security

Figure 15.13. Web Services Editor: Security

These quality of services can also be added using Oracle Enterprise Manager 10g Application Control.

As depicted in Figure 15.14, a browser-based test page (i.e., Web Service Home Page) has been generated at the following endpoint:

PL/SQL Web Service Test Page

Figure 15.14. PL/SQL Web Service Test Page

http://kmensah-lap1:8988/DBWS-PLSQLWS-context-root/
PLSQLWSSoapHttpPort

Step 10: Invoking the Web service through the test page. As illustrated by Figure 15.15, you can invoke the service using the purchase order number.

Invoking PL/SQL Web Service through the Test Page

Figure 15.15. Invoking PL/SQL Web Service through the Test Page

As illustrated by Figure 15.16, you can see the SOAP request and the SOAP response messages:

PL/SQL Web Service Request and Response SOAP Messages

Figure 15.16. PL/SQL Web Service Request and Response SOAP Messages

SOAP Request
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/
envelope/">
    <soap:Body xmlns:ns1="http://dbconnection1/PLSQLWS.wsdl/
types/">
        <ns1:getpoElement>
            <ns1:pono>2004</ns1:pono>
        </ns1:getpoElement>
    </soap:Body>
</soap:Envelope>

SOAP response
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/
envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns0="http://dbconnection1/PLSQLWS.wsdl/types/
"><env:Body><ns0:getpoResponseElement><ns0:result><PORDER
PONUM="2004"> <CLIENT> <CLNUM>2000</CLNUM> <CLNAME>Bobo
Lafleur</CLNAME> <ADDRESS> <STREET>24 Cartoon Drive </STREET>
<CITY>San Francisco</CITY> <STATE>CA</STATE> <ZIP>94313</ZIP>
</ADDRESS> <PHONES> <VARCHAR2>415-666-0000</VARCHAR2> </
PHONES> </CLIENT> <ORDERDATE>10-FEB-06</ORDERDATE>
<SHIPDATE>12-FEB-06</SHIPDATE> <LITEMS> <LITEM_TYP
ItemNum="1"> <ITEM StockNo="1324"> <PRICE>199</PRICE>
<TAXRATE>8</TAXRATE> </ITEM> <QUANTITY>11</QUANTITY>
<DISCOUNT>10</DISCOUNT> </LITEM_TYP> <LITEM_TYP ItemNum="2">
<ITEM StockNo="2324"> <PRICE>299</PRICE> <TAXRATE>8</TAXRATE>
</ITEM> <QUANTITY>22</QUANTITY> <DISCOUNT>20</DISCOUNT>  </
LITEM_TYP> </LITEMS> <SHIPTOADDRESS/> </PORDER></
ns0:result></ns0:getpoResponseElement></env:Body></
env:Envelope>

At this stage, the PL/SQL Web service has been deployed and listening for incoming requests at its endpoint. But remember, Web services are about application-to-application interaction using XML messaging such as SOAP, and the client application can be implemented in any language and reside on any platform. As a Web service assembler (“developer” is not appropriate here), you certainly don’t want to code to SOAP; fortunately, most Web services frameworks furnish tools/utilities that generate the client proxy specific to the Web service client framework from the WSDL (i.e., a Java proxy for a Java Web services framework, a .NET proxy code for .NET framework). So, for this demo to be complete, the next section takes you through the generation of a Java client proxy from the PL/SQL Web service WSDL.

Generating the PL/SQL Web Service Proxy

Step 1: Generate the proxy template.

JDeveloper lets you specify the target platform hosting the service, since the Web service may be hosted on the embedded OC4J, a stand-alone OC4J, or a full-fledged Oracle Application Server.

For this demo, we have deployed the service on the embedded OC4J in JDeveloper, so right-click on the PLSQLWS.wsdl, and select Generate Web Service Proxy; accept the default and proceed to the generation of the Java proxy. And here is the generated PLSQLWSSoapHttpPortClient.java.

PLSQLWSSoapHttpPortClient.java
==============================
package dbconnection1;

import oracle.webservices.transport.ClientTransport;
import oracle.webservices.OracleStub;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.Stub;

import oracle.xml.parser.v2.XMLElement;

...
public class PLSQLWSSoapHttpPortClient {

/**
  * @param args
  */
   public static void main(String[] args) {
   try
   {
      dbconnection1.PLSQLWSSoapHttpPortClient myPort =
         new dbconnection1.PLSQLWSSoapHttpPortClient();
      System.out.println("calling " + myPort.getEndpoint());
      // Add your own code here

    } catch (Exception ex) {
            ex.printStackTrace();
    }
 }
}

The code generator cannot guess which parameter to use from the client application, so this is the only place where you need a little Java expertise to come up with the following instruction to invoke the service with the appropriate parameter (as we did using the test page).

((XMLElement)myPort.getpo(new
java.math.BigDecimal("2004"))).print(System.out);

Update the proxy code as follows:

/**
  * @param args
  */
   public static void main(String[] args) {
   try
   {
      dbconnection1.PLSQLWSSoapHttpPortClient myPort =
         new dbconnection1.PLSQLWSSoapHttpPortClient();
      System.out.println("calling " + myPort.getEndpoint());
      // Add your own code here
      ((XMLElement)myPort.getpo(new
          java.math.BigDecimal("2004"))).print(System.out);

    } catch (Exception ex) {
            ex.printStackTrace();
    }
}

Note: You also need to accept the following import statement that JDeveloper has inserted in the resulting PLSQLWSSoapHttpPortClient.java:

import oracle.xml.parser.v2.XMLElement;

Save and proceed to step 2.

Step 2: Compile and run the Web Services Proxy.

To see the HTTP traffic between the WS Proxy and the WS, select “HTTP Analyzer” in the View panel. Then, in the application navigation panel, right-click on PLSQLWSSoapHttpPortClient.java and select Run. As depicted in Figure 15.17, you will see the SOAP request (same as in the test page case) and the SOAP response (more nicely displayed than in the test page invocation).

PL/SQL Web Services Invocation from Proxy

Figure 15.17. PL/SQL Web Services Invocation from Proxy

That’s it.

PL/SQL Web Services Limitations with JDeveloper

The following restrictions apply to PL/SQL Web services generation using JDeveloper (some of these limitations are specific to JDeveloper):

  • Stored procedures of the same name that are accessible in multiple schema will fail the code generators.

  • An overloaded program unit sharing the same name with another program unit in the same package. The WSDL processor cannot determine which program unit to execute; therefore, such PL/SQL program units cannot be deployed as Web services.

  • The BFILE type can only be used as an OUT argument or as a function return value.

  • PL/SQL pads CHAR type data into a string of length 4,001, which exceeds the 4,000 limit and results in a JDBC SQL exception.

  • The PL/SQL BCLOB type is not supported.

  • PL/SQL record type is not supported for creating directly, so you need to explicitly use JPublisher to produce a new package that uses supported types as parameters or specify the type map (see step 6).

  • Ref cursors return types: A PL/SQL package that returns a ref cursor type, such as the following code fragment, is not exposable as Web services:

    package refcur_pkg as type refcur_t is ref cursor;
    function RetRefCur return refcur_pkg.refcur_t;end;
  • SYS schema: It is generally a bad practice to allow user objects in the SYS schema; consequently, JDeveloper does not allow creating a Web service from a package owned by SYS schema.

  • Types declared within a package spec: PL/SQL packages that declare new types within the package specification cannot be published as Web services. The workaround is to create the types externally to the package.

  • Nested Tables: JDeveloper does not allow creating Web services from PL/SQL packages that use PL/SQL Nested Tables.

This concludes the wizard-driven approach for assembling PL/SQL Web services. The next section introduces you to the command-line approach, which supports more database programming models than JDeveloper, including PL/SQL, Java in the database (see Part I), SQL query, SQL DML, and streams AQ.

Assembling Database Web Services Using the Command-Line Tool

Contrasted with the JDeveloper wizard-driven approach, the WSA approach may appear cumbersome but currently supports more models than JDeveloper. This section briefly describes the Web Service Assembler, then the generic steps for exposing database functionality with it, showing a complete example of publishing database functionality using WSA.

Introducing the Web Services Assembler

The Web Services Assembler utility furnishes options and APIs for assembling and deploying Web services on the Oracle AS Web Services layer.

It uses JPublisher under the covers and is delivered as a JAR file (wsa.jar) under $OC4J_HOME/webservices/lib. It is integrated with the Apache Ant and Oracle JDeveloper. It can be invoked:

  • Using either the following command:

    -java -jar wsa.jar ...

  • Or as Ant tasks, with the WSA option corresponding to the database functionality to be exposed:

<oracle:plsqlAssemble .../>
<oracle:sqlAssemble .../>
<oracle:dbJavaAssemble .../>
<oracle:aqlAssemble .../>

Prerequisites:Make sure JAVA_HOME/bin and JDK 1.4 or later are in the PATH.

The following wsa options are required for all database Web services types:

  • appName: Web service application name

  • dbConnection: Database connection URL used at code generation time (assume it will be different from the production database used at runtime)

  • dbUser: Database user and password used at code generation time (assume same schema and objects at runtime)

  • dataSource: JNDI location of the datasource used at runtime

As described in Chapter 13, JPublisher now generates code to retry database connection in case of loss of database connection.

The following WSA options may be used to specify additional details:

  • context: Root context for the Web application

  • debug: Displays detailed diagnostic messages

  • ear: Name and location of the generated J2EE EAR file, which contains the Java wrapper for the database functionality exposed as Web service

  • jpubProp: JPublisher options to fine-tune code generation

  • output: Location for storing generated files

  • portName: Name of the port in the generated WSDL

  • serviceName: Local part of the service name in the generated WSDL

  • style: Style part of the message format used in the generated WSDL

  • uri: URI for the Web service to use in deployment descriptors

  • use: Use part of the message format used in the generated WSDL

Generic Steps for Publishing Database Functionality Using Web Services Assembler

Assembling database Web services using the command line involves the following eight steps:

  • Step 1: Determine the functionality to be exposed.

  • Step 2: Run the Web Services Assembler tool to assemble the Web service, based on the specified database functionality.

  • Step 3: If PL/SQL wrappers are generated and the sysUser argument is not set, you will have to load the generated PL/SQL wrapper(s) into the database. The Web Services Assembler tool (WSA) will load the wrapper automatically otherwise.

  • A PL/SQL wrapper is generated (under the covers by JPublisher) when the PL/SQL RECORD and INDEX BY TABLE types are used in the PL/SQL package.

  • Similarly, a PL/SQL wrapper is also generated for exposing Java in the database; otherwise, you will have to load it manually using sqlplus.

  • Step 4: Configure the OC4J datasources to ensure that the JPublisher-generated Java proxy class can connect to the database and the functionality it represents.

  • Step 5: Deploy the Web service application into a running instance of OC4J.

  • Step 6: Optionally, check that the deployment is successful using the generated test page (i.e., Web service home page).

  • Step 7: Use the Web Services Assembler tool (WSA) to generate the Web services client proxy and incorporate it into your client application.

  • Step 8: Invoke the Web service using the client proxy.

The rest of this chapter describes the steps mentioned here for assembling and publishing PL/SQL packages, Java in the database, SQL Query/ DML, and streams AQ using the Web Services Assembler.

Assembling PL/SQL Web Services Using Web Services Assembler

Prerequisite:

  • Select the PL/SQL package that you want to expose as a Web service:

    REFCUR
    
    package refcur as
       type curstype is ref cursor return emp%rowtype;
       FUNCTION getcurfunc RETURN curstype;
       PROCEDURE getcurproc(a curstype);
    end;
    
    package BODY refcur as
    
      FUNCTION getcurfunc RETURN curstype IS curs curstype;
       BEGIN
         open curs for select * from emp where ename='SCOTT';
         return curs;
       END;
    
      PROCEDURE getcurproc(a curstype) IS name emp%rowtype;
       BEGIN
          LOOP
            FETCH a INTO  name ;
            EXIT WHEN a%NOTFOUND;
            dbms_output.put_line(name.ENAME);
          END LOOP;
        close a;
       END;
    
    END;
  • The name for the Web service application: REFCURWS

  • The JNDI location for the JDBC datasource to be used at runtime: jdbc/OracleManagedDS

  • The JDBC URL for database connection and the username and password to be used at compile/generation time:

"jdbc:oracle:thin:@//localhost:5521/<global database name>
        scott/tiger 

Step 1a

Provide the PL/SQL package and the information described in the Prerequisites section as input to the Web Services Assembler plsqlAssemble command described hereafter:

java -jar wsa.jar
-plsqlAssemble
-appName RefCurWS
-sql refcur
-dataSource jdbc/OracleManagedDS
-dbConnection jdbc:oracle:thin:@//<your global database name>
-dbUser scott/tiger
-style rpc
-use encoded

Here is the effective command (you need to replace <your global database name> with the actual global database name in your environment):

$ java -jar $ORACLE_HOME/webservices/lib/wsa.jar -
plsqlAssemble -appName PLSQLRefCurWS -sql refcur -dataSource
jdbc/OracleManagedDS –dbConnection jdbc:oracle:thin:@//
localhost:5521/<global database name> -dbUser scott/tiger -
style rpc -use encoded 

This command generates the following files and directory structures:

  • PLSQLRefCurWS.ear

  • ear

    • META-INF

    • PLSQLRefCurWS-web.war

  • WarW

    • WEB-INF

  • src/server/oracle/generated

    • GetcurfuncRowBase.java

    • GetcurfuncRowUser.java

    • refcur.java

    • refcurBase.java

    • refcurUser.java

As mentioned in Table 15.1, WSA generates the following three interfaces to map REF CURSOR according to the encoding (literal/encoded) to: an Array of Beans (Array/Array), an XMLTYpe (any/text_xml), and an OracleWebRowSet (swaRef/text_xml). See the getcurfuncXMLSource(), getcurfuncXMLRowSet(), andgetcurfuncBeans() interfaces in refcur.java.

refcur.java
===========

package oracle.generated;

import java.sql.SQLException;
import java.sql.Connection;
import java.io.*;

public interface refcur extends java.rmi.Remote{


  public javax.xml.transform.Source  getcurfuncXMLSource()
throws java.rmi.RemoteException;
  public javax.xml.transform.Source  getcurfuncXMLRowSet()
throws java.rmi.RemoteException;
  public GetcurfuncRowUser[] getcurfuncBeans() throws
java.rmi.RemoteException;
}

For more details, see the “Mapping PL/SQL IN and IN OUT Parameters to XML IN OUT Parameters” section in the Oracle AS 10.1.3 Web Services Guide.

Step 1b

Alternatively, you can use an Ant task for generating PL/SQL Web services. The following code fragment is an Ant task for the Web Services Assembler to be inserted in the build.xml:

<oracle:plsqlAssemble
dbUser="scott/tiger"
sql="refcur"
dbConnection="jdbc:oracle:thin:@ :@//localhost:5521/
lab.regress.rdbms.dev.us.oracle.com "
dataSource="jdbc/OracleManagedDS"
appName="RefCurWS"
style="rpc"
use="encoded"
/>

Step 2 (Optional)

If WSA generates PL/SQL wrappers (RECORD and INDEX-BY-TABLE), these must be loaded into the user schema in the database either manually using SQL*Plus (just run the wrapper) or automatically by WSA using the following option of plsqlAssemble:

  • -jpubProp plsqload for the command line

  • jpubprop="plsqlload" for the Ant task

No wrapper has been generated for this demo.

Step 3 and 4

Not necessary (or already done).

Step 5

J2EE_HOME being the file system directory where the OC4J is installed, and 23791 the RMI port, you can deploy the service into a running instance of OC4J and bind the application, using the following command:

$ java -jar $J2EE_HOME/admin_client.jar
deployer:oc4j:localhost:23791 oc4jadmin welcome -deploy -file
PLSQLRefCurWS.ear -deploymentName PLSQLRefCurWS -
bindAllWebApps

06/02/12 20:48:49 Notification ==>Uploading file
PLSQLRefCurWS.ear ...
06/02/12 20:48:49 Notification ==>Application Deployer for
PLSQLRefCurWS STARTS.
06/02/12 20:48:49 Notification ==>Undeploy previous
deployment
06/02/12 20:48:49 Notification ==>Initialize /kmensah_oc4j/
j2ee/home/applications/PLSQLRefCurWS.ear begins...
06/02/12 20:48:49 Notification ==>Initialize /kmensah_oc4j/
j2ee/home/applications/PLSQLRefCurWS.ear ends...
06/02/12 20:48:49 Notification ==>Starting application :
PLSQLRefCurWS
06/02/12 20:48:49 Notification ==>Initializing ClassLoader(s)
06/02/12 20:48:49 Notification ==>Initializing EJB container
06/02/12 20:48:49 Notification ==>Loading connector(s)
06/02/12 20:48:49 Notification ==>Starting up resource
adapters
06/02/12 20:48:49 Notification ==>Initializing EJB sessions
06/02/12 20:48:49 Notification ==>Committing ClassLoader(s)
06/02/12 20:48:49 Notification ==>Initialize PLSQLRefCurWS-
web begins...
06/02/12 20:48:49 Notification ==>Initialize PLSQLRefCurWS-
web ends...
06/02/12 20:48:49 Notification ==>Started application :
PLSQLRefCurWS
06/02/12 20:48:49 Notification ==>Binding web application(s)
to site default-web-site begins...
06/02/12 20:49:03 Notification ==>Binding web application(s)
to site default-web-site ends...
06/02/12 20:49:03 Notification ==>Application Deployer for
PLSQLRefCurWS COMPLETES. Operation time: 14047 msecs

$

You can check that the Web service is indeed deployed, as depicted in Figure 15.18, by connecting to Oracle Enterprise Manager (oc4jadmin) at the following URL:

Oracle Enterprise Manager (oc4jadmin)

Figure 15.18. Oracle Enterprise Manager (oc4jadmin)

http://<hostname>:8888/em

See the OC4J Deployment Guide for more information on deploying EAR files.

Step 6 (Optional)

Test the service by clicking on Test Service on the OEM screen (top left), as depicted by Figure 15.19. The test page will give three functions: getcurfuncBeans, which retrieves an array of Beans; getcurfuncXMLSource(), which retrieves an XML (i.e., any/text_xml); and getcurfuncXMLRowSet(), which retrieves an XMLRowSet (i.e., swaRef/text_xml).

Web Services Test Page

Figure 15.19. Web Services Test Page

As you can see, getcurfuncBeans has been selected because the test page only support simple types such as primitive types and bean or array of such types; selecting the other functions will hang the browser.

Step 7

Generate the Web Service Proxy using the -genProxy option of the Web Services Assembler:

$java -jar $OC4J_HOME/webservices/lib/wsa.jar -genProxy -wsdl
"http://<hostname>:8888/PLSQLRefCurWS/PLSQLRefCurWS?wsdl"  -
output ./wsclient

This command generates the following files and directories:

wsclient/oracle/generated/GetcurfuncRowUser.java
HttpSoap11Client.java
======================
...
/**
     * @param args
     */
    public static void main(String[] args) {
        try {
            oracle.generated.HttpSoap11Client myPort =
             new oracle.generated.HttpSoap11Client();
            System.out.println("calling " +
                 myPort.getEndpoint());
            // Add your own code here

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
PLSQLRefCurWS.java  Refcur.java
runtime/

Similar to the Web service proxy generated using JDeveloper, you need to edit HttpSoap11Client.java and insert the following fragment into the proxy class below the “//Add your own code”:

GetcurfuncRowUser user;
GetcurfuncRowUser[] users = myPort.getcurfuncBeans();
int le = users.length;
for (int i=0; i<le; i++) {
user = users[i];
System.out.println("Employee " + user.getEname());
System.out.println("Emp# " + user.getEmpno());
System.out.println("Department# " + user.getDeptno());
System.out.println("Manager " + user.getMgr());
//System.out.println("Hiredate " + user.getHiredate());
System.out.println("Job " + user.getJob());
System.out.println("Salary " + user.getSal());
System.out.println("Commission " + user.getComm());}

Step 8

Compile and run the client using the following command (you may add the additional JAR files to the CLASSPATH beforehand):

javac -classpath ${CLASSPATH}:${OC4J_HOME}/webservices/lib/
wsclient_extended.zip:${OC4J_HOME}/webservices/lib/jaxrpc-
api.jar oracle/generated/HttpSoap11Client.java

You may need to compile the Java classes in Oracle/generated/runtime:

javac oracle/generated/runtime/*.java

Then run the client application:

$ java -classpath ${CLASSPATH}: ${OC4J_HOME}/webservices/lib/
wsclient_extended.jar:
${OC4J_HOME}/webservices/lib/jaxrpc-api.jar:
${J2EE_HOME}/lib/jax-qname-namespace.jar:
${J2EE_HOME}/lib/activation.jar:${J2EE_HOME}/lib/mail.jar:
${J2EE_HOME}/lib/http_client.jar:
${OC4J_HOME}/lib/xmlparserv2.jar oracle/generated/HttpSoap11Client
$ java -classpath ${CLASSPATH}:${OC4J_HOME}/webservices/lib/
wsclient_extended.zip:${OC4J_HOME}/webservices/lib/jaxrpc-
api.jar:${J2EE_HOME}/lib/jax-gname-namespace.jar:${J2EE_HOME}/lib/
activation.jar:{J2EE_HOME}/lib/mail.jar:${J2EE_HOME}/lib/
http_client.jar:${ORACLE_HOME}/lib/xmlparserv2.jar oracle/generated/
HttpSoap11Client
calling http://<hostname>:8888/PLSQLRefCurWS/PLSQLRefCurWS
Employee SCOTT
Emp# 7788
Department# 20
Manager 7566
Job ANALYST
Salary 4350
Commission null

At this stage, you may add the quality of services using the Web Service Administration page of Oracle Enterprise Manager Application Control, as depicted in Figure 15.20.

OEM Application Control, Web Service Administration

Figure 15.20. OEM Application Control, Web Service Administration

Voilà!

For retrieving XML documents instead of Array of Beans, try adding the following code fragment to HttpSoap11Client.java in Step 7:

System.out.println("*** XML Document ***");
 Element soapElem = eme.getcurfuncXMLSource();
 Source source = new DOMSource(soapElem);
 Transformer trans =
TransformerFactory.newInstance().newTransformer();
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    StreamResult streamr = new StreamResult(buf);
    trans.transform(source, streamr);
    System.out.println(buf.toString()); 

For WebRowSet, try adding the following code in HttpSoap11Client.java in Step 7:

   System.out.println("*** WebRowSet ***");
    soapElem = eme.getcurfuncXMLRowSet();
    source = new DOMSource(soapElem);
    trans = TransformerFactory.newInstance().newTransformer();
    buf = new ByteArrayOutputStream();
    streamr = new StreamResult(buf);
    trans.transform(source, streamr);
    InputStream istream =
            new ByteArrayInputStream(buf.toString().getBytes());
    OracleWebRowSet rowset = new OracleWebRowSet();
    System.setProperty("http.proxyHost", "www-proxy.us.oracle.com");
    System.setProperty("http.proxyPort", "80");
    //System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
             "oracle.xml.jaxp.JXDocumentBuilderFactory");
    System.setProperty("org.xml.sax.driver",
                   "oracle.xml.parser.v2.SAXParser");
    System.out.println("rowset read xml");
    rowset.readXml(new InputStreamReader(istream));
    System.out.println("rowset write xml");
    rowset.writeXml(new PrintWriter(System.out));
    System.out.flush();  

Assembling Java in the Database as a Web Service

The idea here is to generate a client-side stub to be deployed in the Web Services layer.

Prerequisites:

The fully qualified name of the server-side Java class. It may contain any of the following types as parameters and return types:

  • Primitive types (except char)

  • Serializable types

  • JavaBeans, whose attributes are supported types

  • Standard JDBC types (i.e., java.sql.*) and Oracle JDBC types (i.e., oracle.sql.*)

  • Arrays of supported types

  • Select a Java class in the database

  • The name for the Web service application: JavaDbWS

  • The JNDI location for the JDBC datasource to be used at runtime: jdbc/OracleManagedDS

  • The JDBC URL for database connection and the username and password to be used at compile/generation time:

"jdbc:oracle:thin:@//localhost:5521/<global database
name>
scott/tiger 

Step 1a

java -jar wsa.jar
-dbJavaAssemble
-appName JavaDbWS
-dbJavaClassName REFCUR
-dataSource jdbc/OracleManagedDS
-dbConnection jdbc:oracle:thin:@//<hostname>:<port>/<global
database name>
-dbUser scott/tiger
-sysUser system/manager

Step 1b

Alternatively, you may use an Ant task with the Web Services Assembler dbJavaAssemble command:

<oracle:dbJavaAssemble
appName="javacallin"
dbJavaClassName="REFCUR"
dbConnection="jdbc:oracle:thin:@<hostname>:<port>/<service>"
dataSource="jdbc/OracleManagedDS"
dbUser="scott/tiger"
sysUser="system/manager"
/>

Steps 2 through 6 are similar to the PL/SQL equivalent.

Assembling SQL Queries or SQL DML Statements as Web Services

Prerequisites:

  • Determine the SQL queries and DML to be published. Multiple sqlstatement arguments can be specified on the command line (or on the Ant task). Note: The DML statements (INSERT/UPDATE/ DELETE) are auto-committed.

  • The name for the Web service application.

  • The JNDI location for the JDBC datasource to be used at runtime.

  • The JDBC URL for database connection and the username and password to be used at compile/generation time.

Assembling a SQL Query Web Service from a SQL Statement

Step 1a

Provide the SQL statements or query, the name and password for the database that they are based on, and the other information described in the Prerequisites section as input to the Web Services Assembler sqlAssemble command, as in the following example:

java -jar wsa.jar
-sqlAssemble
-appName query
-dataSource jdbc/OracleManagedDS
-sqlstatement "getEmpCount=select ename, sal from emp where
sal>:{mysal NUMBER}"
-sqlstatement "getEmpBySal=select ename, sal from emp where
sal>:{mysal NUMBER}"
-sqlstatement "updateEmp=update emp SET sal=sal+500 where
ename=:{myname VARCHAR}"
-dbConnection jdbc:oracle:thin:@stacd15:1521:lsqlj
-dbUser scott/tiger

Step 1b

Use the Ant task for generating Query or DML Web Services: The current release provides Ant tasks for Web services development. The following example shows how the Web Services Assembler sqlAssemble command can be performed as an Ant task:

<oracle:sqlAssemble
appName="query"
dataSource="jdbc/OracleManagedDS"
dbConnection="jdbc:oracle:thin:@dsunrde22:1521:sqlj"
dbUser="scott/tiger">
<sqlstatement="getEmpCount=select ename, sal from emp where
sal>:{mysal
NUMBER}"/>
<sqlstatement="getEmpBySal=select ename, sal from emp where
sal>:{mysal
NUMBER}"/>
<sqlstatement="updateEmp=update emp SET sal=sal+500 where
ename=:{myname
VARCHAR}"/>
/>

Assembling Oracle Streams AQ as Web Services

The WebServicesAssembler tool can generate a Web service from an AQ existing in a database. Each stream AQ queue belongs to a queue table (persisted in the RDBMS), which defines the type of the payload. Stream AQ queues can have single or multiple consumers:

  • A single consumer is often referred to as a queue.

  • A multiple consumer AQ is often referred to as a topic.

The generated Java code employs the Oracle Streams AQ JMS APIs. Prerequisites:

  • The name of the queue or topic to be exposed (single queue or topic):

    The followng PL/SQL script defines a queue, sample_queue, and a topic, sample_topic. The payload of the queue is of type queue_message (SQL object type). The payload of the topic is of type topic_message (SQL object type).

  • The name for the Web service application.

  • The JNDI location for the JDBC datasource to be used at runtime.

  • The JDBC URL for database connection and the username and password to be used at compile/generation time.

Assembling Streams AQ Web Services Using Web Services Assembler

Step 1a

Furnish the inputs to Web Services Assembler -aqAssemble command:

java -jar $ORACLE_HOME/webservices/lib/wsa.jar
-aqAssemble
-appName queue
-dataSource jdbc/OracleManagedDS
-portName assembleQueuePort
-sql sample_queue
-dbConnection jdbc:oracle:thin:@stacd15:1521:lsqlj
-dbUser scott/tiger

Queues and topics must be deployed in different services using different values for sql and appName options.

Step 1b

Alternatively, an Ant task may be used instead:

<aqAssemble
appName="queue"
dataSource="jdbc/OracleManagedDS"
sql="sample_queue"
portName="assembleQueuePort"
dbConnection="jdbc:oracle:thin:@localhost:1521:lsqlj"
dbUser="scott/tiger"
/>

Steps 2 to 4 are identical to previous models.

Step 5

Developing Client Code to Access a Stream AQ Queue Web Service

SampleQueuePortClient queue = new SampleQueuePortClient();
QueueMessageUser m;
queue.send(new QueueMessageUser( "star chopper", "sample
1"));
queue.send(new QueueMessageUser("easy blocks", "sample 2"));
queue.send(new QueueMessageUser("back to future", "sample
3"));
m = queue.receive();
while (m != null) {
System.out.println("Message received from SampleQueue: " +
m.getSubject()
+ ": " + m.getText());
m = queue.receiveNoWait();
}
This client returns the following responses.
Message received from SampleQueue: sample 1: star chopper
Message received from SampleQueue: sample 2: easy blocks
Message received from SampleQueue: sample 3: back to future

Accessing an Oracle AQ Queue with JMS

The Web Services Assembler aqAssemble option lets you access the Oracle Streams AQ queue via the JMS queue instance. By setting either of the following options instead of datasource, the Web service will use a JMS queue at runtime instead of a JDBC-based queue:

  • aqConnectionLocation: JDNI location of the Oracle Streams AQ/ JMS queue connection

  • aqConnectionFactoryLocation: JNDI location of the Oracle Streams AQ/JMS queue connection factory

Data Type Restrictions

  • Streams are not supported in Oracle Streams AQ Web services.

  • SQL Type SYS.ANYDATA is not supported in PL/SQL Web services.

  • REF CURSOR is not supported as a parameter in PL/SQL Web services.

  • REF CURSOR returned as Oracle WebRowSet and XDB RowSet does not support complex types in the result.

  • PL/SQL stored procedures do not currently support the char types, including char, character, and nchar as OUT or INOUT parameters, and long types, including long and long raw as OUT or INOUT parameters.

Conclusion

In summary, the Oracle AS Web Services framework lets you turn database Web services into first-class citizens of the service-oriented architecture, since they inherit all the quality of services (e.g., Web services security, Web services reliability, Web services logging, Web services auditing).

Let’s move to the next chapter, which is about the Database as Web service consumer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.233.205