Oracle9i Application Developer's Guide - Advanced Queuing Release 2 (9.2) Part Number A96587-01 |
|
You can access AQ over the Internet by using Simple Object Access Protocol (SOAP). Internet Data Access Presentation (IDAP) is the SOAP specification for AQ operations. IDAP defines XML message structure for the body of the SOAP request. An IDAP-structured message is transmitted over the Internet using transport protocols such as HTTP or SMTP.
This chapter discusses the following topics:
Figure 17-1 shows the architecture for performing AQ operations over HTTP. The major components are:
The AQ client program sends XML messages (conforming to IDAP) to the AQ servlet. Any HTTP client, for example Web browsers, can be used. The Web server/ServletRunner hosting the AQ servlet interprets the incoming XML messages. Examples include Apache/Jserv or Tomcat. The AQ servlet connects to the Oracle database server and performs operations on the users' queues.
See "Using HTTP to Access the AQ XML Servlet" and "Using HTTP and HTTPS for Advanced Queuing Propagation" for details.
Figure 17-2 shows additional components in the architecture for sending AQ messages over SMTP:
The e-mail server verifies client signatures using certificates stored in LDAP and then routes the request to the AQ servlet.
See "Using SMTP to Access the AQ Servlet" for more details.
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:
http://schemas.xmlsoap.org/soap/envelope/
SOAP structures a message request or response as follows:
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 may 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.
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, 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 AQ operations, the SOAP body must contain an AQ XML document. The AQ XML document has the namespace http://ns.oracle.com/AQ/schemas/access
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.
In the case of SMTP (e-mail), the method invocation can be done by the filter interface of the e-mail server, which invokes a Java method with the e-mail-message-body as argument. This results in remote invocation of the POST
method on the AQ servlet. The response is e-mailed directly to the recipient specified in the reply of the message. The response header can contain SMTP-protocol-related headers also.
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.
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:
SOAP:Body
element. This request can be one of the AQ XML client requests described in the next section.At the receiving site, a request can have one of the following outcomes:
In (a), the HTTP infrastructure passes the headers and body to the SOAP infrastructure. In (b), the result is an HTTP response containing an HTTP error in the status field and no XML body. In (c), the result of the method request consists of a response or error. In (d), the result of the method is an error that prevented the dispatching infrastructure on the receiving side from successful completion. In (c) and (d), additional message headers may for extensibility again be present in the results of the 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 will never contain both a result and an error.
The body of a SOAP message is an IDAP message. This XML document has the namespace http://ns.oracle.com/AQ/schemas/access
. This body represents:
Client requests for enqueue--SEND
and PUBLISH
requests--use the following methods:
AQXmlSend
--to enqueue to a single-consumer queueAQXmlPublish
--to enqueue to multiconsumer queues/topicsAQXmlSend
and AQXmlPublish
take the arguments and argument attributes shown in Table 17-1. Required arguments are shown in bold.
AQ supports messages of the following types:
All these types of queues can be accessed using SOAP. If the queue holds messages in RAW, Oracle object, or JMS format, XML payloads are transformed to the appropriate internal format during enqueue and stored in the queue. During dequeue, when messages are obtained from queues containing messages in any of the preceding formats, they are converted to XML before being sent to the client.
The message payload type depends on the type of the queue on which the operation is being performed. A discussion of the queue types follows:
The contents of RAW queues are raw bytes. The user must supply the hex representation of the message payload in the XML message. For example, <raw>023f4523</raw>
.
For ADT queues that are not JMS queues (that is, they are not type AQ$_JMS_*
), the type of the payload depends on the type specified while creating the queue table that holds the queue. The XML specified here must map to the SQL type of the payload for the queue table.
See Also:
Oracle9i XML Database Developer's Guide - Oracle XML DB for details on mapping SQL types to XML |
Assume the queue is defined to be of type EMP_TYP
, which 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));
The corresponding XML representation is:
<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>
For queues with JMS types (that is, those with payloads of type AQ$_JMS_*
), there are four different XML elements, depending on the JMS type. IDAP supports queues/topics with the following JMS types: TextMessage, MapMessage, BytesMessage and ObjectMessage. JMS queues with payload type StreamMessage are not supported through IDAP.
The JMS types and XML components are shown in Table 17-2. The distinct XML element for each JMS type is shown in its respective column.
Required elements are shown in bold in Table 17-2.
All JMS messages consist of the following common elements:
oracle_jms_properties
, which consists of
type
--type of the messagereply_to
--consists of an agent_name
, address
, and protocol
userid
--supplied by AQ; client cannot specifyappid
--application identifiergroupid
--group identifiergroup_sequence
--sequence within the group identified by group_id
timestamp
--the time the message was sent, which cannot be specified during enqueue. It is automatically populated in a message that is dequeued.recv_timestamp
--the time the message was receiveduser_properties
--in addition to the preceding predefined properties, users can also specify their own message properties as name-value pairs. The user_properties
consists of a list of property elements. Each property is a name-value pair consisting of the following:
name
--property nameint_value
--integer property value or
string_value
--string property value or
long_value
--long property value or
double_value
--double property value or
boolean_value
--boolean property value or
float_value
-- float property value or
short_value
--short property value or
byte_value
--byte property value or
The following examples show enqueue requests using the different message and queue types.
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>
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>
The 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>
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>
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>
<?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>
Client requests for dequeue use the AQXmlReceive
method, which takes the arguments and argument attributes shown in Table 17-3. Required arguments are shown in bold.
The following examples show dequeue requests using different attributes of AQXmlReceive
.
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>
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>
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>
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>
In the dequeue request examples, if you include AQXmlCommit
at the end of the RECEIVE
request, the transaction is committed upon completion of the operation. In "Dequeue Request Example--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>
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>
Client requests for registration use the AQXmlRegister method, which takes the arguments and argument attributes shown in Table 17-4. Required arguments are shown in bold.
.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>
A request to commit all actions performed by the user in a session uses the AQXmlCommit
method.
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>
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.
A 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>
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-5.
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-6.
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>
The response to a dequeue request uses the AQXmlReceiveResponse
method. The components of the response are shown in Table 17-7.
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>
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>
The response to a register request uses the AQXmlRegisterResponse
method, which consists of status_response
. (See Table 17-7 for a description of status_response
.)
The response to a commit request uses the AQXmlCommitResponse method, which consists of status_response
. (See Table 17-7 for a description of status_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>
The response to a rollback request uses the AQXmlRollbackResponse
method, which consists of status_response
. (See Table 17-7 for a description of status_response
.)
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:
In case of an error in any of the preceding requests, a FAULT
is generated. The FAULT
element consists of:
faultcode
- error code for faultfaultstring
- indicates a client error or a server error. A client error means that the request is not valid. Server error indicates that the AQ servlet has not been set up correctlydetail
, which consists of
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>
IDAP exposes the SOAP schema and the AQ XML schema to the client. All documents sent are validated against these schemas:
http://schemas.xmlsoap.org/soap/envelope/
http://ns.oracle.com/AQ/schemas/access
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 via 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>
The IDAP schema describes the contents of the IDAP body for Internet access to AQ features.
<?xml version="1.0"?> <!-- ****************** 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" /> <!-- ****************** 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> <!-- ****************** 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>
The 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 AQ XML servlet can be found in |
The 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 AQ XML document.
The AQ servlet creates a JDBC OCI connection pool to connect to the Oracle9i 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 Oracle9i Supplied Java Packages Reference for information on the AQxmlDataSource
class.
The user specified in the AQxmlDataSource is the AQ servlet super-user. This user must have CREATE SESSION
privilege and EXECUTE
privilege on the DBMS_AQIN
package.
Create a user AQADM
as the AQ servlet superuser 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 superuser as follows:
import javax.servlet.*; import javax.servlet.http.*; import oracle.AQ.xml.*; /** * This is a sample 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 AQ operations.
The 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). Note the following considerations:
The LD_LIBRARY_PATH
must contain $ORACLE_HOME/lib
CLASSPATH
must contain:
$ORACLE_HOME/jdbc/lib/classes111.zip $ORACLE_HOME/jdbc/lib/jta.zip $ORACLE_HOME/jdbc/lib/nls_charset11.zip $ORACLE_HOME/jdbc/lib/jndi.zip $ORACLE_HOME/lib/lclasses11.zip $ORACLE_HOME/lib/xmlparserv2.jar $ORACLE_HOME/lib/xschema.jar $ORACLE HOME/rdbms/jlib/aqapi11.jar $ORACLE_HOME/rdbms/jlib/jmscommon.jar $ORACLE_HOME/rdbms/jlib/aqxml.jar $ORACLE_HOME/rdbms/jlib/xsu111.jar $ORACLE_HOME/jis/lib/servlet.jar
CLASSPATH
must contain:
$ORACLE_HOME/jdbc/lib/classes12.zip $ORACLE_HOME/jdbc/lib/jta.zip $ORACLE_HOME/jdbc/lib/nls_charset12.zip $ORACLE_HOME/jdbc/lib/jndi.zip $ORACLE_HOME/lib/lclasses12.zip $ORACLE_HOME/lib/xmlparserv2.jar $ORACLE_HOME/lib/xschema.jar $ORACLE_HOME/rdbms/jlib/aqapi.jar $ORACLE_HOME/rdbms/jlib/jmscommon.jar $ORACLE_HOME/rdbms/jlib/aqxml.jar $ORACLE_HOME/rdbms/jlib/xsu12.jar $ORACLE_HOME/jis/lib/servlet.jar
CLASSPATH
, compile the servlet using javac
or any other Java compiler.
After the servlet is installed, the Web server must be configured to authenticate all users that send POST
requests to the AQ servlet. The AQ servlet allows only authenticated users to access the servlet. If the user is not authenticated, 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.
In the context of the AQ servlet, the user name that is used to connect to the Web server is known as the AQ HTTP agent or AQ Internet user.
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>
After authenticating the users who connect to the AQ servlet, you establish which operations the users are authorized to perform by doing the following:
To register the AQ agent for Internet access, use DBMS_AQADM.CREATE_AQ_AGENT
. The CREATE_AQ_AGENT
procedure takes an agent_name.
You specify which protocols the user can use to access the servlet--HTTP, SMTP, or both. For agents accessing the AQ servlet using SMTP, an LDAP certificate_location
must also be specified. See "Setup for Receiving AQ XML Requests Using SMTP (E-mail)" for more information.
Create an AQ agent JOHN
to access the 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 AQ agents function similarly to CREATE_AQ_AGENT
. These procedures are documented in the Oracle9i Supplied PL/SQL Packages and Types Reference.
To map an AQ agent to one or more database users, use DBMS_AQADM.ENABLE_DB_ACCESS
. With the ENABLE_DB_ACCESS
procedure, you give an 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.
Map the 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');
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 AQ servlet creates a database session as one of the database users (db_user
) t
hat maps to the AQ agent. The db_user
selected has privileges to access the queue specified in the request.
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
. Since OE.OE_NEW_ORDERS_QUE
is in the OE schema, it does a CREATE SESSION
as OE to perform the requested operation.
The AQ servlet creates a connection pool to the Oracle server using the AQ servlet super-user. This super-user
creates sessions on behalf of db_users
that the 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. See "Creating the AQ XML Servlet Class" for how to create the AQ servlet super-user.
The AQ servlet super-user can be granted CREATE
PROXY
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 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 AQ agents, the protocols they are enabled for, and the mapping between AQ agents and database users. Example entries in this view are shown in Table 17-8.
agent_name | db_username | http_enabled | smtp_enabled |
---|---|---|---|
scott |
cbadmin |
YES |
NO |
scott |
buyer |
YES |
NO |
aqadmin |
OE |
YES |
YES |
aqadmin |
seller |
YES |
YES |
bookstore |
- |
NO |
YES |
An LDAP server is required if:
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.agent_alias
instead of (agent_name, address, protocol)
. If an agent_alias
is specified in a client request, it is resolved to agent_name, address, protocol
using the LDAP server.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) ; } }
You must set up the database, Web server, LDAP server, and e-mail server to receive AQ XML requests using SMTP.
Database and LDAP Server Setup
To store AQ agents in the LDAP server, the database must be registered to the LDAP server using the Database Configuration Assistant (DBCA), and the value of GLOBAL_TOPIC_ENABLED
must be set to TRUE
(default is FALSE
; reset using alter system set global_topic_enabled=TRUE
).
To create AQ agents that can access the servlet using SMTP, use the DBMS_AQADM.CREATE_AQ_AGENT
procedure.
Create an AQ agent for the appl
application to access the AQ servlet using SMTP and the digital certificate of the application owner, Kurt:
DBMS_AQADM.CREATE_AQ_AGENT( agent_name => 'appl', enable_http => true, enable_smtp => true, certificate_location => 'cn=kurt,cn=acme,cn=com');
The certificate_location
parameter is required to authenticate the appl
application when a message is received.
ORACLE_SMTP_AGENT
on the Web server that is allowed to access the AQ servlet.
The Oracle e-mail server will connect to the servlet using user ORACLE_SMTP_AGENT
.
Use setEmailServerHost(hostname)
or setEmailServerAddr(ip_address)
in the AQxmlServlet to do this.
Example: Specify the e-mail server host as follows:
setEmailServerAddr("144.25.186.236"); or setEmailServerHost("email-srv.us.oracle.com");
The LDAP server is used to retrieve certificates for the AQ agent and verify the signature in the incoming message.
Internet access to AQ using SMTP requires Oracle Email Server 5.5. Do the following:
DBMS_AQST
is installed on the e-mail server.The following information is required:
'aqdb1'
;'welcome'
'acme.com'
'aqdb1@acme.com'
'aqdb1'
http://aq-sun.us.oracle.com:8000/aqserv/servlet/AQTestServlet
ORACLE_SMTP_AGENT
; password is established in "Web Server Setup").host=ldaphost
, port=389.
'cn=aqdb1, cn=oraclecontext,cn=acme,cn=com'
.dbms_aqst
:
declare status binary_integer; begin status := dbms_aqst.register_db( 'aqdb1', -- email user account for aqdb1 'welcome', -- email user password 'acme.com', -- email user domain 'aqdb1@acme.com', -- complete email address 'aqdb1', -- name of destination database 'http://aq-sun:8000/aqserv/servlet/AQTestServlet', -- URL to access the destination database servlet 'welcome', -- password of ORACLE_SMTP_AGENT 'ldaphost', -- LDAP host for lookup client certificates '389', -- LDAP port for LDAP lookup 'cn=aqdb1,cn=oraclecontext,cn=acme,cn=com', -- base DN of LDAP lookup NULL, NULL -- anonymous bind ); dbms_output.put_line('register DB status: ' || status); end;
After the setup is complete, an AQ agent can send e-mail messages to the database e-mail address to perform AQ operations. The AQ operations should be constructed according to IDAP, signed using the Oracle e-mail S/MIME toolkit, and sent as a binary attachment with the name including IDAP_MESSAGE
.
The procedures for an AQ client to make a request to the AQ servlet using HTTP and for the AQ servlet to process the request are as follows:
For example, https://aq.us.oracle.com:8000/aqserv/servlet/AQTestServlet
This opens a connection to port 8000 on aq.us.oracle.com.
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>
POST
to the servlet at the remote server.
See the $ORACLE_HOME/demo directory for sample code of POST
requests using HTTP.
POST
request.If this is the first request being serviced by this servlet, the servlet is initialized--its init() method
is invoked. The init () method
creates a connection pool to the Oracle server using the AQxmlDataSource parameters (SID, host, port, AQ servlet super-user name, password) provided by the client.
For example, in the client request (step 3 in "AQ Client Request to the AQ Servlet Using HTTP"), the agent JOHN
is trying to access OE.OE_NEW_ORDERS_QUE.
AQ$INTERNET_USERS
view). If any one of these db_users
has privileges to access the queue/topic specified in the request, the 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 will create a session for the agent JOHN
with the privileges of database user OE
. (See "Mapping the AQ Agent to Database Users" for information on ENABLE_DB_ACCESS
.)
COMMIT
or ROLLBACK request is made.SEND/PUBLISH/RECEIVE/REGISTER/COMMIT/ROLLBACK
) is performed.For example, the response for the preceding request may 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>
After a client is authenticated and connects to the 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 aborted. 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, it must include this HTTP header containing the session ID cookie in subsequent requests. This is automatically done by most Web browsers. However, if you are using a Java or C client to post requests, this has to be done 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 issued to end the transaction. The commit or rollback requests can also be included as part of other 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, the transaction is automatically aborted. This timeout can be modified in the init() method of the servlet by using setSessionMaxInactiveTime(). See "Customizing the AQ Servlet" for more information.
Using Advanced Queuing propagation in Oracle9i, you can propagate over HTTP and HTTPS (HTTP over SSL) instead of Oracle Net Services (formerly Net8). HTTP, unlike Oracle Net Services, is easy to configure for firewalls.
HTTP AQ propagation uses the infrastructure for Internet access to AQ as its basis. The background process doing propagation pushes messages to an AQ Servlet that enqueues them into the destination database, as shown in Figure 17-3.
Since 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.
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 AQ HTTP propagation without any change to the existing code, by following steps 1-3. Similarly an application using AQ http propagation can easily switch back to Net Services propagation just by re-creating the dblink with a Net Services connection string, without any other changes.
For example, if the webserver is running on the machine 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 AQ HTTP agent.
UTL_HTTP.SET_PROXY
procedure, as described in Oracle9i Supplied PL/SQL Packages and Types Reference.Create a class AQPropServlet that extends AQxmlServlet as described in [create the 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 Oracle9i, the propagation servlet name and deployment path are fixed; that is, they must be AQPropServlet
and the servlet, respectively.
dbms_aqdm.schedule_propagation. dbms_aqadm.schedule_propagation('src_queue', 'dba');
The general procedure for an AQ client to make a request to the AQ servlet using SMTP is as follows:
IDAP_MESSAGE
, and sends it as a binary attachment to the database e-mail address.The procedure for the AQ servlet to process a request is described in "AQ Servlet Processes a Request Using HTTP". When the servlet sends a response, the e-mail server sends an e-mail message containing the XML response to the address specified in the reply-to field of the original e-mail message.
The oracle.AQ.xml.AQxmlServlet provides the API to set the connection pool size, session timeout, style sheet, and callbacks before and after AQ operations.
The AQ data source is used the specify the backend database to which the servlet connects to perform AQ operations. It contains the database SID, host name, listener port and the username/password of the 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 Oracle9i Supplied Java Packages Reference for more information.
The 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, you must specify a cache size using the AQxmlDataSource.setCacheSize(size)
method.
After a client is authenticated and connects to the 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 aborted.
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, the transaction is automatically aborted. This timeout can be specified in the init() method of the servlet by using setSessionMaxInactiveTime() method.
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); } }
The AQ servlet sends back responses in XML. The servlet administrator can specify a style sheet that is to be set for all responses sent back from this servlet. This can be done by invoking the setStyleSheet(type,href)
or the setStyleSheetProcessingInstr(proc_instr) in init()
method of the servlet.
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); } }
Using the AQ servlet, you can register callbacks that will be invoked before and after AQ operations are performed. This allows users to perform AQ and non-AQ operations in the same transaction.
To receive callbacks, users register an object that implements the oracle.AQ.xml.AQxmlCallback
interface. The AQxmlCallback
interface has the following methods:
public interface AQxmlCallback { /** Callback invoked before any AQ operations are performed by the servlet */ public void beforeAQOperation(HttpServletRequest request, HttpServletResponse response, AQxmlCallbackContext ctx); /** Callback invoked after any 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 AQ operations. Users can perform other SQL operations in the callback functions using this connection object.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
Before any 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 AQ Servlet callback */ public class TestCallback implements oracle.AQ.xml.AQxmlCallback { /** Callback invoked before any 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 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 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); } }
|
Copyright © 1996, 2002 Oracle Corporation. All Rights Reserved. |
|