This chapter covers the following topics:
Java Messaging Service (JMS) is a messaging standard defined by Sun Microsystems, Oracle, and other vendors. JMS is a set of interfaces and associated semantics that define how a JMS client accesses the facilities of an enterprise-messaging product.
Oracle Java Messaging Service provides a Java API for Oracle Advanced Queuing (AQ) based on the JMS standard. Oracle JMS supports the standard JMS interfaces and has extensions to support the AQ administrative operations and other AQ features that are not a part of the standard.
JMS Text Message can represent a purchase order or an invoice. It contains the following components:
Header: All messages support the same set of header properties which contain values used by both clients and providers to identify and route messages.
Properties: In addition to the standard header properties, you can add optional header properties to a message. Properties can be standard properties, provider-specific, or application-specific properties.
Body: This is the message payload. JMS defines various types of message payloads, as well as a type that can store JMS messages of any or all JMS-specified message types.
Oracle supports JMS Text messages using aq$jms_text_message
or aq$jms_message
types. Users must create the queue using one of these types as the payload.
There are sample queues created for inbound and outbound JMS messages. These two seeded queues are WF_JMS_IN and WF_JMS_OUT to receive inbound and outbound JMS messages.
Note: In addition to these two seeded queues, Oracle XML Gateway allows JMS providers to create customized JMS queues for Business-to-Business transactions.
For example, when a message is sent to a Trading Parnter using JMS messages, Oracle XML Gateway puts the messages in the WF_JMS_OUT topic.
A JMS client or provider is a Java-based client. A JMS client publishes a JMS Text message to a JMS topic. The Oracle Workflow Business Event System then processes this message from JMS queues.
To provide complete support for Business-to-Business transactions, Oracle XML Gateway provides the various points of Transport protocols for Trading Partner based message consumption and message generation. These various protocol integration points are:
Oracle Transport Agent (OTA) Using the Seeded ECX_INBOUND and ECX_OUTBOUND Queues
Web Services Using Seeded WF_WS_JMS_IN and WF_WS_JMS_OUT Queues
JMS Client Application Using WF_JMS_IN, WF_JMS_OUT, or Any JMS Queues
XML Gateway can receive and send XML messages between Trading Partners and Oracle E-Business Suite through OTA protocol using ECX_INBOUND and ECX_OUTBOUND queues.
Inbound Message Queue (ECX_INBOUND) holds all inbound messages that enter the process through the Transport Agent or placed directly by an API.
For outbound messages, XML Gateway creates XML messages and then enqueues them on this Outbound Message Queue (ECX_OUTBOUND).
See: Queues, Message Queues chapter for details.
XML Gateway can receive and send XML messages as a document type Web service using the Simple Object Accessed Protocol (SOAP).
All inbound messages are prepared as designed event before being enqueued to the SOAP agent, WF_WS_JMS_IN queue. The Web Service IN Agent listeners pick up the message for further processing.
Outbound XML messages are created by Workflow processes and passed to the SOAP agent, WF_WS_JMS_OUT queue. The messages are picked up by the SOAP client who is responsible for the actual delivery of the message to the Trading Partner.
See: Process Flows, Web Service chapter for inbound and outbound process flow details.
By leveraging the Oracle Workflow Business Event System, Oracle XML Gateway allows receiving and sending JMS-based messages for business-to-business transactions between the Oracle E-Business Suite and Trading Partners using WF_JMS_IN, WF_JMS_OUT, or any JMS queues registered with Business Event System. See: Steps to Create Custom JMS Queues for Outbound B2B Transactions, and Steps to Create Custom JMS Queues for Inbound B2B Transactions.
How XML Gateway can be integrated with any JMS queues and the header properties for inbound and outbound transactions are explained in details in the next section.
To have seamless JMS integration and complete transaction monitoring and logging support, Oracle XML Gateway uses internal APIs to provide the following integration features:
For inbound transactions, ability to provide complete Trading Partner user and transaction validation as well as authorization support so that XML Gateway only processes those messages that are valid and have the appropriate authorization.
For outbound transactions, ability to provide a mechanism to verify at the runtime that the Trading Partner setup is complete and store the JMS queues as part of the setup and so that the generated messages can be sent to the desired JMS queue.
After an application raises a business event for JMS queues, the event dispatcher catches the event, executes the event subscription to that event, enqueues the message and then places it to the default WF_JMS_OUT outbound agent or any customized outbound JMS queue registered with the Business Event System with the following JMS message header properties:
ECX_MESSAGE_TYPE
ECX_MESSAGE_STANDARD
ECX_TRANSACTION_TYPE
ECX_TRANSACTION_SUBTYPE
ECX_PARTY_SITE_ID
ECX_MSGID
A JMS provider then consumes the message placed in the JMS queue.
A JMS provider publishes XML messages to an inbound JMS agent (WF_JMS_IN or any JMS queue) registered with the Business Event System. The User to Trading Partner and Trading Partner to Transaction validation and authorization will then be processed so that Oracle XML Gateway can process the valid message for the inbound transaction.
The following properties must be set in the JMS message header to enable Oracle XML Gateway to process the inbound message:
ECX_MESSAGE_TYPE
ECX_MESSAGE_STANDARD
ECX_TRANSACTION_TYPE
ECX_TRANSACTION_SUBTYPE
ECX_PARTY_SITE_ID
BES_EVENT_NAME=oracle.apps.ecx.jms.receive;
BES_EVENT_KEY
ECX_USERNAME (Optional)
Note: The ECX_USERNAME is used for authorization if the ECX: Enable User Check for Trading Partner profile option is enabled. The JMS payload must contain the transaction payload.
To send a message to a Trading Partner using JMS messages, the appropriate protocol type must be set first in the Trading Partner Setup form:
Select JMS as the Protocol Type field for transactions enabled at the site level.
Select a JMS agent registered with the Business Event System (BES) for the Protocol Address field.
The agent can be WF_JMS_OUT or an agent you created and registered with the BES.
Oracle XML Gateway uses the following seeded event name for inbound transactions through custom JMS queue:
Event Name: oracle.apps.ecx.jms.receive
Event Description: Event for JMS queues
Status: Enabled
Owner Name: Oracle Workflow
Business event for JMS queues, oracle.apps.ecx.jms.receive, has the following seeded subscriptions:
Description | Phase | Status | Source Type | Rule Function | WF Process Type | WF Process Name |
---|---|---|---|---|---|---|
Rule function to perform the User to Trading Partner and Trading Partner to Transaction validation and authorization | 10 | Enabled | External | ECX_RULE.TPPreProcessing | N/A | N/A |
Rule function to perform the inbound processing | 20 | Enabled | External | ECX_RULE.receiveTPMessage | N/A | N/A |
Rule function for error handling | 10 | Enabled | Error | WF_RULE.error_rule | ECXMAIN | ECXERROR |
Oracle XML Gateway provides you with seeded JMS queues (WF_JMS_IN and WF_JMS_OUT) and a mechanism allowing you to create custom JMS queues for your B2B transaction needs.
Steps to Create Custom JMS Queues for Outbound B2B Transactions
Steps to Create Custom JMS Queues for Inbound B2B Transactions
Performing Outbound B2B Transactions Using JMS Queues
Create a JMS Topic for Outbound Messages
Create a JMS Topic for outbound processing by creating queues with payload type aq$jms_text_messsage
.
Sample Code: (Create JMS topic, multiple consumers and grant the required permissions)
Following code creates a sample JMS queue CUSTOM_IMS_OUT in the APPLSYS schema.
/* Create Queue Table for CUSTOM_IMS_OUT Topic */ declare queue_table_exists exception; pragma EXCEPTION_INIT(queue_table_exists, -24001); begin dbms_output.put_line('==================================='); dbms_output.put_line('Creating Queue Table for CUSTOM_JMS_OUT Topic '); dbms_output.put_line('==================================='); begin dbms_aqadm.create_queue_table ( queue_table => 'CUSTOM_JMS_OUT', queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE', sort_list => 'PRIORITY,ENQ_TIME', multiple_consumers => TRUE, comment => 'Custom JMS Topic', compatible => '8.1' ); exception when queue_table_exists then null; when others then dbms_output.put_line('Oracle Server Error = '||to_char(sqlcode)); dbms_output.put_line('Oracle Server Message = '||sqlerrm); raise_application_error(-20000, 'Oracle Error Mkr2= ' ||to_char(sqlcode)||' - '||sqlerrm); end; end; / commit; /* Create Topic for CUSTOM_JMS_OUT Topic */ DECLARE queue_exists exception; pragma EXCEPTION_INIT(queue_exists, -24006); BEGIN dbms_output.put_line('==================================='); dbms_output.put_line('Creating CUSTOM_JMS_OUT Topic'); dbms_output.put_line('==================================='); begin dbms_aqadm.create_queue queue_name => 'CUSTOM_JMS_OUT', queue_table => 'CUSTOM_JMS_OUT', comment => 'Custom JMS Topic' ); exception when queue_exists then null; when others then dbms_output.put_line('Oracle Server Error = '||to_char(sqlcode)); dbms_output.put_line('Oracle Server Message = '||sqlerrm); raise_application_error(-20000, 'Oracle Error Mkr5= ' ||to_char(sqlcode)||' - '||sqlerrm); end; END; / commit; /* Start Topic */ declare begin dbms_output.put_line('================================'); dbms_output.put_line('Starting CUSTOM_JMS_OUT Queue '); dbms_output.put_line('================================'); dbms_aqadm.start_queue(queue_name => 'CUSTOM_JMS_OUT'); exception when others then dbms_output.put_line('Oracle Server Error = '||to_char(sqlcode)); dbms_output.put_line('Oracle Server Message = '||sqlerrm); raise_application_error(-20000, 'Oracle Error Mkr9= ' ||to_char(sqlcode)||' - '||sqlerrm); end; / commit; /* Creates Subscribers for Multiconsumer Queues */ REM ******************************************************************** REM sqlplus apps/pwd@dbinst @custommoutqsubc.sql <wf schema> <wf schema pwd> REM ******************************************************************** SET VERIFY OFF WHENEVER SQLERROR EXIT FAILURE ROLLBACK; connect &&1/&&2 WHENEVER SQLERROR CONTINUE; declare lagent sys.aq$_agent; subscriber_exist exception; pragma EXCEPTION_INIT(subscriber_exist, -24034); begin lagent := sys.aq$_agent('CUSTOM_JMS_OUT',null,0); dbms_aqadm.add_subscriber(queue_name =>'&&1..CUSTOM_JMS_OUT',subscriber=>lagent, rule=>'1=1'); exception when subscriber_exist then dbms_aqadm.alter_subscriber(queue_name =>'&&1..CUSTOM_JMS_OUT', subscriber=>lagent, rule=>'1=1'); null; -- ignore if we already added this subscriber. end; / commit; exit; /* Create the necessary grants */ REM ******************************************************************** REM | APPS username REM | APPS password REM | AOL username REM | AOL password REM ******************************************************************** WHENEVER SQLERROR EXIT FAILURE ROLLBACK; WHENEVER SQLERROR CONTINUE; WHENEVER OSERROR EXIT FAILURE ROLLBACK; connect &3/&4 REM create grants in APPLSYS grant all on custom_jms_out to &&1 with grant option; execute dbms_aqadm.grant_queue_privilege(privilege =>'ALL',queue_name =>'&&3'||'.CUSTOM_JMS_OUT',grantee =>'&&1',grant_option=>TRUE); REM create synonyms in APPS WHENEVER SQLERROR CONTINUE; connect &1/&2 create synonym custom_jms_out for &3..custom_jms_out; commit; exit; /
Configure the Agent and Queue Handler for JMS Queues
Configure the agents and queue handler for the CUSTOM JMS topic through the Workflow Business Event Manager. Oracle Workflow provides a queue handler named wf_event_ojmstext_qh that provides enqueue and dequeue procedures for JMS topics.
The sample CUSTOM_JMS_OUT queue has the following properties:
Property | Value |
---|---|
Name | CUSTOM_JMS_OUT |
Display Name | CUSTOM_JMS_OUT |
Protocol | SQLNET |
Address | <SCHEMA>.CUSTOM_JMS_OUT@<LOCAL DATABASE> |
System | <LOCAL SYSTEM> |
Queue Handler | WF_EVENT_OJMSTEXT_QH |
Direction | OUT |
Status | Enabled |
Set Up JMS Protocol for Trading Partners in the Trading Partner Setup form
Use the following guidelines for custom JMS queues:
Property | Value |
---|---|
Protocol_Type | JMS |
Connection_Type | DIRECT |
JMS_Queue_Name | JMS queue |
Create a JMS Client and Subscribe to the Messages
Create a JMS Client that will subscribe to the JMS queue and consume the messages. All the message parameters will be available as part of the JMS message. The generated XML will be available as the payload in the JMS message.
Sample Code: (JMS Subscriber)
/*** * This is a sample java file which uses Oracle JMS - Java Messaging Service * API to retrieve text Message. * * This demo does the following: * -- Setup Connection * -- Get Session from Connection * -- Get topic from session * -- Create a Durable Subscriber for this topic * -- Receive the Message for subscriber * * The following instructions describe how to compile and execute * this sample on the client machine. * * System requirements: * ==================== * 1) The client machine should have JDK 1.1.x or JDK1.2 or higher installed * 2) The following jar/zip files should be in the CLASSPATH on the client * machine. * For JDK1.2.x * classes12.zip * aqapi.jar * jmscommon.jar * For JDK1.1.x * classes111.zip * aqapi11.jar * jmscommon.jar * Set up CLASSPATH, PATH, LD_LIBRARY_PATH based on JDK version and platform. * Compilation and Running: * ======================== * 3) If you already have the jars in step 2) in classpath * javac JMSSubscriber.java * 4) java JMSSubscriber ***/ import javax.jms.JMSException; import javax.jms.Session; import javax.jms.TextMessage; import javax.jms.Topic; import javax.jms.TopicSession; import javax.jms.TopicSubscriber; import oracle.jms.AQjmsConnection; import oracle.jms.AQjmsFactory; import oracle.jms.AQjmsSession; import oracle.jms.AQjmsTopicConnectionFactory; import oracle.jms.AQjmsTextMessage; public class JMSSubscriber { /* * TopicConnectionFactory object used to create topic connections */ AQjmsTopicConnectionFactory topicConnectionFactory = null; Topic topic = null; /* JMS Connection object */ AQjmsConnection topicConnection = null; /* * TopicSession object for Subscribers */ TopicSession subTopicSession = null; /** * Default Constructor */ public JMSSubscriber() { try { /* Get Connection Factory for topic with specified TNS and driver */ topicConnectionFactory = (AQjmsTopicConnectionFactory) AQjmsFactory .getTopicConnectionFactory("ap601sdb", "atgwfdev", 4135, "thin"); /* Create topicConnection with username and password */ topicConnection = (AQjmsConnection) topicConnectionFactory .createTopicConnection("apps", "password"); /* Create subscriber TopicSession */ subTopicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); /* Get topic object from schema and queue */ topic = ((AQjmsSession) subTopicSession).getTopic("applsys", "custom_jms_in"); /* * Start Connection. It is in Stopped mode by default */ topicConnection.start(); } catch (JMSException ex) { System.out.println("Exception = " + ex.toString()); } } /** * Method to close topicConnection * * @throws JMSException */ public void close() throws JMSException { topicConnection.close(); } /** * Method to recieve messages from topic */ public void recieveMessages() { try { TopicSubscriber topicSubscriber = subTopicSession .createDurableSubscriber(topic, "Subscriber1"); boolean done = false; System.out.println("Dequeue Messages for Subscriber "); AQjmsTextMessage msg = null; while (!done) { msg = (AQjmsTextMessage) topicSubscriber.receiveNoWait(); if (msg == null) { done = true; } else { System.out.println("Recieved Message with ID : " + msg.getJMSMessageID()); System.out.println("Message Properties -"); System.out.println("ECX_MESSAGE_TYPE : " + msg.getStringProperty("ECX_MESSAGE_TYPE")); System.out.println("ECX_MESSAGE_STANDARD : " + msg.getStringProperty("ECX_MESSAGE_STANDARD")); System.out.println("ECX_TRANSACTION_TYPE : " + msg.getStringProperty("ECX_TRANSACTION_TYPE")); System.out.println("ECX_TRANSACTION_SUBTYPE : " + msg.getStringProperty("ECX_TRANSACTION_SUBTYPE")); System.out.println("ECX_PARTY_SITE_ID : " + msg.getStringProperty("ECX_PARTY_SITE_ID")); System.out.println("BES_EVENT_NAME : " + msg.getStringProperty("BES_EVENT_NAME")); System.out.println("BES_EVENT_KEY : " + msg.getStringProperty("BES_EVENT_KEY")); System.out.println("Message Text -"); System.out.println(msg.getText()); } } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { JMSSubscriber jMSSubscriber = new JMSSubscriber(); jMSSubscriber.recieveMessages(); try { /* Close topicConnection */ jMSSubscriber.close(); } catch (Exception e) { e.printStackTrace(); } }
Related Topics
Steps to Create Custom JMS Queues for Inbound B2B Transactions
Java Messaging Service (JMS) Overview
Oracle XML Gateway and B2B Transactions Integration Points
Performing Inbound B2B Transactions Using JMS Queues
Create a JMS Topic for Inbound Messages
Create a JMS Topic for inbound processing by creating queues with payload type aq$jms_text_message
.
See: Step 1, Performing Outbound B2B Transactions Using JMS Queues for details. Replace the CUSTOM_JMS_OUT queue with CUSTOM_JMS_IN to create a JMS queue for inbound messages.
Configure the Agent and Queue Handler for JMS Queues
See: Step 2, Performing Outbound B2B Transactions Using JMS Queues for details. Replace the CUSTOM_JMS_OUT queue with CUSTOM_JMS_IN and use direction as IN.
Create a JMS Client and Publish Messages to the Custom JMS Queue
Create a JMS Client that will publish messages to the JMS queue. When publishing the messages, there are some XML Gateway specific parameters that should be available as part of the JMS message:
Name | Value |
---|---|
ECX_TRANSACTION_TYPE | External Transaction Type |
ECX_TRANSACTION_SUBTYPE | External Transaction Subtype |
ECX_MESSAGE_STANDARD | Message Standard |
ECX_MESSAGE_Type | Message Type |
ECX_PARTY_SITE_ID | Source TP Location Code |
BES_EVENT_NAME | oracle.apps.ecx.jms.receive |
BES_EVENT_KEY | Unique key for every run |
ECX_USERNAME (Optional) | Valid Oracle E-Business Suite Users |
Note: The XML Payload should be set as the payload in the JMS message. Any other optional parameters specific to the processing should also be provided as part of these name value pairs.
Sample Code: (JMS Publisher)
/*** * This is a sample java file which uses Oracle JMS - Java Messaging Service * API to publish text Message. * * This does the following: * -- Setup Connection * -- Get Session from Connection * -- Setup topic * -- Create a publisher for this topic * -- Publish Message to the Topic * * The following instructions describe how to compile and execute * this sample on the client machine. * * System requirements: * ==================== * 1) The client machine should have JDK 1.1.x or JDK1.2 or higher installed * 2) The following jar/zip files should be in the CLASSPATH on the client * machine. * For JDK1.2.x * classes12.zip * aqapi.jar * jmscommon.jar * For JDK1.1.x * classes111.zip * aqapi11.jar * jmscommon.jar * Set up CLASSPATH, PATH, LD_LIBRARY_PATH based on JDK version and platform. * Compilation and Running: * ======================== * 3) If you already have the jars in step 2) in classpath * javac JMSPublisher.java * * 4) java JMSPublisher * ***/ import javax.jms.JMSException; import javax.jms.Session; import javax.jms.TextMessage; import javax.jms.Topic; import javax.jms.TopicPublisher; import javax.jms.TopicSession; import oracle.jms.AQjmsConnection; import oracle.jms.AQjmsFactory; import oracle.jms.AQjmsSession; import oracle.jms.AQjmsTextMessage; import oracle.jms.AQjmsTopicConnectionFactory; public class JMSPublisher { /* * TopicConnectionFactory object used to create topic connections */ AQjmsTopicConnectionFactory topicConnectionFactory = null; Topic topic = null; /* JMS Connection object */ AQjmsConnection topicConnection = null; /* * TopicSession object for Publishers. */ static AQjmsSession pubTopicSession = null; TopicPublisher topicPublisher = null; /** * Default Constructor */ public JMSPublisher() { try { /* Get Connection Factory for topic with specified TNS and driver*/ topicConnectionFactory = (AQjmsTopicConnectionFactory) AQjmsFactory .getTopicConnectionFactory("ap601sdb", "atgwfdev", 4135, "thin"); /* Create topicConnection with username and password*/ topicConnection = (AQjmsConnection) topicConnectionFactory .createTopicConnection("apps", "password"); /* Create publisher TopicSession*/ pubTopicSession = (AQjmsSession) topicConnection .createTopicSession(false, Session.AUTO_ACKNOWLEDGE); /* Get topic object from schema and queue*/ topic = ((AQjmsSession) pubTopicSession).getTopic("applsys", "custom_jms_in"); /* Create Publisher*/ topicPublisher = pubTopicSession.createPublisher(topic); /* Start Connection. * It is in Stopped mode by default */ topicConnection.start(); } catch (JMSException ex) { System.out.println("Exception = " + ex.toString()); } } /** * Method to close topicConnection * @throws JMSException */ public void close() throws JMSException { topicConnection.close(); } /** * Method to publish message to topic * @return msgid MessageId of the published Message */ public String publishMessage() { String msgid = null; AQjmsTextMessage msg = null; try { /* * Create Text Message */ msg = (AQjmsTextMessage) pubTopicSession.createTextMessage(); /* * Set its properties */ msg.setStringProperty("ECX_MESSAGE_TYPE", "XML"); msg.setStringProperty("ECX_MESSAGE_STANDARD", "OAG"); msg.setStringProperty("ECX_TRANSACTION_TYPE", "INVOICE"); msg.setStringProperty("ECX_TRANSACTION_SUBTYPE", "PROCESS"); msg.setStringProperty("ECX_PARTY_SITE_ID", "Business World"); msg.setStringProperty("BES_EVENT_NAME","oracle.apps.ecx.jms.receive"); msg.setStringProperty("BES_EVENT_KEY", "n6"); /* * Set Payload.Here its XML text */ String payload = new String( "<ECX_MAPS><ECX_MAPPINGS><MAP_ID>1</MAP_ID><MAP_CODE>hehe</MAP_CODE></ECX_MAPPINGS></ECX_MAPS>"); msg.setText(payload); /* * Publish Message to topic */ topicPublisher.publish(topic, msg); /* retrieve message id of posted message*/ msgid = msg.getJMSMessageID(); } catch (JMSException e) { e.printStackTrace(); } return msgid; } public static void main(String[] args) { JMSPublisher jMSPublisher = new JMSPublisher(); /* Post a message and get message id of posted message*/ String msgid = jMSPublisher.publishMessage(); /* Message Id is of Format - ID:<id> * Example ID:ASFG43543JH5K435H5K4 * So retieve correct id */ msgid = msgid.substring(3, msgid.length() - 1); System.out.println(" Message ID = " + msgid); try { /* Close topicConnection */ jMSPublisher.close(); } catch (Exception e) { e.printStackTrace(); } } }
Related Topics
Steps to Create Custom JMS Queues for Outbound B2B Transactions