bea.com | products | dev2dev | support | askBEA |
|
e-docs > WebLogic Platform > WebLogic Integration > BPM Topics > Programming BPM Client Apps > Establishing JMS Connections |
Programming BPM Client Apps |
Establishing JMS Connections
This section explains how to establish Java Message Service (JMS) connections. It includes the following topics:
Note: For more information about JMS, see Programming WebLogic JMS, in the BEA WebLogic Server document set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html
Or the JavaSoft JMS specification version 1.0.2, from Sun Microsystems, Inc., available at the following URL:
http://www.javasoft.com/products/jms/docs.html
Overview of JMS
WebLogic Server, on which the WebLogic Integration process engine and business process management (BPM) framework runs, implements the JMS, which supports the transmission of XML content. The process engine uses WebLogic JMS for communicating worklist, time, and event notifications; and error and audit messages.
The following figure shows how JMS enables communication, through XML messages, between running BPM workflow instances and external client applications.
Figure 6-1 Overview of JMS
As shown here, an XML event issued by a JMS application is:
The following sections describe the JMS destinations that are used by the process engine, and explain how to connect to and use them. An example showing how to connect to a JMS topic, WLI_BPM_Notify, is also provided.
For more information about JMS, see Programming WebLogic JMS, in the BEA WebLogic Server document set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html
JMS Destinations Used by the Process Engine
The following table summarizes the JMS destinations (queues and topics) used by the process engine.
Connecting to JMS
To connect to any of the JMS destinations defined in the table JMS Destinations Used by the Process Engine (and to be able to post and receive XML messages), the WebLogic Server administrator must perform the following steps for each destination:
A destination can be either a queue or a topic, encapsulating the address syntax for a specific provider. An administrator defines and configures the destinations and WebLogic Server adds them to the JNDI space during startup.
On the client side, destinations are handles to the objects on the server. The methods return only the destination names. To access destinations for messaging, you create message producers and consumers that can attach to destinations.
For more information about JMS, see Programming WebLogic JMS in the BEA WebLogic Server document set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html
Receiving Messages Asynchronously
To receive messages asynchronously from a destination, you must register an asynchronous message listener by performing the following steps:
Note: This step can also be accomplished using message-driven beans for WebLogic Server 6.0 or greater. For more information about EJBs, see Programming WebLogic Enterprise JavaBeans in the BEA WebLogic Server document set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/ejb/index.html
public void setMessageListener(
javax.jms.MessageListener listener
) throws javax.jms.JMSException
For more information about JMS, see Programming WebLogic JMS in the BEA WebLogic Server document set, available at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html
Generating Message-Driven Beans for Multiple Event Queues
As noted previously, the system administrator can define multiple event queues, if required, as described in Connecting to JMS. In this case, the system administrator must also generate the associated message-driven beans.
To generate message-driven beans for multiple event queues, use the com.bea.wlpi.util.MDBGenerator utility, as follows:
java com.bea.wlpi.util.MDBGenerator -queue queue_name
[-min number] [-max number] [-order number] [-transact]
[-validate] [-timeout seconds] [-help]
The following table lists the MDBGenerator utility arguments.
This utility generates a message-driven bean deployment for a specific queue as a jar file named qname-mdb.jar, where qname specifies the associated queue name. To deploy the message-driven beans on WebLogic Server, edit the ejb-jar.xml and weblogic-ejb.xml files to associate the EJB with a configured JMS destination. For more information, see Programming WebLogic Enterprise JavaBeans in the BEA WebLogic Server document set, available at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/ejb/index.html
Guaranteeing Message Delivery
Messages can be specified as persistent or non-persistent. A persistent message is guaranteed to be delivered at least once—it is not considered sent until it has been safely written in the file or database. WebLogic JMS writes persistent messages to a persistent backing store (file or JDBC database) assigned to each JMS server during configuration. Non-persistent messages are not stored. They are guaranteed to be delivered at least once unless there is a system failure, in which case messages may be lost. If a connection is closed or recovered, all non-persistent messages that have not yet been acknowledged will be redelivered. Once a non-persistent message is acknowledged, it will not be redelivered.
In the event that one or more receipients are not available when a message is sent, you can guarantee message delivery using addressed messages. Addressed messages persist an incoming event message until it is consumed by all recipients or a specified expiration time (time-to-live) elapses, whichever occurs first. You can guarantee message delivery on a workflow instance or template basis.
To guarantee message delivery using addressed messaging, the sending application (message producer) must define the following information:
Specifically, these fields specify the ID of the instance and/or name of the template, respectively, that you want to receive the message. You can define the WLPIInstanceIDs and WLPITemplateNames JMS header fields using the following javax.jms.Message class method:
public void setStringProperty(
java.lang.String name,
java.lang.String value
) throws javax.jms.JMSException
For example, to define the JMS header fields for the msg message instance, use the following methods:
String instanceID;
//instanceID set somewhere
msg.setStringProperty("WLPIInstanceIDs", instanceID);
String templateName="MyTemplate";
msg.setStringProperty("WLPITemplateNames", templateName);
These fields must be specified as String values. You can specify multiple IDs for each field, separated by commas. You should target only those instances and/or templates that have already been instantiated.
JMS header fields are always transmitted with the message, and are available to the message consumers (including the message-driven beans). For more information about defining JMS message header fields, see "Setting and Browsing Message Header and Property Fields" in "Developing a WebLogic JMS Application" in Programming WebLogic JMS, in the BEA WebLogic Server documentation set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/implement.html
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/implement.html
The time-to-live value can also be set via the Studio Post XML Event dialog box, as described in Defining Actions in Using the WebLogic Integration Studio.
Once set, you can view the resulting expiration time via the JMSExpiration JMS header field using the following javax.jms.Message class method:
public long getJMSExpiration(
) throws javax.jms.JMSException
For more information about viewing JMS message header fields, see "Setting and Browsing Message Header and Property Fields" in "Developing a WebLogic JMS Application" in Programming WebLogic JMS, in the BEA WebLogic Server documentation set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/implement.html
The following figure illustrates how to guarantee message delivery using addressed messaging.
Figure 6-2 Guaranteed Message Delivery
Note the following in this figure:
Guaranteeing Sequential Processing of Messages
One advantage of message-driven beans is that incoming messages can be processed in parallel by random message-driven bean instances. In this case, however, you cannot guarantee the order in which messages are processed.
If the order in which messages are received and processed is significant, you can guarantee that order by directing all messages to the same message-driven bean instance.
To guarantee that messages are delivered to the same message-driven bean instance and processed in a sequential order, the sending and receiving applications must preform the following steps:
You can define the WLPIOrderKey JMS header field using the following javax.jms.Message class method:
public void setLongProperty(
java.lang.String name,
long value
) throws javax.jms.JMSException
For example, to define the WLPIOrderKey JMS header field for the msg message instance, use the following method:
msg.setLongProperty("WLPIOrderKey",
Long.parseLong(instanceID));
Related messages that require sequential processing should be assigned the same order key value.
JMS header fields are always transmitted with the message, and are available to the message consumers (including the message-driven beans). For more information about defining JMS message header fields, see "Setting and Browsing Message Header and Property Fields" in "Developing a WebLogic JMS Application" in Programming WebLogic JMS, in the BEA WebLogic Server documentation set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/implement.html
A message selector is a Boolean expression. It consists of a String with a syntax similar to the where clause of an SQL select statement.
For example: WLPIOrderKey=1
For more information about defining JMS message selectors, see "Filtering Messages" in "Developing a WebLogic JMS Application" in Programming WebLogic JMS, in the BEA WebLogic Server documentation set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/implement.html
Note: All message groups that are to be processed in sequential order must be sent to the same JMS event queue.
All messages with a specific order key are processed by the same message-driven bean instance, in the order received, guaranteeing the sequential processing of the messages.
The following figure illustrates the sequential processing of messages using order keys.
Figure 6-3 Guaranteed Sequential Processing of Messages
Note the following in this figure:
Example of Connecting to a JMS Topic
This section provides an example showing how to connect to a JMS destination, in this case, the worklist notification topic, WLPI_BPM_Notify. The WLPI_BPM_Notify topic is used by a worklist client to refresh its display, dynamically, upon receipt of a message. In this example a message selector (filter) is used to receive notification. Subsequently, if the properties of the received message match the current values of the organization, role, user, and action, the message selector is used to refresh the display.
Each section of code is described in detail. For more information about JMS, see Programming WebLogic JMS in the BEA WebLogic Server document set, available at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html
Define the required variables, including the JNDI context, JMS connection factory, and topic static variables:
protected static final String JNDI_FACTORY= "weblogic.jndi.WLInitialContextFactory";
protected static final String JMS_FACTORY= "javax.jms.TopicConnectionFactory";
protected static final String NOTIFY_TOPIC="com.bea.wli.bpm.Notify";
Create all the objects necessary for sending messages to a JMS topic:
private TopicConnectionFactory tconFactory;
private TopicConnection tcon;
private TopicSession tsession;
private Topic topic;
private TopicSubscriber tsubscriber;
Set up the JNDI initial context, as follows:
try {
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL, wlpi.getUrl());
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
env.put("weblogic.jndi.createIntermediateContexts", "true");
Context ctx = new InitialContext(env);
tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY);
tcon = tconFactory.createTopicConnection();
For more information about setting session transaction and acknowledge modes, see Programming WebLogic JMS in the BEA WebLogic Server document set, available at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html
tsession = tcon.createTopicSession(
false, Session.AUTO_ACKNOWLEDGE
);
topic = (Topic)ctx.lookup(NOTIFY_TOPIC);
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html
if (tsubscriber != null) tsubscriber.close();
String selector = "orgId = '" +
wlpi.getWorklist().getActiveOrganization() + "' AND assigneeId = '" +
wlpi.getUserId() + "' AND NOT role" + " AND action = 'assigned'";
tsubscriber = tsession.createSubscriber(topic, selector, false);
tsubscriber.setMessageListener(this);
tcon.start();
}
When a message is delivered to the topic session, it is passed to the onMessage() method, which you must implement as described in Receiving Messages Asynchronously.
The following code provides an example of a message listener client that uses the notification to refresh its tasklist displays.
Note: For AWT/Swing applications, you must not update the user interface on the same thread as the call to the onMessage() method call, or you will encounter deadlocks and/or exceptions. You should marshall the call onto the AWT Event Dispatcher Thread. The Swing utilities provide the invokeLater() method to enqueue a runnable object on the AWT Event Dispatcher Thread, and you can include the update logic in the runnable object run() method.
import javax.swing.SwingUtilities;
public void onMessage(Message msg) {
String action;
TaskInfo task;
try {
// We're only interested in ObjectMessages with a TaskInfo
// payload.
if (!(msg instanceof ObjectMessage))
return;
Object data = ((ObjectMessage)msg).getObject();
if (!(data instanceof TaskInfo))
return;
action = msg.getStringProperty("action");
task = (TaskInfo)data;
} catch (JMSException e) {
e.printStackTrace();
return;
}
if (action.equals("update"))
taskUpdated(task);
else if (action.equals("remove"))
taskDeleted(task);
}
private void taskDeleted(final TaskInfo task) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
vTasks.remove(task);
int row = vDisplayedTasks.indexOf(task);
if (row != -1) {
vDisplayedTasks.remove(row);
model.fireTableRowsDeleted(row, row);
}
}
});
}
For more information about JMS, see Programming WebLogic JMS, in the BEA WebLogic Server document set, at the following URL:
http://download.oracle.com/docs/cd/E13222_01/wls/docs70/jms/index.html