Skip Headers

Oracle® Streams Advanced Queuing User's Guide and Reference
Release 10.1

Part Number B10785-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Feedback

Go to previous page
Previous
Go to next page
Next
View PDF

17 Internet Access to Oracle Streams AQ

You can access Oracle Streams Advanced Queuing (AQ) over the Internet by using Simple Object Access Protocol (SOAP). Internet Data Access Presentation (IDAP) is the SOAP specification for Oracle Streams AQ operations. IDAP defines XML message structure for the body of the SOAP request. An IDAP-structured message is transmitted over the Internet using HTTP.

This chapter contains these topics:

Overview of Oracle Streams AQ Operations over the Internet

Figure 17-1 shows the architecture for performing Oracle Streams AQ operations over HTTP. The major components are:

The Oracle Streams AQ client program sends XML messages (conforming to IDAP) to the Oracle Streams AQ servlet. Any HTTP client, for example Web browsers, can be used. The Web server/Servlet Runner hosting the Oracle Streams AQ servlet interprets the incoming XML messages. Examples include Apache/Jserv or Tomcat. The Oracle Streams AQ servlet connects to the Oracle Database server and performs operations on the users' queues.

Figure 17-1 Architecture for Performing Oracle Streams AQ Operations Using HTTP

Description of adque430.gif follows
Description of the illustration adque430.gif

Internet Data Access Presentation (IDAP)

The Internet Data Access Presentation (IDAP) uses the Content-Type of text/xml to specify the body of the SOAP request. XML provides the presentation for IDAP request and response messages as follows:

SOAP Message Structure

SOAP structures a message request or response as follows:

  • SOAP envelope (the root or top element in an XML tree))

  • SOAP header (first element under the root)

  • SOAP body (the Oracle Streams AQ XML document)

The SOAP Envelope

The tag of this root element is SOAP:Envelope. SOAP defines a global attribute SOAP:encodingStyle that indicates serialization rules used instead of those described by the SOAP specification. This attribute can appear on any element and is scoped to that element and all child elements not themselves containing such an attribute. Omitting SOAP:encodingStyle means that type specification has been followed (unless overridden by a parent element).

The SOAP envelope also contains namespace declarations and additional attributes, provided they are namespace qualified. Additional namespace-qualified subelements can follow the body.

SOAP Headers

The tag of this first element under the root is SOAP:Header. A SOAP header passes necessary information, such as the transaction ID, with the request. The header is encoded as a child of the SOAP:Envelope XML element. Headers are identified by the name element and are namespace-qualified. A header entry is encoded as an embedded element.

The SOAP Body

The SOAP body, tagged SOAP:Body, contains a first subelement whose name is the method name. This method request element contains elements for each input and output parameter. The element names are the parameter names. The body also contains SOAP:Fault, indicating information about an error.

For performing Oracle Streams AQ operations, the SOAP body must contain an Oracle Streams AQ XML document. The Oracle Streams AQ XML document has the namespace http://ns.oracle.com/AQ/schemas/access

SOAP Method Invocation

A method invocation is performed by creating the request header and body and processing the returned response header and body. The request and response headers can consist of standard transport protocol-specific and extended headers.

HTTP Headers

The POST method within the HTTP request header performs the SOAP method invocation. The request should include the header SOAPMethodName, whose value indicates the method to be invoked on the target. The value consists of a URI followed by a "#", followed by a method name (which must not include the "#" character), as follows:

SOAPMethodName: http://ns.oracle.com/AQ/schemas/access#AQXmlSend

The URI used for the interface must match the implied or specified namespace qualification of the method name element in the SOAP:Body part of the payload.

Method Invocation Body

SOAP method invocation consists of a method request and optionally a method response. The SOAP method request and method response are an HTTP request and response, respectively, whose content is an XML document that consists of the root and mandatory body elements. This XML document is referred to as the SOAP payload in the rest of this chapter.

The SOAP payload is defined as follows:

  • The SOAP root element is the top element in the XML tree.

  • The SOAP payload headers contain additional information that must travel with the request.

  • The method request is represented as an XML element with additional elements for parameters. It is the first child of the SOAP:Body element. This request can be one of the Oracle Streams AQ XML client requests described in the next section.

  • The response is the return value or an error or exception that is passed back to the client.

At the receiving site, a request can have one of the following outcomes:

  1. The HTTP infrastructure on the receiving site is able to receive and process the request. In this case, the HTTP infrastructure passes the headers and body to the SOAP infrastructure.

  2. The HTTP infrastructure on the receiving site cannot receive and process the request. In this case, the result is an HTTP response containing an HTTP error in the status field and no XML body.

  3. The SOAP infrastructure on the receiving site is able to decode the input parameters, dispatch to an appropriate server indicated by the server address, and invoke an application-level function corresponding semantically to the method indicated in the method request. In this case, the result of the method request consists of a response or error.

  4. The SOAP infrastructure on the receiving site cannot decode the input parameters, dispatch to an appropriate server indicated by the server address, and invoke an application-level function corresponding semantically to the interface or method indicated in the method request. In this case, the result of the method is an error that prevented the dispatching infrastructure on the receiving side from successful completion.

In the last two cases, additional message headers can be present in the results of the request for extensibility.

Results from a Method Request

The results of the request are to be provided in the form of a request-response. The HTTP response must be of Content-Type text/xml. A SOAP result indicates success and an error indicates failure. The method response never contains both a result and an error.

IDAP Documents

The body of a SOAP message is an IDAP message. This XML document has the namespace http://ns.oracle.com/AQ/schemas/access. The body represents:

IDAP Client Requests for Enqueue

Client send and publish requests use the following methods:

  • AQXmlSend—to enqueue to a single-consumer queue

  • AQXmlPublish—to enqueue to multiconsumer queues/topics

AQXmlSend and AQXmlPublish take the arguments and argument attributes shown in Table 17-1. Required arguments are shown in bold.

Table 17-1 Client Requests for Enqueue—Arguments and Attributes for AQXmlSend and AQXmlPublish

Argument Attribute
producer_options destination—specify the queue/topic to which messages are to be sent. The destination element has an attribute lookup_type, which determines how the destination element value is interpreted.
  • DATABASE (default)—destination is interpreted as schema.queue_name

  • LDAP—the LDAP server is used to resolve the destination

- visibility
  • ON_COMMIT—The enqueue is part of the current transaction. The operation is complete when the transaction commits. This is the default case.

  • IMMEDIATE—effects of the enqueue are visible immediately after the request is completed. The enqueue is not part of the current transaction. The operation constitutes a transaction on its own.

- transformation—the PL/SQL transformation to be invoked before the message is enqueued
message_set—contains one or more messages. Each message consists of a message_header and message_payload
message_header message_id—unique identifier of the message, supplied during dequeue
- correlation—correlation identifier of the message
- expiration—duration in seconds that a message is available for dequeuing. This parameter is an offset from the delay. By default messages never expire.

If the message is not dequeued before it expires, then it is moved to the exception queue in the EXPIRED state

- delay—duration in seconds after which a message is available for processing
- priority—the priority of the message. A smaller number indicates higher priority. The priority can be any number, including negative numbers.
- sender_id—the application-specified identifier
  • agent_name, address, protocol

  • agent_alias—if specified, resolves to a name, address, protocol using LDAP

- recipient_list—list of recipients; overrides the default subscriber list. Each recipient consists of:
  • agent_name, address, protocol

  • agent_alias—if specified, resolves to a name, address, protocol using LDAP

- message_state— state of the message is filled in automatically during dequeue

0 (the message is ready to be processed)

1 (the message delay has not yet been reached)

2 (the message has been processed and is retained)

3 (the message has been moved to the exception queue)

- exception_queue—in case of exceptions the name of the queue to which the message is moved if it cannot be processed successfully. Messages are moved in two cases: The number of unsuccessful dequeue attempts has exceeded max_retries or the message has expired. All messages in the exception queue are in the EXPIRED state.

The default is the exception queue associated with the queue table. If the exception queue specified does not exist at the time of the move, then the message is moved to the default exception queue associated with the queue table, and a warning is logged in the alert file. If the default exception queue is used, then the parameter returns a NULL value at dequeue time.

message_payload This can have different sub-elements based on the payload type of the destination queue/topic. The different payload types are described in the next section
AQXmlCommit This is an empty element—if specified, the user transaction is committed at the end of the request


See Also:

"Internet Integration and Internet Data Access Presentation" for an explanation of IDAP message payloads

The following examples show enqueue requests using different message and queue types.

Example 17-1 IDAP Enqueue Request: Sending an ADT Message to a Single-Consumer Queue

The queue QS.NEW_ORDER_QUE has a payload of type ORDER_TYP.

<?xml version="1.0"?>
   <Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <AQXmlSend xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <producer_options>
            <destination>QS.NEW_ORDERS_QUE</destination>
          </producer_options>

          <message_set>
            <message_count>1</message_count>        

            <message>
              <message_number>1</message_number>

              <message_header>
                <correlation>ORDER1</correlation>
                    <sender_id>
                        <agent_name>scott</agent_name>
                      </sender_id> 
              </message_header>

              <message_payload>   

               <ORDER_TYP>
                     <ORDERNO>100</ORDERNO>
                     <STATUS>NEW</STATUS>
                     <ORDERTYPE>URGENT</ORDERTYPE>
                     <ORDERREGION>EAST</ORDERREGION>
                     <CUSTOMER>
                        <CUSTNO>1001233</CUSTNO>
                        <CUSTID>MA1234555623212</CUSTID>
                        <NAME>AMERICAN EXPRESS</NAME>
                        <STREET>EXPRESS STREET</STREET>
                        <CITY>REDWOOD CITY</CITY>
                        <STATE>CA</STATE>
                        <ZIP>94065</ZIP>
                        <COUNTRY>USA</COUNTRY>
                     </CUSTOMER>
                     <PAYMENTMETHOD>CREDIT</PAYMENTMETHOD>
                     <ITEMS>
                        <ITEMS_ITEM>
                           <QUANTITY>10</QUANTITY>
                           <ITEM>
                              <TITLE>Perl</TITLE>
                              <AUTHORS>Randal</AUTHORS>
                              <ISBN>ISBN20200</ISBN>
                              <PRICE>19</PRICE>
                           </ITEM>
                           <SUBTOTAL>190</SUBTOTAL>
                        </ITEMS_ITEM>
                        <ITEMS_ITEM>
                           <QUANTITY>20</QUANTITY>
                           <ITEM>
                              <TITLE>XML</TITLE>
                              <AUTHORS>Micheal</AUTHORS>
                              <ISBN>ISBN20212</ISBN>
                              <PRICE>59</PRICE>
                           </ITEM>
                           <SUBTOTAL>590</SUBTOTAL>
                        </ITEMS_ITEM>
                     </ITEMS>
                     <CCNUMBER>NUMBER01</CCNUMBER>
                     <ORDER_DATE>2000-08-23 0:0:0</ORDER_DATE>
               </ORDER_TYP>
             </message_payload>
            </message>
          </message_set>
        </AQXmlSend>
      </Body>
</Envelope> 

Example 17-2 IDAP Enqueue Request: Publishing an ADT Message to a Multiconsumer Queue

The multiconsumer queue AQUSER.EMP_TOPIC has a payload of type EMP_TYP. EMP_TYP has the following structure:

CREATE OR REPLACE TYPE emp_typ AS object (
     empno NUMBER(4),
     ename VARCHAR2(10),
     job VARCHAR2(9),
     mgr NUMBER(4),
     hiredate DATE,
     sal   NUMBER(7,2),
     comm  NUMBER(7,2)
     deptno NUMBER(2));
 

A PUBLISH request has the following format:

<?xml version="1.0"?>
<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">

      <Body>
        <AQXmlPublish xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <producer_options>
            <destination>AQUSER.EMP_TOPIC</destination>
          </producer_options>

          <message_set>
            <message_count>1</message_count>        

            <message>
              <message_number>1</message_number>

              <message_header>
                 <correlation>NEWEMP</correlation>
                       <sender_id>
                          <agent_name>scott</agent_name>
                       </sender_id> 
              </message_header>

              <message_payload>   
                    <EMP_TYP>
                  <EMPNO>1111</EMPNO>
                  <ENAME>Mary</ENAME>
                      <MGR>5000</MGR>
                      <HIREDATE>1996-01-01 0:0:0</HIREDATE>
                <SAL>10000</SAL>
                <COMM>100.12</COMM>
                      <DEPTNO>60</DEPTNO>
                    </EMP_TYP>
             </message_payload>
            </message>
          </message_set>
        </AQXmlPublish>
      </Body>
</Envelope> 

Example 17-3 IDAP Enqueue Request: Sending a Message to a JMS Queue

The Java Message Service (JMS) queue AQUSER.JMS_TEXTQ has payload type JMS Text message (SYS.AQ$_JMS_TEXT_MESSAGE). The send request has the following format:

<?xml version="1.0"?>
<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>

        <AQXmlSend xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <producer_options>
            <destination>AQUSER.JMS_TEXTQ</destination>
          </producer_options>

          <message_set>
            <message_count>1</message_count>        

            <message>
              <message_number>1</message_number>

              <message_header>
                <correlation>text_msg</correlation>
                        <sender_id>
                                <agent_name>john</agent_name>
                        </sender_id>
              </message_header>

              <message_payload>   

                    <jms_text_message>        
                        <oracle_jms_properties>
                     <appid>AQProduct</appid>
                       <groupid>AQ</groupid>
                      </oracle_jms_properties>

                      <user_properties>
                        <property>
                          <name>Country</name>
                          <string_value>USA</string_value>
                        </property>
                        <property>
                           <name>State</name>
                          <string_value>California</string_value>
                        </property>
                       </user_properties>

                       <text_data>All things bright and beautiful</text_data>
               </jms_text_message>
             </message_payload>
            </message>
          </message_set>
                </AQXmlSend>
      </Body>
</Envelope> 

Example 17-4 IDAP Enqueue Request: Publishing a Message to a JMS Topic

The JMS topic AQUSER.JMS_MAP_TOPIC has payload type JMS Map message (SYS.AQ$_JMS_MAP_MESSAGE). The publish request has the following format:

<?xml version="1.0"?>

<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>

        <AQXmlPublish xmlns = "http://ns.oracle.com/AQ/schemas/access">

          <producer_options>
            <destination>AQUSER.JMS_MAP_TOPIC</destination>
          </producer_options>

          <message_set>
            <message_count>1</message_count>        

            <message>
              <message_number>1</message_number>

              <message_header>
                        <correlation>toyota</correlation>
                        <sender_id >
                                     <agent_name>john</agent_name>
                                  </sender_id>
                        <recipient_list>
                           <recipient>
                              <agent_name>scott</agent_name>
                           </recipient>
                           <recipient>
                              <agent_name>aquser</agent_name>
                           </recipient>
                           <recipient>
                              <agent_name>jmsuser</agent_name>
                           </recipient>
                        </recipient_list>         
              </message_header>

              <message_payload>   

                  <jms_map_message> 
                    <oracle_jms_properties>
                          <reply_to>
                                       <agent_name>oracle</agent_name>
                                    </reply_to>
                         <groupid>AQ</groupid>
                       </oracle_jms_properties>

                         <user_properties>
                         <property>
                           <name>Country</name>
                           <string_value>USA</string_value>
                         </property>
                         <property>
                           <name>State</name>
                           <string_value>California</string_value>
                         </property>
                        </user_properties>

                         <map_data>
                        <item>
                       <name>Car</name>
                         <string_value>Toyota</string_value>
                        </item>
                        <item>
                          <name>Color</name>
                          <string_value>Blue</string_value>
                      </item>
                        <item>
                          <name>Price</name>
                          <int_value>20000</int_value>
                        </item>
                      </map_data>
               </jms_map_message>
             </message_payload>
            </message>
          </message_set>
           </AQXmlPublish>
      </Body>
</Envelope> 

Example 17-5 IDAP Enqueue Request: Sending a Message to a Queue with a RAW Payload

The queue AQUSER.RAW_MSGQ has a payload of type RAW. The SEND request has the following format:

<?xml version="1.0"?>
   <Envelope  xmlns =  "http://schemas.xmlsoap.org/soap/envelope/">
   <Body> 
      <AQXmlSend xmlns = "http://ns.oracle.com/AQ/schemas/access">
        <producer_options>
          <destination>AQUSER.RAW_MSGQ</destination>
        </producer_options>
        <message_set>
          <message_count>1</message_count>  

          <message>
             <message_number>1</message_number>

                 <message_header>
                   <correlation>TKAXAS11</correlation>
                   <sender_id>
                      <agent_name>scott</agent_name>
                   </sender_id>   
                 </message_header>
                 <message_payload>
                    <RAW>426C6F622064617461202D20626C6F622064617461202D20626C6F62206461746120426C6F6
22064617461202D20626C6F622064617461202D20626C6F62206461746120426</RAW>
                 </message_payload>
               </message>
            </message_set>
          </AQXmlSend>
      </Body>
</Envelope>

Example 17-6 IDAP Enqueue Request: Sending/Publishing and Committing the Transaction

<?xml version="1.0"?>
<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">

      <Body>
        <AQXmlPublish xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <producer_options>
            <destination>AQUSER.EMP_TOPIC</destination>
          </producer_options>

          <message_set>
            <message_count>1</message_count>        

            <message>
              <message_number>1</message_number>

              <message_header>
                <correlation>NEWEMP</correlation>
                <sender_id>
                   <agent_name>scott</agent_name>
                </sender_id> 
              </message_header>

              <message_payload>   
                <EMP_TYP>
                  <EMPNO>1111</EMPNO>
                        <ENAME>Mary</ENAME>
                  <MGR>5000</MGR>
                        <HIREDATE>1996-01-01 0:0:0</HIREDATE>
                  <SAL>10000</SAL>
                  <COMM>100.12</COMM>
                        <DEPTNO>60</DEPTNO>
                     </EMP_TYP>
             </message_payload>
            </message>
          </message_set>

        <AQXmlCommit/>

        </AQXmlPublish>
      </Body>
</Envelope>

IDAP Client Requests for Dequeue

Client requests for dequeue use the AQXmlReceive method, which takes the arguments and argument attributes shown in Table 17-2. Required arguments are shown in bold.

Table 17-2 Client Requests for Dequeue—Arguments and Attributes for AQXmlReceive

Argument Attribute
consumer_options destination—specify the queue/topic from which messages are to be received. The destination element has an attribute lookup_type, which determines how the destination element value is interpreted
  • DATABASE (default)—destination is interpreted as schema.queue_name

  • LDAP—the LDAP server is used to resolve the destination

- consumer_name—Name of the consumer. Only those messages matching the consumer name are accessed. If a queue is not set up for multiple consumers, then this field should not be specified
- wait_time—the time (in seconds) to wait if there is currently no message available which matches the search criteria
- selector—criteria used to select the message, specified as one of:
  • correlation—the correlation identifier of the message to be dequeued.

  • message_id— the message identifier of the message to be dequeued

  • condition—dequeue message that satisfy this condition.

A condition is specified as a Boolean expression using syntax similar to the WHERE clause of a SQL query. This Boolean expression can include conditions on message properties, user data properties (object payloads only), and PL/SQL or SQL functions (as specified in the where clause of a SQL query). Message properties include priority, corrid and other columns in the queue table

To specify dequeue conditions on a message payload (object payload), use attributes of the object type in clauses. You must prefix each attribute with tab.user_data as a qualifier to indicate the specific column of the queue table that stores the payload. The deq_condition parameter cannot exceed 4000 characters.

- visibility
  • ON_COMMIT (default)—The dequeue is part of the current transaction. The operation is complete when the transaction commits.

  • IMMEDIATE—effects of the dequeue are visible immediately after the request is completed. The dequeue is not part of the current transaction. The operation constitutes a transaction on its own.

- dequeue_mode—Specifies the locking action associated with the dequeue. The dequeue_mode can be specified as one of:
  • REMOVE (default): Read the message and delete it. The message can be retained in the queue table based on the retention properties.

  • BROWSE: Read the message without acquiring any lock on the message. This is equivalent to a select statement.

  • LOCKED: Read and obtain a write lock on the message. The lock lasts for the duration of the transaction. This is equivalent to a select for update statement.

- navigation_mode—Specifies the position of the message that is retrieved. First, the position is determined. Second, the search criterion is applied. Finally, the message is retrieved. The navigation_mode can be specified as one of:
  • FIRST_MESSAGE: Retrieves the first message which is available and matches the search criteria. This resets the position to the beginning of the queue.

  • NEXT_MESSAGE (default): Retrieve the next message which is available and matches the search criteria. If the previous message belongs to a message group, then Oracle Streams AQ retrieves the next available message which matches the search criteria and belongs to the message group. This is the default.

  • NEXT_TRANSACTION: Skip the remainder of the current transaction group (if any) and retrieve the first message of the next transaction group. This option can only be used if message grouping is enabled for the current queue.

- transformation—the PL/SQL transformation to be invoked after the message is dequeued
AQXmlCommit This is an empty element—if specified, the user transaction is committed at the end of the request

The following examples show dequeue requests using different attributes of AQXmlReceive.

Example 17-7 IDAP Dequeue Request: Receiving Messages from a Single-Consumer Queue

Using the single-consumer queue QS.NEW_ORDERS_QUE, the receive request has the following format:

<?xml version="1.0"?>

<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <AQXmlReceive xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <consumer_options>
            <destination>QS.NEW_ORDERS_QUE</destination>
            <wait_time>0</wait_time>
          </consumer_options>
                </AQXmlReceive>
      </Body>
</Envelope> 

Example 17-8 IDAP Dequeue Request: Receiving Messages from a Multiconsumer Queue

Using the multiconsumer queue AQUSER.EMP_TOPIC with subscriber APP1, the receive request has the following format:

<?xml version="1.0"?>
<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <AQXmlReceive xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <consumer_options>
            <destination>AQUSER.EMP_TOPIC</destination>
            <consumer_name>APP1</consumer_name>
            <wait_time>0</wait_time>
            <navigation_mode>FIRST_MESSAGE</navigation_mode> 
          </consumer_options>
                </AQXmlReceive>
      </Body>
</Envelope> 

Example 17-9 IDAP Dequeue Request: Receiving Messages from a Specific Correlation ID

Using the single consumer queue QS.NEW_ORDERS_QUE, to receive messages with correlation ID NEW, the receive request has the following format:

<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <AQXmlReceive xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <consumer_options>
            <destination>QS.NEW_ORDERS_QUE</destination>
            <wait_time>0</wait_time>
            <selector>
                 <correlation>NEW</correlation>
            </selector>
          </consumer_options>
                </AQXmlReceive>
      </Body>
</Envelope> 

Example 17-10 IDAP Dequeue Request: Receiving Messages that Satisfy a Specific Condition

Using the multiconsumer queue AQUSER.EMP_TOPIC with subscriber APP1 and condition deptno=60, the receive request has the following format:

<?xml version="1.0"?>
<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <AQXmlReceive xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <consumer_options>
            <destination>AQUSER.EMP_TOPIC</destination>
            <consumer_name>APP1</consumer_name>
            <wait_time>0</wait_time>
            <selector>
                 <condition>tab.user_data.deptno=60</condition>
            </selector>
          </consumer_options>
                </AQXmlReceive>
      </Body>
</Envelope> 

Example 17-11 IDAP Dequeue Request: Receiving Messages and Committing

In the dequeue request examples, if you include AQXmlCommit at the end of the RECEIVE request, then the transaction is committed upon completion of the operation. In "IDAP Dequeue Request: Receiving Messages from a Multiconsumer Queue", the receive request can include the commit flag as follows:

<?xml version="1.0"?>

<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <AQXmlReceive xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <consumer_options>
            <destination>QS.NEW_ORDERS_QUE</destination>
            <wait_time>0</wait_time>
          </consumer_options>

              <AQXmlCommit/>

                </AQXmlReceive>
      </Body>
</Envelope>

Example 17-12 IDAP Dequeue Request: Browsing Messages

Messages are dequeued in REMOVE mode by default. To receive messages from QS.NEW_ORDERS_QUE in BROWSE mode, modify the receive request as follows:

<?xml version="1.0"?>

<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>
        <AQXmlReceive xmlns = "http://ns.oracle.com/AQ/schemas/access">
          <consumer_options>
            <destination>QS.NEW_ORDERS_QUE</destination>
            <wait_time>0</wait_time>
            <dequeue_mode>BROWSE</dequeue_mode>
          </consumer_options>
           </AQXmlReceive>
      </Body>
</Envelope> 

IDAP Client Requests for Registration

Client requests for registration use the AQXmlRegister method, which takes the arguments and argument attributes shown in Table 17-3. Required arguments are shown in bold.

Table 17-3 Client Registration—Arguments and Attributes for AQXmlRegister

Argument Attribute
register_options destination—specify the queue or topic on which notifications are registered. The destination element has an attribute lookup_type, which determines how the destination element value is interpreted
  • DATABASE (default)—destination is interpreted as schema.queue_name

  • LDAP—the LDAP server is used to resolve the destination

- consumer_name—the consumer name for multiconsumer queues or topics. For single consumer queues, this parameter must not be specified
- notify_url—where notification is sent when a message is enqueued. The form can be http://url or mailto://email address or plsql://pl/sql procedure.

Example 17-13 IDAP Register Request: Registering for Notification at an E-mail Address

To notify an e-mail address of messages enqueued for consumer APP1 in queue AQUSER.EMP_TOPIC, the register request has the following format:

<?xml version="1.0"?>
<Envelope xmlns= "http://schemas.xmlsoap.org/soap/envelope/">
      <Body>

        <AQXmlRegister xmlns = "http://ns.oracle.com/AQ/schemas/access">

          <register_options>
            <destination>AQUSER.EMP_TOPIC</destination>
            <consumer_name>APP1</consumer_name>
            <notify_url>mailto:app1@hotmail.com</notify_url>
          </register_options>

          <AQXmlCommit/>

                </AQXmlRegister>
      </Body>
</Envelope> 

IDAP Client Requests to Commit a Transaction

A request to commit all actions performed by the user in a session uses the AQXmlCommit method.

Example 17-14 IDAP Commit Request Example

A commit request has the following format.

<?xml version="1.0"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body>
      <AQXmlCommit xmlns="http://ns.oracle.com/AQ/schemas/access"/>
   </Body>
</Envelope>

IDAP Client Requests to Rollback a Transaction

A request to roll back all actions performed by the user in a session uses the AQXmlRollback method. Actions performed with IMMEDIATE visibility are not rolled back.

Example 17-15 IDAP Rollback Request Example

An IDAP client rollback request has the following format:

<?xml version="1.0"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body>
      <AQXmlRollback xmlns="http://ns.oracle.com/AQ/schemas/access"/>
   </Body>
</Envelope>

IDAP Server Response to Enqueue

The response to an enqueue request to a single-consumer queue uses the AQXmlSendResponse method. The components of the response are shown in Table 17-4.

Table 17-4 IDAP Server Response to an Enqueue to a Single-Consumer Queue (AQXmlSendResponse)

Response Attribute
status_response status_code—indicates success (0) or failure (-1)

error_code—Oracle code for the error

error_message—description of the error

send_result destination—where the message was sent

message_id—identifier for every message sent


Example 17-16 Server Request: Enqueuing a Single Message to a Single-Consumer Queue

The result of a SEND request to the single consumer queue QS.NEW_ORDERS_QUE has the following format:

<?xml version = '1.0'?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body>
      <AQXmlSendResponse xmlns="http://ns.oracle.com/AQ/schemas/access">
         <status_response>
            <status_code>0</status_code>
         </status_response>
         <send_result>
            <destination>QS.NEW_ORDERS_QUE</destination>
            <message_id>12341234123412341234</message_id>
         </send_result>
      </AQXmlSendResponse>
   </Body>
</Envelope>

The response to an enqueue request to a multiconsumer queue or topic uses the AQXmlPublishResponse method. The components of the response are shown in Table 17-5.

Table 17-5 IDAP Server Response to an Enqueue to a Multiconsumer Queue or Topic (AQXmlPublishResponse)

Response Attribute
status_response status_code—indicates success (0) or failure (-1)

error_code—Oracle code for the error

error_message—description of the error

publish_result destination—where the message was sent

message_id—identifier for every message sent


Example 17-17 IDAP Server Request: Enqueuing to a Multiconsumer Queue

The result of a SEND request to the multiconsumer queue AQUSER.EMP_TOPIC has the following format:

<?xml version = '1.0'?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body>
      <AQXmlPublishResponse xmlns="http://ns.oracle.com/AQ/schemas/access">
         <status_response>
            <status_code>0</status_code>
         </status_response>
         <publish_result>
            <destination>AQUSER.EMP_TOPIC</destination>
            <message_id>23434435435456546546546546</message_id>
         </publish_result>
      </AQXmlPublishResponse>
   </Body>
</Envelope>

IDAP Server Response to a Dequeue Request

The response to a dequeue request uses the AQXmlReceiveResponse method. The components of the response are shown in Table 17-6.

Table 17-6 IDAP Server Response to a Dequeue from a Queue or Topic (AQXmlReceiveResponse)

Response Attribute
status_response status_code—indicates success (0) or failure (-1)

error_code—Oracle code for the error

error_message—description of the error

receive_result destination—where the message was sent

message_set—the set of messages dequeued


Example 17-18 IDAP Dequeue Response: Receiving Messages from an ADT Queue (AQXmlReceiveResponse)

The result of a RECEIVE request on the queue AQUSER.EMP_TOPIC with a payload of type EMP_TYP has the following format:

<?xml version = '1.0'?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body>
      <AQXmlReceiveResponse xmlns="http://ns.oracle.com/AQ/schemas/access">
         <status_response>
            <status_code>0</status_code>
         </status_response>
         <receive_result>
            <destination>AQUSER.EMP_TOPIC</destination>
            <message_set>
               <message_count>1</message_count>
               <message>
                  <message_number>1</message_number>
                  <message_header>
                     <message_id>1234344545565667</message_id>
                     <correlation>TKAXAP10</correlation>
                     <priority>1</priority>
                     <delivery_count>0</delivery_count>
                     <sender_id>
                        <agent_name>scott</agent_name>
                     </sender_id>
                     <message_state>0</message_state>
                  </message_header>
                  <message_payload>
                    <EMP_TYP>
                        <EMPNO>1111</EMPNO>
                        <ENAME>Mary</ENAME>
                            <MGR>5000</MGR>
                            <HIREDATE>1996-01-01 0:0:0</HIREDATE>
                      <SAL>10000</SAL>
                      <COMM>100.12</COMM>
                            <DEPTNO>60</DEPTNO>
                          </EMP_TYP>
                 </message_payload>
               </message>
            </message_set>
         </receive_result>
      </AQXmlReceiveResponse>
   </Body>
</Envelope>

Example 17-19 IDAP Dequeue Response: Receiving Messages from a JMS Queue

The result of a RECEIVE request on a queue with a payload of type JMS Text message has the following format:

<?xml version = '1.0'?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
      <AQXmlReceiveResponse xmlns="http://ns.oracle.com/AQ/schemas/access">
         <status_response>
            <status_code>0</status_code>
         </status_response>
         <receive_result>
            <destination>AQUSER.JMS_TEXTQ</destination>
            <message_set>
               <message_count>1</message_count>
               <message>
                  <message_number>1</message_number>
                  <message_header>
                     <message_id>12233435454656567</message_id>
                     <correlation>TKAXAP01</correlation>
                     <delay>0</delay>
                     <priority>1</priority>
                     <message_state>0</message_state>
                     <sender_id>
                        <agent_name>scott</agent_name>
                     </sender_id>
                  </message_header>
                  <message_payload>
                     <jms_text_message>
                        <oracle_jms_properties>
                           <reply_to>
                              <agent_name>oracle</agent_name>
                              <address>redwoodshores</address>
                              <protocol>100</protocol>
                           </reply_to>
                           <userid>AQUSER</userid>
                           <appid>AQProduct</appid>
                           <groupid>AQ</groupid>
                           <timestamp>01-12-2000</timestamp>
                           <recv_timestamp>12-12-2000</recv_timestamp>
                        </oracle_jms_properties>
                        <user_properties>
                           <property>
                              <name>Country</name>
                              <string_value>USA</string_value>
                           </property>
                           <property>
                              <name>State</name>
                              <string_value>California</string_value>
                           </property>
                        </user_properties>
                        <text_data>All things bright and beautiful</text_data>
                     </jms_text_message>
                  </message_payload>
               </message>
            </message_set>
         </receive_result>
      </AQXmlReceiveResponse>
   </Body>
</Envelope>

IDAP Server Response to a Register Request

The response to a register request uses the AQXmlRegisterResponse method, which consists of status_response. (See Table 17-6 for a description of status_response.)

IDAP Commit Response

The response to a commit request uses the AQXmlCommitResponse method, which consists of status_response. (See Table 17-6 for a description of status_response.)

Example 17-20 IDAP Commit Response

The response to a commit request has the following format:

<?xml version = '1.0'?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body>
      <AQXmlCommitResponse xmlns="http://ns.oracle.com/AQ/schemas/access">
         <status_response>
            <status_code>0</status_code>
         </status_response>
      </AQXmlCommitResponse>
   </Body>
</Envelope>

IDAP Rollback Response

The response to a rollback request uses the AQXmlRollbackResponse method, which consists of status_response. (See Table 17-6 for a description of status_response.)

IDAP Notification

When an event for which a client has registered occurs, a notification is sent to the client at the URL specified in the REGISTER request. AQXmlNotification consists of:

  • notification_options, which has

    • destination—the destination queue/topic on which the event occurred

    • consumer_name—in case of multiconsumer queues/topics, this refers to the consumer name for which the event occurred

  • message_set—the set of message properties.

IDAP Response in Case of Error

In case of an error in any of the preceding requests, a FAULT is generated. The FAULT element consists of:

  • faultcode - error code for fault

  • faultstring - indicates a client error or a server error. A client error means that the request is not valid. Server error indicates that the Oracle Streams AQ servlet has not been set up correctly

  • detail, which consists of

    • status_response

Example 17-21 IDAP Response in Case of Error

A FAULT message has the following format:

<?xml version = '1.0'?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body>
      <Fault xmlns="http://schemas.xmlsoap.org/soap/envelope/">
         <faultcode>100</faultcode>
         <faultstring>Server Fault</faultstring>
         <detail>
            <status_response>
               <status_code>-1</status_code>
               <error_code>410</error_code>
               <error_message>JMS-410: XML SQL Excetpion 
ORA-24031: invalid value, OWNER_NAME should be non-NULL
ORA-06512: at "SYS.DBMS_AQJMS", line 177
ORA-06512: at line 1
</error_message>
            </status_response>
         </detail>
      </Fault>
   </Body>
</Envelope>

SOAP and Oracle Streams AQ XML Schemas

IDAP exposes the SOAP schema and the Oracle Streams AQ XML schema to the client. All documents sent are validated against these schemas:

SOAP Schema

The SOAP schema describes the structure of a document: envelope, header, and body.

<?xml version='1.0'?>
<!-- XML Schema for SOAP v 1.1 Envelope -->
<schema xmlns='http://www.w3.org/2001/XMLSchema'
        xmlns:tns='http://schemas.xmlsoap.org/soap/envelope/'
        targetNamespace='http://schemas.xmlsoap.org/soap/envelope/'>

  <!-- SOAP envelope, header and body -->

  <element name="Envelope" type="tns:Envelope"/>
  <complexType name='Envelope'>
   <sequence>
    <element ref='tns:Header' minOccurs='0'/>
    <element ref='tns:Body' minOccurs='1'/>
    <any minOccurs='0' maxOccurs='*'/>
   </sequence>
    <anyAttribute/>
  </complexType>

  <element name="Header" type="tns:Header"/>
  <complexType name='Header'>
   <sequence>
    <any minOccurs='0' maxOccurs='*'/>
   </sequence>
    <anyAttribute/>
  </complexType>

  <element name="Body" type="tns:Body"/>
  <complexType name='Body'>
   <sequence>
    <any minOccurs='0' maxOccurs='*'/>
   </sequence>
    <anyAttribute/>
  </complexType>

  <!-- Global Attributes.  The following attributes are intended 
       to be usable through qualified attribute names on any complex type
       referencing them.  -->
 
  <attribute name="mustUnderstand" type="tns:mutype" use="optional" value="0"/>
  </attribute>

  <simpleType  name="mutype">
     <restriction base="string">
          <enumeration value="0"/>
        <enumeration value="1"/>
     </restriction>
  </simpleType>

  <attribute name='actor' type='anyURI'/>
 
  <!-- 'encodingStyle' indicates any canonicalization conventions followed
       in the contents of the containing element.  For example, the value
       'http://schemas.xmlsoap.org/soap/encoding/' indicates 
       the pattern described in SOAP specification. -->

  <simpleType name='encodingStyle'>
    <list itemType='anyURI'/>
  </simpleType>
  <attributeGroup name='encodingStyle'>
    <attribute name='encodingStyle' type='tns:encodingStyle'/>
  </attributeGroup>

  <!-- SOAP fault reporting structure -->
  <complexType name='Fault' final='extension'>
   <sequence>
    <element name='faultcode' type='QName'/>
    <element name='faultstring' type='string'/>
    <element name='faultactor' type='anyURI' minOccurs='0'/>
    <element name='detail' type='tns:detail' minOccurs='0'/>
   </sequence>
  </complexType>

  <complexType name='detail'>
   <sequence>
    <any minOccurs='0' maxOccurs='*'/>
   </sequence>
    <anyAttribute/> 
  </complexType>

</schema>

IDAP Schema

The IDAP schema describes the contents of the IDAP body for Internet access to Oracle Streams AQ features.

<?xml version="1.0"?>

<!-- ****************** Oracle Streams AQ xml schema  ****************** -->

<schema xmlns = "http://www.w3.org/2001/XMLSchema"
        targetNamespace = "http://ns.oracle.com/AQ/schemas/access"
        xmlns:aq = "http://ns.oracle.com/AQ/schemas/access"
        xmlns:xsd = "http://www.w3.org/2001/XMLSchema">

<import namespace = "http://schemas.xmlsoap.org/soap/envelope/"
        schemaLocation = "soap_env.xsd" />



<!-- ****************** Oracle Streams AQ xml client operations  ****************** -->

   <element name="AQXmlSend">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:producer_options" minOccurs="1" maxOccurs="1" />
           <element ref="aq:message_set" minOccurs="1" maxOccurs="1"/>
           <element ref="aq:AQXmlCommit" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
    </element>

   <element name="AQXmlPublish">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:producer_options" minOccurs="1" maxOccurs="1" />
           <element ref="aq:message_set" minOccurs="1" maxOccurs="1"/>
           <element ref="aq:AQXmlCommit" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
    </element>


   <element name="AQXmlReceive">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:consumer_options" minOccurs="1" maxOccurs="1" />
           <element ref="aq:AQXmlCommit" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
   </element>


   <element name="AQXmlRegister">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:register_options" minOccurs="1" maxOccurs="1" />
           <element ref="aq:AQXmlCommit" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
   </element>

   <element name="AQXmlCommit">
      <complexType>
      </complexType>
   </element>

   <element name="AQXmlRollback">
      <complexType>
      </complexType>
   </element>

 

   <!-- ****************** Oracle Streams AQ xml server responses  ****************** -->

   <element name="AQXmlSendResponse">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:status_response" minOccurs="1" maxOccurs="1"/> 
           <element ref="aq:send_result" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
    </element>

   <element name="AQXmlPublishResponse">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:status_response" minOccurs="1" maxOccurs="1"/> 
           <element ref="aq:publish_result" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
    </element>


   <element name="AQXmlReceiveResponse">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:status_response" minOccurs="1" maxOccurs="1"/> 
           <element ref="aq:receive_result" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
    </element>


   <element name="AQXmlRegisterResponse">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:status_response" minOccurs="1" maxOccurs="1"/> 
        </sequence>
      </complexType>
    </element>

   <element name="AQXmlCommitResponse">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:status_response" minOccurs="1" maxOccurs="1"/> 
        </sequence>
      </complexType>
    </element>

   <element name="AQXmlRollbackResponse">
      <complexType mixed="true">
        <sequence>
           <element ref="aq:status_response" minOccurs="1" maxOccurs="1"/> 
        </sequence>
      </complexType>
    </element>

 
   <element name="destination">
     <complexType>
      <simpleContent>
        <extension base='string'>
          <attribute name="lookup_type" type="aq:dest_lookup_type" 
                   default="DATABASE"/>
        </extension>
     </simpleContent>
   </complexType>
   </element>             

   <!-- **** destination lookup type ******* -->
   <!-- lookup_type can be specified to either lookup LDAP or use  -->
   <simpleType name="dest_lookup_type">
    <restriction base="string">
      <enumeration value="DATABASE"/>
      <enumeration value="LDAP"/>
     </restriction>
    </simpleType>

   <!-- ****************** Producer Options ****************** -->
   <element name="producer_options">
      <complexType mixed="true">
        <sequence>
        <element ref="aq:destination" minOccurs="1" maxOccurs="1"/>       
        <element ref="aq:visibility" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:transformation" minOccurs="0" maxOccurs="1"/>
        </sequence>
      </complexType>
    </element>

   <!-- ****************** Consumer Options ****************** -->
   <element name="consumer_options">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:destination" minOccurs="1" maxOccurs="1"/> 
        <element ref="aq:consumer_name" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:wait_time" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:selector" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:batch_size" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:visibility" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:dequeue_mode" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:navigation_mode" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:transformation" minOccurs="0" maxOccurs="1"/>
        </sequence>
       </complexType>
    </element>


   <!-- ****************** Register Options ****************** -->
   <element name="register_options">
      <complexType mixed="true">
        <sequence>
        <element ref="aq:destination" minOccurs="1" maxOccurs="1"/> 
        <element ref="aq:consumer_name" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:notify_url" minOccurs="1" maxOccurs="1"/> 
        </sequence>
      </complexType>
    </element>

   <element name="recipient_list">
     <complexType mixed="true">
      <sequence>
        <element ref="aq:recipient" minOccurs="1" maxOccurs="*"/>
      </sequence>
     </complexType>
   </element>


   <!-- ****************** Message Set ************************* -->
   <element name="message_set">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:message_count" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:message" minOccurs="0" maxOccurs="*"/>
       </sequence>
      </complexType>
   </element>


   <!-- ****************** Message ************************* -->
   <element name="message">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:message_number" minOccurs="0" maxOccurs="1"/>    
        <element ref="aq:message_header" minOccurs="1" maxOccurs="1"/>
        <element ref="aq:message_payload" minOccurs="0" maxOccurs="1"/>
       </sequence>
      </complexType>
   </element>


   <!-- ****************** Message header ****************** -->
   <element name="message_header">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:message_id" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:correlation" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:delay" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:expiration" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:priority" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:delivery_count" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:sender_id" minOccurs="1" maxOccurs="1"/>
        <element ref="aq:recipient_list" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:message_state" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:exception_queue" minOccurs="0" maxOccurs="1"/> 
      </sequence> 
     </complexType>
    </element>


   <!-- ****************** Oracle JMS properties ****************** -->
   <element name="oracle_jms_properties">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:type" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:reply_to" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:userid" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:appid" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:groupid" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:group_sequence" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:timestamp" minOccurs="0" maxOccurs="1"/> 
        <element ref="aq:recv_timestamp" minOccurs="0" maxOccurs="1"/> 
       </sequence>
      </complexType>
    </element>


   <!-- ****************** Message payload ****************** -->
   <element name="message_payload">
     <complexType>
        <choice>
          <element ref="aq:raw" minOccurs="0" maxOccurs="1"/> 
          <element ref="aq:jms_text_message" minOccurs="0" maxOccurs="1"/> 
          <element ref="aq:jms_map_message" minOccurs="0" maxOccurs="1"/> 
          <element ref="aq:jms_bytes_message" minOccurs="0" maxOccurs="1"/> 
          <element ref="aq:jms_object_message" minOccurs="0" maxOccurs="1"/> 
          <any minOccurs="0" maxOccurs="*" processContents="skip"/>
        </choice>
     </complexType>
   </element>             


   <!-- ****************** User-defined properties ****************** -->
   <element name="user_properties">
      <complexType mixed="true">
        <sequence>
        <element ref="aq:property" minOccurs="0" maxOccurs="*"/> 
        </sequence>
      </complexType>
   </element>

   <!-- ****************** Property  ****************** -->
   <element name="property">
      <complexType mixed="true">
        <sequence>
          <element ref="aq:name" minOccurs="1" maxOccurs="1"/> 
          <choice>
            <element ref="aq:int_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:string_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:long_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:double_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:boolean_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:float_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:short_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:byte_value" minOccurs="1" maxOccurs="1"/> 
          </choice>
        </sequence>
      </complexType>
    </element>


   <!-- ****************** Status response ****************** -->
   <element name="status_response">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:acknowledge" minOccurs="0" maxOccurs="1"/>       
        <element ref="aq:status_code" minOccurs="0" maxOccurs="1"/>       
        <element ref="aq:error_code" minOccurs="0" maxOccurs="1"/>        
        <element ref="aq:error_message" minOccurs="0" maxOccurs="1"/>
       </sequence>
      </complexType>
   </element>


   <!-- ****************** Send result ****************** -->
   <element name="send_result">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:destination" minOccurs="1" maxOccurs="1"/>       
        <element ref="aq:message_id" minOccurs="0" maxOccurs="*"/>        
      </sequence>
      </complexType>
   </element>

   <!-- ****************** Publish result ****************** -->
   <element name="publish_result">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:destination" minOccurs="1" maxOccurs="1"/>       
        <element ref="aq:message_id" minOccurs="0" maxOccurs="*"/>        
       </sequence>
      </complexType>
   </element>


   <!-- ****************** Receive result ****************** -->
   <element name="receive_result">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:destination" minOccurs="1" maxOccurs="1"/>       
        <element ref="aq:message_set" minOccurs="0" maxOccurs="*"/>
       </sequence>        
      </complexType>
   </element>


   <!-- ****************** Notification *************************** -->
   <element name="notification_options">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:destination" minOccurs="1" maxOccurs="1"/>       
        <element ref="aq:consumer_name" minOccurs="1" maxOccurs="1"/> 
       </sequence>
      </complexType>
   </element>


   <element name="priority" type="integer"/>              
   <element name="expiration" type="integer"/>            
   <element name="consumer_name" type="string"/> 
   <element name="wait_time" type="integer"/>
   <element name="batch_size" type="integer"/>

   <element name="notify_url" type="string"/> 
   <element name="message_id" type="string"/> 
   <element name="message_state" type="string"/>


   <element name="message_number" type="integer"/>
   <element name="message_count" type="integer"/>

   <element name="correlation" type="string"/> 
   <element name="delay" type="integer"/> 
   <element name="delivery_count" type="integer"/> 
   <element name="exception_queue" type="string"/> 
   <element name="agent_alias" type="string"/>

   <element name="type" type="string"/> 
   <element name="userid" type="string"/> 
   <element name="appid" type="string"/> 
   <element name="groupid" type="string"/> 
   <element name="group_sequence" type="integer"/> 
   <element name="timestamp" type="date"/> 
   <element name="recv_timestamp" type="date"/> 

   <element name="recipient">
     <complexType>
       <choice>
         <sequence>
           <element ref="aq:agent_name" minOccurs="0" maxOccurs="1"/>
           <element ref="aq:address" minOccurs="0" maxOccurs="1"/>        
           <element ref="aq:protocol" minOccurs="0" maxOccurs="1"/> 
         </sequence>
         <element ref="aq:agent_alias" minOccurs="1" maxOccurs="1"/>
       </choice>
     </complexType>
   </element>             


   <element name="sender_id">
     <complexType>
       <choice>
         <sequence>
           <element ref="aq:agent_name" minOccurs="0" maxOccurs="1"/>
           <element ref="aq:address" minOccurs="0" maxOccurs="1"/>        
           <element ref="aq:protocol" minOccurs="0" maxOccurs="1"/> 
         </sequence>
         <element ref="aq:agent_alias" minOccurs="1" maxOccurs="1"/>
       </choice>
     </complexType>
   </element>             


   <element name="reply_to">
     <complexType>
       <choice>
         <sequence>
           <element ref="aq:agent_name" minOccurs="1" maxOccurs="1"/>
           <element ref="aq:address" minOccurs="0" maxOccurs="1"/>        
           <element ref="aq:protocol" minOccurs="0" maxOccurs="1"/> 
         </sequence>
         <element ref="aq:agent_alias" minOccurs="1" maxOccurs="1"/>
       </choice>
     </complexType>
   </element>             


   <element name="selector"> 
     <complexType>
        <choice>
          <element ref="aq:correlation" minOccurs="0" maxOccurs="1"/> 
          <element ref="aq:message_id" minOccurs="0" maxOccurs="1"/> 
          <element ref="aq:condition" minOccurs="0" maxOccurs="1"/> 
        </choice>
     </complexType>
   </element>


   <element name="condition" type="string"/>

   <element name="visibility">
    <simpleType>
     <restriction base="string">
      <enumeration value="ON_COMMIT"/>
      <enumeration value="IMMEDIATE"/>
     </restriction>
    </simpleType>
    </element>    

   <simpleType name="del_mode_type">
     <restriction base="string">
      <enumeration value="PERSISTENT"/>
      <enumeration value="NONPERSISTENT"/>
     </restriction>
    </simpleType>

   <element name="dequeue_mode"> 
   <simpleType>    
    <restriction base="string">
      <enumeration value="BROWSE"/>
      <enumeration value="LOCKED"/>
      <enumeration value="REMOVE"/>
      <enumeration value="REMOVE_NODATA"/>
    </restriction>
    </simpleType>
   </element>     

   <element name="navigation_mode"> 
   <simpleType>
    <restriction base="string">
      <enumeration value="FIRST_MESSAGE"/>
      <enumeration value="NEXT_MESSAGE"/>
      <enumeration value="NEXT_TRANSACTION"/>
    </restriction>
    </simpleType>
   </element>
 
   <element name="transformation" type="string"/> 

   <element name="acknowledge">
     <complexType>
     </complexType>
   </element>             
   <element name="status_code" type="string"/> 
   <element name="error_code" type="string"/> 
   <element name="error_message" type="string"/> 

   <element name="name" type="string"/> 
   <element name="int_value" type="integer"/> 
   <element name="string_value" type="string"/> 
   <element name="long_value" type="long"/> 
   <element name="double_value" type="double"/> 
   <element name="boolean_value" type="boolean"/> 
   <element name="float_value" type="float"/> 
   <element name="short_value" type="short"/> 
   <element name="byte_value" type="byte"/> 

   <element name="agent_name" type="string"/> 
   <element name="address" type="string"/> 
   <element name="protocol" type="integer"/> 


   <!-- ****************** RAW message *********************** -->
   <element name="raw" type="string"/> 


   <!-- ****************** JMS text message ****************** -->
   <element name="jms_text_message">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:oracle_jms_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:user_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:text_data" minOccurs="1" maxOccurs="1"/>
      </sequence>
      </complexType>
   </element>
        
   <element name="text_data" type="string"/> 


   <!-- ****************** JMS map message ****************** -->
   <element name="jms_map_message">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:oracle_jms_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:user_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:map_data" minOccurs="1" maxOccurs="1"/>
       </sequence>
      </complexType>
   </element>

   <!-- ****************** Map data ****************** -->
   <element name="map_data">
      <complexType mixed="true">
        <sequence>
        <element ref="aq:item" minOccurs="0" maxOccurs="*"/> 
        </sequence>
      </complexType>
   </element>

   <!-- ****************** Map Item  ****************** -->
   <element name="item">
      <complexType mixed="true">
        <sequence>
          <element ref="aq:name" minOccurs="1" maxOccurs="1"/> 
          <choice>
            <element ref="aq:int_value" minOccurs="1" maxOccurs="1"/> 
            <element ref="aq:string_value" minOccurs="1" maxOccurs="1"/>
            <element ref="aq:long_value" minOccurs="1" maxOccurs="1"/>
            <element ref="aq:double_value" minOccurs="1" maxOccurs="1"/>
            <element ref="aq:boolean_value" minOccurs="1" maxOccurs="1"/>
            <element ref="aq:float_value" minOccurs="1" maxOccurs="1"/>
            <element ref="aq:short_value" minOccurs="1" maxOccurs="1"/>
            <element ref="aq:byte_value" minOccurs="1" maxOccurs="1"/>
          </choice>
        </sequence>
      </complexType>
    </element>
        

   <!-- ****************** JMS bytes message ****************** -->
   <element name="jms_bytes_message">
      <complexType mixed="true">
       <sequence>
        <element ref="aq:oracle_jms_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:user_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:bytes_data" minOccurs="1" maxOccurs="1"/>
       </sequence>
      </complexType>
   </element>
        
   <element name="bytes_data" type="string"/> 


   <!-- ****************** JMS object message ****************** -->
   <element name="jms_object_message">
      <complexType mixed="true">
        <sequence>
        <element ref="aq:oracle_jms_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:user_properties" minOccurs="0" maxOccurs="1"/>
        <element ref="aq:ser_object_data" minOccurs="1" maxOccurs="1"/>
        </sequence>
      </complexType>
   </element>
        
   <element name="ser_object_data" type="string"/> 

</schema>

Deploying the Oracle Streams AQ XML Servlet

The Oracle Streams AQ XML servlet is a Java class that extends the oracle.AQ.xml.AQxmlServlet class. The AQxmlServlet class extends the javax.servlet.http.HttpServlet class.


Note:

Demos for the Oracle Streams AQ XML servlet can be found in $ORACLE_HOME/rdbms/demo/. Check the aqxmlREADME.txt file for details.

The Oracle Streams AQ XML Servlet accepts requests with Content-Type "text/xml" or application/x-www-form-urlencoded. When the Content-Type request is set to application/x-www-form-urlencoded, you must set the parameter name to aqxmldoc and the value must be the URL-encoded Oracle Streams AQ XML document.

Creating the Oracle Streams AQ XML Servlet Class

The Oracle Streams AQ servlet creates a JDBC Oracle Call Interface (OCI) connection pool to connect to the Oracle Database server. The init() method of the servlet must specify an AQxmlDataSource object that encapsulates the database connection parameters and the username and password. See the Oracle XML API Reference for information on the AQxmlDataSource class.

The user specified in the AQxmlDataSource is the Oracle Streams AQ servlet super-user. This user must have CREATE SESSION privilege and EXECUTE privilege on the DBMS_AQIN package.

Example 17-22 Creating Oracle Streams AQ XML Servlet Class

Create a user AQADM as the Oracle Streams AQ servlet super-user as follows:

connect sys/change_on_install as sysdba;
GRANT CONNECT, RESOURCE to aqadm IDENTIFIED BY aqadm;
grant create session to aqadm;
GRANT EXECUTE ON DBMS_AQJMS TO aqadm;

A sample servlet can be created using this super-user as follows:

import javax.servlet.*;
import javax.servlet.http.*;
import oracle.AQ.xml.*;

/**
 * This is a sample Oracle Streams AQ Servlet.
 */
public class AQTestServlet extends oracle.AQ.xml.AQxmlServlet
{ 

  /* The init method must be overloaded to specify the AQxmlDataSource */
  public void init()
  {
      AQxmlDataSource  db_drv = null;

      try
      {
        /* Create data source with username, password, sid, host, port */
        db_drv = new AQxmlDataSource("AQADM", "AQADM", "test_db", "sun-248", "5521");

        this.setAQDataSource(db_drv);
      }
      catch (Exception ex)
      {
          System.out.println("Exception in init: " + ex);
      }
}

The superclass oracle.AQ.xml.AQxmlServlet implements the doPost() and doGet() methods in javax.servlet.http.HttpServlet. The doPost() method handles incoming SOAP requests and performs the requested Oracle Streams AQ operations.


Note:

The example assumes that the Oracle Streams AQ servlet is installed in a Web server that implements Javasoft's Servlet2.2 specification (such as Tomcat 3.1). For a Web server that implements the Servlet 2.0 specification (such as Apache Jserv), you should extend the oracle.AQ.xml.AQxmlServlet20 class instead of the AQxmlServlet class and override the appropriate write() method.

Compiling the Oracle Streams AQ XML Servlet

The Oracle Streams AQ servlet can be deployed with any Web server or servlet-runner that implements Javasoft's Servlet2.0 or Servlet2.2 interfaces (for example, Apache Jserv or Tomcat).

Because the servlet uses JDBC OCI drivers to connect to the Oracle Database server, the Oracle Database client libraries must be installed on the computer hosting the servlet.

The LD_LIBRARY_PATH must contain $ORACLE_HOME/lib.

The servlet can be compiled using JDK 1.2.x, JDK 1.3.x or JDK 1.4.x libraries.

For JDK 1.4.x, the CLASSPATH must contain:

$ORACLE_HOME/jdbc/lib/classes12.jar
$ORACLE_HOME/jdbc/lib/ojdbc14.jar
$ORACLE_HOME/jdbc/lib/orai18n.jar
$ORACLE_HOME/jlib/jndi.jar
$ORACLE_HOME/jlib/jta.jar
$ORACLE_HOME/lib/servlet.jar
$ORACLE_HOME/lib/xmlparserv2.jar
$ORACLE_HOME/lib/xschema.jar
$ORACLE_HOME/lib/xsu12.jar
$ORACLE_HOME/rdbms/jlib/aqapi.jar
$ORACLE_HOME/rdbms/jlib/aqxml.jar
$ORACLE_HOME/rdbms/jlib/jmscommon.jar

For JDK 1.3.x, the CLASSPATH must contain:

$ORACLE_HOME/jdbc/lib/classes12.jar
$ORACLE_HOME/jdbc/lib/orai18n.jar
$ORACLE_HOME/jlib/jndi.jar
$ORACLE_HOME/jlib/jta.jar
$ORACLE_HOME/lib/servlet.jar
$ORACLE_HOME/lib/xmlparserv2.jar
$ORACLE_HOME/lib/xschema.jar
$ORACLE_HOME/lib/xsu12.jar
$ORACLE_HOME/rdbms/jlib/aqapi.jar
$ORACLE_HOME/rdbms/jlib/aqxml.jar
$ORACLE_HOME/rdbms/jlib/jmscommon.jar

For JDK 1.2.x, the CLASSPATH must contain:

$ORACLE_HOME/jdbc/lib/classes12.jar
$ORACLE_HOME/jdbc/lib/orai18n.jar
$ORACLE_HOME/jlib/jndi.jar
$ORACLE_HOME/jlib/jta.jar
$ORACLE_HOME/lib/xmlparserv2.jar
$ORACLE_HOME/lib/servlet.jar
$ORACLE_HOME/lib/xschema.jar
$ORACLE_HOME/lib/xsu12.jar
$ORACLE_HOME/rdbms/jlib/aqapi.jar
$ORACLE_HOME/rdbms/jlib/aqxml.jar
$ORACLE_HOME/rdbms/jlib/jmscommon.jar

After setting the CLASSPATH, compile the servlet using javac or any other Java compiler.


Note:

If you are using the Oracle Streams AQ XML Servlet or the Oracle Streams AQ JMS API with JDK1.2, versions 1.2.2_05a or higher, then you must turn off the JIT compiler. Set JAVA_COMPILER = none to avoid problems in multithreaded applications.

Configuring the Web server to Authenticate Users Sending POST Requests

After the servlet is installed, the Web server must be configured to authenticate all users that send POST requests to the Oracle Streams AQ servlet. The Oracle Streams AQ servlet allows only authenticated users to access the servlet. If the user is not authenticated, then an error is returned by the servlet.

The Web server can be configured in multiple ways to restrict access. Some of the common techniques are basic authentication (username/password) over SSL and client certificates. Consult your Web server documentation to see how you can restrict access to servlets.

Using HTTP

In the context of the Oracle Streams AQ servlet, the username that is used to connect to the Web server is known as the Oracle Streams AQ HTTP agent or Oracle Streams AQ Internet user.

Example 17-23 Restricting Access To Servlets in Apache

In Apache, the following can be used to restrict access (using basic authentication) to servlets installed under aqserv/servlet. In this example, all users sending POST requests to the servlet are authenticated using the users file in /apache/htdocs/userdb.

<Location /aqserv/servlet>
  <Limit POST>    
    AuthName "AQ restricted stuff"
    AuthType Basic      
    AuthUserFile /apache/htdocs/userdb/users
    require valid-user  
  </Limit>
</Location> 

Authorizing Users to Perform Operations with Oracle Streams AQ Servlet

After authenticating the users who connect to the Oracle Streams AQ servlet, you establish which operations the users are authorized to perform by doing the following:

  1. Register the Oracle Streams AQ agent for Internet access.

  2. Map the Oracle Streams AQ agent to one or more database users.

Registering the Oracle Streams AQ Agent

To register the Oracle Streams AQ agent for Internet access, use DBMS_AQADM.CREATE_AQ_AGENT. The CREATE_AQ_AGENT procedure takes an agent_name.

Example 17-24 Creating and Registering an Oracle Streams AQ Agent

Create an Oracle Streams AQ agent JOHN to access the Oracle Streams AQ servlet using HTTP.

DBMS_AQADM.CREATE_AQ_AGENT(agent_name => 'JOHN', enable_http => true);

The procedures ALTER_AQ_AGENT and DROP_AQ_AGENT for altering and dropping Oracle Streams AQ agents function similarly to CREATE_AQ_AGENT. These procedures are documented in the PL/SQL Packages and Types Reference.

Mapping the Oracle Streams AQ Agent to Database Users

To map an Oracle Streams AQ agent to one or more database users, use DBMS_AQADM.ENABLE_DB_ACCESS. With the ENABLE_DB_ACCESS procedure, you give an Oracle Streams AQ agent the privileges of a particular database user. This allows the agent to access all queues that are visible to the database users to which the agent is mapped.

Example 17-25 Mapping Oracle Streams AQ Agent to Database Users

Map the Oracle Streams AQ Internet agent JOHN to database users OE (Overseas Shipping) and CBADM (Customer Billing administrator).

DBMS_AQADM.ENABLE_DB_ACCESS(agent_name =>'JOHN', db_username => 'OE');
DBMS_AQADM.ENABLE_DB_ACCESS(agent_name =>'JOHN', db_username => 'CBADM');

Database Sessions

When the user sends a POST request to the servlet, the servlet parses the request to determine which queue/topic the user is trying to access. Accordingly, the Oracle Streams AQ servlet creates a database session as one of the database users (db_user) that maps to the Oracle Streams AQ agent. The db_user selected has privileges to access the queue specified in the request. For example:

Oracle Streams AQ agent JOHN sends an enqueue request to OE.OE_NEW_ORDERS_QUE. The servlet sees that JOHN can map to db_users OE and CBADM. Because OE.OE_NEW_ORDERS_QUE is in the OE schema, it does a CREATE SESSION as OE to perform the requested operation.

The Oracle Streams AQ servlet creates a connection pool to the Oracle Database server using the Oracle Streams AQ servlet super-user. This super-user creates sessions on behalf of db_users that the Oracle Streams AQ Internet agent maps to. Hence the super-user must have privileges to create proxy sessions for all the users specified in the ENABLE_DB_ACCESS call.

Example 17-26 Granting Connect to Oracle Streams AQ Servlet Super-User

The Oracle Streams AQ servlet super-user can be granted CONNECT THROUGH session privileges as follows:

connect sys/change_on_install as sysdba
rem grant super-user AQADM privileges to create proxy sessions as OE
alter user OE grant CONNECT THROUGH AQADM;

rem grant super-user AQADM privileges to create proxy sessions as CBADM
alter user CBADM grant CONNECT THROUGH AQADM;

If an Oracle Streams AQ Internet agent is mapped to more than one db_user, then all the db_users must have the FORCE ANY TRANSACTION privilege:

grant FORCE ANY TRANSACTION to OE; 
grant FORCE ANY TRANSACTION to CBADM; 

To disable the mapping between an agent and a database user, use DBMS_AQADM.DISABLE_DB_ACCESS.

The SYSTEM.AQ$INTERNET_USERS view lists Oracle Streams AQ agents, the protocols they are enabled for, and the mapping between Oracle Streams AQ agents and database users. Example entries in this view are shown in Table 17-7.

Table 17-7 SYSTEM_AQ$INTERNET_USERS View

agent_name db_username http_enabled
scott cbadmin YES
scott buyer YES
aqadmin OE YES
aqadmin seller YES
bookstore - NO

Using an LDAP Server with an Oracle Streams AQ XML Servlet

An LDAP server is required if:

  • The lookup_type destination attribute is specified as LDAP. In this case the destination name is resolved to a schema.queue_name using the LDAP server.

  • You use agent_alias instead of (agent_name, address, protocol). If an agent_alias is specified in a client request, then it is resolved to agent_name, address, protocol using the LDAP server.

Example 17-27 Specifying the LDAP Server Context for Oracle Streams AQ XML Servlet

The LDAP context must be specified by the setLDAPContext(DirContext) call, as follows:

public void init()
{
                      Hashtable env = new Hashtable(5, 0.75f);
                      AQxmlDataSource  db_drv = null;

      try
      {
           /* Create data source with username, password, sid, host, port */
           db_drv = new AQxmlDataSource("AQADM", "AQADM", "test_db",
                                        "sun-248", "5521");
           this.setAQDataSource(db_drv);

           env.put(Context.INITIAL_CONTEXT_FACTORY,                    "com.sun.jndi.ldap.LdapCtxFactory");
           env.put(Context.PROVIDER_URL, "ldap://yow:389");
           env.put(SEARCHBASE, "cn=server1,cn=dbservers,cn=wei");
           env.put(Context.SECURITY_AUTHENTICATION, "simple");
           env.put(Context.SECURITY_PRINCIPAL, "cn=orcladmin");
           env.put(Context.SECURITY_CREDENTIALS, "welcome");

                   DirContext inictx = new InitialDirContext(env);
                   String searchbase = (String)env.get("server_dn");
                   lctx = (DirContext)inictx.lookup(searchbase);

                   // Set up LDAP context
                   setLdapContext(lctx);

                   // Set the EMAIL server address (if any)
                   setEmailServerAddr("144.25.186.236");
      }
      catch (Exception ex)
      {
                 System.err.println("Servlet init exception: " +ex) ;
      }
 }

Using HTTP to Access the Oracle Streams AQ XML Servlet

The procedures for an Oracle Streams AQ client to make a request to the Oracle Streams AQ servlet using HTTP and for the Oracle Streams AQ servlet to process the request are as follows:


Oracle Streams AQ Client Request to the Oracle Streams AQ Servlet Using HTTP
  1. The client opens an HTTP(S) connection to the server.

    For example, https://aq.us.oracle.com:8000/aqserv/servlet/AQTestServlet

    This opens a connection to port 8000 on aq.us.oracle.com.

  2. The client logs in to the server by either:

    • HTTP basic authentication (with or without SSL)

    • SSL certificate-based client authentication

  3. The client constructs the XML message representing the Send, Publish, Receive or Register request.

    Example:

    <?xml version="1.0"?>
    <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
          <Body>
    
            <AQXmlSend  xmlns = "http://ns.oracle.com/AQ/schemas/access">
              <producer_options>
                <destination>OE.OE_NEW_ORDERS_QUE</destination>
              </producer_options>
    
              <message_set>
                <message_count>1</message_count>        
                <message>
                  <message_number>1</message_number>
                  <message_header>
                                            <correlation>XML_ADT_SINGLE_ENQ</correlation>
                            <sender_id>
                               <agent_name>john</agent_name>
                           </sender_id>
                  </message_header>
                  <message_payload>   
                  <ORDER_TYP>
                         <ORDERNO>100</ORDERNO>
                         <STATUS>NEW</STATUS>
                         <ORDERTYPE>NORMAL</ORDERTYPE>
                         <ORDERREGION>EAST</ORDERREGION>
                         <CUSTOMER>
                            <CUSTNO>1001233</CUSTNO>
                            <CUSTID>JOHN</CUSTID>
                            <NAME>AMERICAN EXPRESS</NAME>
                            <STREET>EXPRESS STREET</STREET>
                            <CITY>REDWOOD CITY</CITY>
                            <STATE>CA</STATE>
                            <ZIP>94065</ZIP>
                            <COUNTRY>USA</COUNTRY>
                         </CUSTOMER>
                         <PAYMENTMETHOD>CREDIT</PAYMENTMETHOD>
                         <ITEMS>
                            <ITEMS_ITEM>
                               <QUANTITY>10</QUANTITY>
                               <ITEM>
                                  <TITLE>Perl</TITLE>
                                  <AUTHORS>Randal</AUTHORS>
                                  <ISBN>ISBN20200</ISBN>
                                  <PRICE>19</PRICE>
                               </ITEM>
                               <SUBTOTAL>190</SUBTOTAL>
                            </ITEMS_ITEM>
                          </ITEMS>
                         <CCNUMBER>NUMBER01</CCNUMBER>
                         <ORDER_DATE>2000-08-23 0:0:0</ORDER_DATE>
                   </ORDER_TYP>
                 </message_payload>
                </message>
              </message_set>
              </AQXmlSend>
          </Body>
    </Envelope> 
    
    
  4. The client sends an HTTP POST to the servlet at the remote server.

    See the $ORACLE_HOME/demo directory for sample code of POST requests using HTTP.


Oracle Streams AQ Servlet Processes a Request Using HTTP
  1. The server accepts the client HTTP(S) connection.

  2. The server authenticates the user (Oracle Streams AQ agent) specified by the client.

  3. The server receives the POST request.

  4. The Oracle Streams AQ servlet is invoked.

    If this is the first request being serviced by this servlet, then the servlet is initialized—its init() method is invoked. The init () method creates a connection pool to the Oracle Database server using the AQxmlDataSource parameters (SID, host, port, Oracle Streams AQ servlet super-username, password) provided by the client.

  5. The servlet processes the message as follows:

    • If this is the first request from this client, then a new HTTP session is created. The XML message is parsed and its contents are validated. If a session ID is passed by the client in the HTTP headers, then this operation is performed in the context of that session. This is described in detail in the next section.

    • The servlet determines which object (queue and topic) the agent is trying to perform operations on:

      For example, in the client request (step 3 in "Oracle Streams AQ Client Request to the Oracle Streams AQ Servlet Using HTTP"), the agent JOHN is trying to access OE.OE_NEW_ORDERS_QUE.

    • The servlet looks through the list of database users that map to this Oracle Streams AQ agent (using the AQ$INTERNET_USERS view). If any one of these db_users has privileges to access the queue/topic specified in the request, then the Oracle Streams AQ servlet super-user creates a session on behalf of this db_user.

    • For example, where the agent JOHN is mapped to the database user OE using the DBMS_AQADM.ENABLE_DB_ACCESS call, the servlet creates a session for the agent JOHN with the privileges of database user OE.

    • A new database transaction is started if no transaction is active in the HTTP session. Subsequent requests in the session are part of the same transaction until an explicit COMMIT or ROLLBACK request is made.

    • The requested operation (SEND/PUBLISH/RECEIVE/REGISTER/COMMIT/ROLLBACK) is performed.

    • The response is formatted as an XML message and sent back the client.

      For example, the response for the preceding request can be as follows:

      <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
         <Body>
            <AQXmlSendResponse xmlns="http://ns.oracle.com/AQ/schemas/access">
               <status_response>
                  <status_code>0</status_code>
               </status_response>
               <send_result>
                  <destination>OE.OE_NEW_ORDERS_QUE</destination>
                  <message_id>12341234123412341234123412341234</message_id>
               </send_result>
            </AQXmlSendResponse>
         </Body>
      </Envelope>
      
      
    • The response also includes the session ID in the HTTP headers as a cookie. For example, Tomcat sends back session IDs as JSESSIONID=239454ds2343. If the operation does not commit the transaction, then the transaction remains active until an explicit commit/rollback call is received. The effects of the transaction are visible only after it is committed. If the transaction remains inactive for 120 seconds, then it is automatically terminated.

User Sessions and Transactions

After a client is authenticated and connects to the Oracle Streams AQ servlet, an HTTP session is created on behalf of the user. The first request in the session also implicitly starts a new database transaction. This transaction remains open until it is explicitly committed or terminated. The responses from the servlet includes the session ID in the HTTP headers as cookies.

If the client wishes to continue work in the same transaction, then it must include this HTTP header containing the session ID cookie in subsequent requests. This is automatically accomplished by most Web browsers. However, if you are using a Java or C client to post requests, then this must be accomplished programmatically. An example of a Java program used to post requests as part of the same session is given in $ORACLE_HOME/demo directory.

An explicit commit or rollback must be applied to end the transaction. The commit or rollback requests can also be included as part of other Oracle Streams AQ operations (Send, Publish, Receive, Register).

Each HTTP session has a default timeout of 120 seconds. If the user does not commit or rollback the transaction in 120 seconds after the last request that session, then the transaction is automatically terminated. This timeout can be modified in the init() method of the servlet by using setSessionMaxInactiveTime().

Using HTTP and HTTPS for Oracle Streams AQ Propagation

Using Oracle Streams AQ propagation in Oracle Database, you can propagate over HTTP and HTTPS (HTTP over SSL) instead of Oracle Net Services. HTTP, unlike Oracle Net Services, is easy to configure for firewalls.

High-Level Architecture

HTTP Oracle Streams AQ propagation uses the infrastructure for Internet access to Oracle Streams AQ as its basis. The background process doing propagation pushes messages to an Oracle Streams AQ Servlet that enqueues them into the destination database, as shown in Figure 17-2.

Figure 17-2 HTTP Oracle Streams AQ Propagation

Description of adque445.gif follows
Description of the illustration adque445.gif

Because HTTP propagation is different from Net Services in only the transport, most of the setup is the same as for Net Services propagation. The additional steps and differences are outlined in the following section.

Setting Up for HTTP Propagation

  1. The database link at the source database must be created differently. The connect string should specify the protocol as HTTP and specify the host and port of the Web server running the Oracle Streams AQ servlet. The username and password of the database link are used for authentication with the Web server/servlet runner.

  2. An Oracle Streams AQ servlet that connects to the destination database should be deployed.

  3. The source database must be enabled for running Java and XML.

The rest of the steps for propagation remain the same. The administrator must use DBMS_AQADM.SCHEDULE_PROPAGATION to start propagation. Propagation can be disabled with the DBMS_AQADM.DISABLE_PROPAGATION _SCHEDULE and re-enabled using DBMS_AQADM.ENABLE_PROPAGATION _SCHEDULE. The background processes, the job queue processes propagate the messages to the destination database.The job_queue_processes parameters must be at least 2 for propagation to take place.

Any application can be easily set up to use Oracle Streams AQ HTTP propagation without any change to the existing code, by following steps 1-3. Similarly an application using Oracle Streams AQ HTTP propagation can easily switch back to Net Services propagation just by re-creating the database link with a Net Services connection string, without any other changes.

Setting Up for Oracle Streams AQ Propagation over HTTP

  1. The source database must be created for running Java and XML.

  2. Create the database link with protocol as HTTP and the host and port of the Web server running the Oracle Streams AQ servlet, with the username and password for authentication with the Web Server/Servlet Runner.

    For example, if the Web Server is running on the computer webdest.oracle.com and listening for requests on port 8081, then the connect string of the database is as follows:

    (DESCRIPTION=(ADDRESS=(PROTOCOL=http)(HOST=webdest.oracle.com)(PORT=8081))
    
    

    If SSL is used, then specify HTTPS as the protocol in the connect string.

    The database link is created as follows:

    create public database link dba connect to john IDENTIFIED BY welcome using 
    '(DESCRIPTION=(ADDRESS=(PROTOCOL=http)(HOST=webdest.oracle.com)(PORT=8081)
    )';
    
    

    Where user john with password welcome is used to authenticate with the Web server and is also known by the term Oracle Streams AQ HTTP agent.


    Note:

    You cannot use net_service_name in tnsnames.ora with the database link. Doing so results in error ORA-12538.

  3. You can optionally set a proxy to use for all HTTP requests from the database. Use the UTL_HTTP.SET_PROXY procedure, as described in PL/SQL Packages and Types Reference.

  4. If HTTP over SSL is used, then a database wallet must be created for the source database. The wallet must be open for the duration of propagation. If HTTPS is used for propagation, then communication between the source database and the Oracle Streams AQ servlet is encrypted and the HTTPS server is authenticated with the source database. The database uses the database link username-password to authenticate itself with the HTTPS server.

  5. Deploy the Oracle Streams AQ Servlet.

    Create a class AQPropServlet that extends AQxmlServlet as described in [create the Oracle Streams AQ XML Servlet Class]. This servlet must connect to the destination database. The servlet must be deployed on the Web server in the path aqserv/servlet.

    In Oracle Database, the propagation servlet name and deployment path are fixed; that is, they must be AQPropServlet and the servlet, respectively.

  6. Make sure that the Oracle Streams AQ HTTP agent (John) is authorized to perform Oracle Streams AQ operations. This is accomplished at the destination database:

    1. Register the Oracle Streams AQ agent as follows:

      DBMS_AQADM.CREATE_AQ_AGENT(agent_name => 'John', enable_http => true);
      
      
    2. Map the Oracle Streams AQ agent to a database user as follows:

      DBMS_AQADM.ENABLE_DB_ACCESS(agent_name =>'John', db_username =>'CBADM')'
      
  7. Start propagation at the source site by calling:

    dbms_aqdm.schedule_propagation.
    DBMS_AQADM.SCHEDULE_PROPAGATION('src_queue', 'dba');
    

Customizing the Oracle Streams AQ Servlet

The oracle.AQ.xml.AQxmlServlet provides the API to set the connection pool size, session timeout, style sheet, and callbacks before and after Oracle Streams AQ operations.

Setting the Connection Pool Size

The Oracle Streams AQ data source is used the specify the back-end database to which the servlet connects to perform Oracle Streams AQ operations. It contains the database SID, host name, listener port and the username/password of the Oracle Streams AQ servlet super-user.

The data source is represented by the AQxmlDataSource class, which can be set using the setAQDataSource method in the servlet. See the Oracle XML API Reference for more information.

The Oracle Streams AQ data source creates a pool of connections to the database server. By default the maximum size of the pool is set to 50 and the minimum is set to 1. The number of connections in the pool grows and shrinks dynamically based on the number of incoming requests. If you want to change the maximum limit on the number of connections, then you must specify a cache size using the AQxmlDataSource.setCacheSize(size) method.

Setting the Session Timeout

After a client is authenticated and connects to the Oracle Streams AQ servlet, an HTTP session is created on behalf of the user. The first request in the session also implicitly starts a new database transaction. This transaction remains open until it is explicitly committed or terminated.

Each HTTP session has a default timeout of 120 seconds. If the user does not commit or rollback the transaction in 120 seconds after the last request for that session, then the transaction is automatically terminated. This timeout can be specified in the init() method of the servlet by using setSessionMaxInactiveTime() method.

Example 17-28 Initializing the Oracle Streams AQ Servlet for HTTP: Setting the HTTP Session Timeout

The servlet is initialized as follows:

public class AQTestServlet extends oracle.AQ.xml.AQxmlServlet
{ 
  /* The init method must be overloaded to specify the AQxmlDataSource */
  public void init()
  {
      AQxmlDataSource  db_drv = null;

      try
      {
        /* Create data source with username, password, sid, host, port */
        db_drv = new AQxmlDataSource("AQADM", "AQADM", 
                                     "test_db", "sun-248", "5521");

                /* Set the minimum cache size to 10 connections */
                                db_drv.getCacheSize(10);

        this.setAQDataSource(db_drv);

                /* Set the transaction timeout to 180 seconds */        
                this.setSessionMaxInactiveTime(180);
      }
      catch (Exception ex)
      {
          System.out.println("Exception in init: " + ex);
      }
}

Specifying the Style Sheet for All Responses from the Servlet

Oracle Streams AQ servlet sends back XML responses. The servlet administrator can specify a style sheet that is to be set for all responses sent back from this servlet. This can be accomplished by invoking the setStyleSheet(type,href)or the setStyleSheetProcessingInstr(proc_instr) in the init() method of the servlet.

Example 17-29 Specifying a Stylesheet for Use in AQ XML Servlet Responses

For example, to include the following style sheet instruction for all responses, do the following:

<?xml-stylesheet type="text/xsl" href="http://sun-248/stylesheets/bookOrder.xsl"?>

The servlet is initialized as follows:

public class AQTestServlet extends oracle.AQ.xml.AQxmlServlet
{ 
  /* The init method must be overloaded to specify the AQxmlDataSource */
  public void init()
  {
      AQxmlDataSource  db_drv = null;

      try
      {
        /* Create data source with username, password, sid, host, port */
        db_drv = new AQxmlDataSource("AQADM", "AQADM", 
                                     "test_db", "sun-248", "5521");

        this.setAQDataSource(db_drv);

                /* Set the bookOrder.xsl style sheet for all responses */
        setStyleSheet("text/xsl", "http://sun-248:8000/stylesheets/bookOrder.xsl");
      }
      catch (Exception ex)
      {
          System.out.println("Exception in init: " + ex);
      }
}

Callbacks Before and After Oracle Streams AQ Operations

Using the Oracle Streams AQ servlet, you can register callbacks that are invoked before and after Oracle Streams AQ operations are performed. This allows users to perform Oracle Streams AQ operations and other operations in the same transaction.

To receive callbacks, users register an object that implements the oracle.AQ.xml.AQxmlCallback interface.

Example 17-30 Registering Callbacks Invoked Before and After Performing Oracle Streams AQ Operations

The AQxmlCallback interface has the following methods:

public interface AQxmlCallback
{

  /** Callback invoked before any Oracle Streams AQ operations are performed by 
  the servlet */
  public void beforeAQOperation(HttpServletRequest request, 
                                HttpServletResponse response, 
                                AQxmlCallbackContext ctx);

  /** Callback invoked after any Oracle Streams AQ operations are performed by 
  the servlet */
  public void afterAQOperation(HttpServletRequest request, 
                               HttpServletResponse response, 
                               AQxmlCallbackContext ctx);
}

The callbacks are passed in the HTTP request and response streams and an AQxmlCallbackContext object. The object has the following methods:

  • The java.sql.Connection getDBConnection() method gives a handle to the database connection that is used by the servlet for performing Oracle Streams AQ operations. Users can perform other SQL operations in the callback functions using this connection object.

  • You cannot call close(), commit(), or rollback() methods on this connection object.

  • org.w3c.org.Document parseRequestStream() gives a DOM document representing the parsed request stream.

  • The void setStyleSheet(String type,String href)method allows the user to set the style sheet for a particular call. So instead of specifying a single style sheet for all responses from this servlet, users can set style sheets for specific responses.

    The style sheet specified in the callback overrides the style sheet (if any) specified for the servlet in the init() method

Example 17-31 Inserting a Row in the EMP Table by Creating a Callback Class and Associating it with a Servlet

Before any Oracle Streams AQ operation in the servlet, you want to insert a row in the EMP table. Do this by creating a callback class and associating it with a particular servlet as follows:

import javax.servlet.*;
import javax.servlet.http.*;
import oracle.AQ.xml.*;
import java.sql.*;
import javax.jms.*;

/**
 * This is a sample Oracle Streams AQ Servlet callback 
 */
public class TestCallback implements oracle.AQ.xml.AQxmlCallback
{ 

  /** Callback invoked before any Oracle Streams AQ operations are performed by 
  the servlet */
  public void beforeAQOperation(HttpServletRequest request, 
                                HttpServletResponse response, 
                                AQxmlCallbackContext ctx)
  {
      Connection conn = null;
      System.out.println("Entering BeforeAQ Callback ...");

      try
      {
            // Get the connection object from the callback context
            conn = ctx.getDBConnection();

            // Insert value in the EMP table
            PreparedStatement pstmt = conn.prepareStatement (
               "insert into EMP (EMPNO, ENAME) values (100, 'HARRY')");
            pstmt.execute ();
            pstmt.close();
      }
      catch (Exception ex)
      {
          System.out.println("Exception ex: " + ex);
      } 
  }

  /** Callback invoked after any Oracle Streams AQ operations are performed by 
  the servlet */
  public void afterAQOperation(HttpServletRequest request,
                               HttpServletResponse response, 
                               AQxmlCallbackContext ctx)
  {
      System.out.println("Entering afterAQ Callback ...");

      try
      {
         // Set style sheet for response
         ctx.setStyleSheetProcessingInstr(
             "type='text/xsl href='http://sun-248/AQ/xslt23.html'");
      }
      catch (Exception aq_ex)
      {
          System.out.println("Exception: " + ex);
      }
  }
}
 
/* Sample Oracle Streams AQ servlet - using user-defined callbacks */ 
public class AQTestServlet extends oracle.AQ.xml.AQxmlServlet
{ 
  /* The init method must be overloaded to specify the AQxmlDataSource */
  public void init()
  {
      AQxmlDataSource  db_drv = null;
      AQxmlCallback    serv_cbk  = new TestCallback();

      try
      {
        /* Create data source with username, password, sid, host, port */
        db_drv = new AQxmlDataSource("AQADM", "AQADM", "test_db", "sun-248", 
             "5521");

        this.setAQDataSource(db_drv);

        /* Set Callback */
        setUserCallback(serv_cbk);
      }
      catch (Exception ex)
      {
          System.out.println("Exception in init: " + ex);
      }
}

Frequently Asked Questions: Using Oracle Streams AQ and the Internet

The following frequently asked questions cover using Oracle Streams AQ and the Internet and Oracle Internet Directory.

Internet Access Questions


What is IDAP?

IDAP is Internet Data Access Presentation. IDAP defines the message structure for the body of a SOAP request. An IDAP message encapsulates the Oracle Streams AQ request and response in XML. IDAP is used to perform Oracle Streams AQ operations such as enqueue, dequeue, send notifications, register for notifications, and propagation over the Internet standard transports—HTTP(s) and e-mail. In addition, IDAP encapsulates transactions, security, transformation, and the character set ID for requests.


Which Web servers are supported for Oracle Streams AQ Internet access functionality? Must I use Apache or can I use any Web server? Which servlet engines are supported for Oracle Streams AQ Internet access? Can I use Tomcat?

Internet access functionality for Oracle Streams AQ is supported on Apache. This feature is certified to work with Apache, along with the Tomcat or Jserv servlet execution engines. However, the code does not prevent the servlet from working with other Web server and servlet execution engines that support Java Servlet 2.0 or higher interfaces.


How does an Internet agent tie to an Oracle Streams AQ agent stored in Oracle Internet Directory?

You can create an alias to an Oracle Streams AQ agent in Oracle Internet Directory. You can use these Oracle Streams AQ agent aliases in the IDAP document sent over the Internet to perform Oracle Streams AQ operations. Using aliases prevents exposing the internal name of the Oracle Streams AQ agent.


Can I use my own authentication framework for authentication?

Yes, you can use your own authentication framework for authentication. HTTP POST requests to the Oracle Streams AQ Servlet for Oracle Streams AQ operations must be authenticated by the Web server. For example, in Apache, the following can be used to restrict access (using basic authentication) to servlets installed under aqserv/servlet. In this example, all users sending POST requests to the servlet are authenticated using the users file in /apache/htdocs/userdb.

<Location /aqserv/servlet>
<Limit POST>
AuthName "Restrict AQ Servlet Access"
AuthType Basic
AuthUserFile /apache/htdocs/userdb/users
require valid-user
</Limit>
</Location>

Oracle Internet Directory Questions


Which events can be registered in Oracle Internet Directory?

All types of events—system events, user events, and notifications on queues—can be registered with Oracle Internet Directory. System events are database startup, database shutdown, and system error events. User events include user log on and user log off, DDL statements (create, drop, alter), and DML statement triggers. Notifications on queues include OCI notifications, PL/SQL notifications, and e-mail notifications.


How do I use agent information stored in an Oracle Internet Directory?

You can create aliases for an Oracle Streams AQ agent in Oracle Internet Directory. These aliases can be specified while performing Oracle Streams AQ operations-enqueue, dequeue, and notifications. This is specifically useful while performing Oracle Streams AQ operations over the Internet when you do not want to expose an internal agent name. An alias can be used in an Oracle Streams AQ operation (IDAP request).