- Messaging Queuing with JMS
- Message-driven Bean
- JMS as a SOAP Transport
- Reliable Messaging on the Internet
JMS as a SOAP Transport
Because SOAP is transport-agnostic, you can use JMS for its transport instead of HTTP. Furthermore, the concept of an intermediary suggests that SOAP messages go through multiple nodes via different transports. Figure 2 illustrates a possible configuration that contains both concepts. Intercompany communication is performed via HTTP(S). The receiver company has a SOAP intermediary that receives SOAP messages via HTTP and forwards them to back-end applications via JMS. The key idea here is that the external firewall allows HTTP to pass, whereas the internal firewall allows only JMS.
Figure 2 SOAP messaging that includes both HTTP and JMS.
This configuration is typical for several reasons. First, you can augment message processing by adding functions to an intermediary without changing the back-end applications. For example, you may add digital signature verification and logging functions there. Even in that case, you do not have to change the back-end applications. In addition, some companies do not want to accept HTTP through their internal firewall, for security reasons. However, strictly speaking, simply eliminating HTTP does not necessarily improve the security level. The intermediary also plays a role of security domain boundary; for example, credential mapping from external IDs to internal IDs is performed.
SOAP JMS transport is necessary especially for enterprise customers. Although Axis does not currently support JMS transport, a prototype implementation is provided in our examples. Listing 4 is an excerpt from the JMSSender class for the requestor side.
Listing 4: JMSSender Class
public class JMSSender extends BasicHandler { private void sendMessage(MessageContext msgContext, [ccc] String messageTxt) throws AxisFault { BytesMessage msg; try { queueConnection = queueFactory.createQueueConnection(); queueSession = [ccc] queueConnection.createQueueSession(false, [ccc] Session.AUTO_ACKNOWLEDGE); queueSender = queueSession.createSender(queue); msg = queueSession.createBytesMessage(); msg.writeUTF(messageTxt); TemporaryQueue replyTo = [ccc] queueSession.createTemporaryQueue(); msg.setJMSReplyTo(replyTo); queueSender.send(msg); queueConnection.start(); QueueReceiver receiver = [ccc] queueSession.createReceiver(replyTo); javax.jms.Message replyMsg = receiver.receive(); if (replyMsg instanceof BytesMessage) { String replyTxt = ((BytesMessage)replyMsg).readUTF(); org.apache.axis.Message respMsg = [ccc] new org.apache.axis.Message(replyTxt); msgContext.setResponseMessage(respMsg); } closeConnection(); } catch (JMSException e) { throw new AxisFault("JMSSender.sendMessage", [ccc] "JMSException: " + e, null, null); } } ...... }
The sendMessage() method in the class implements a synchronous request/response by combining two JMS messages. It creates a temporary queue for a response, sets it as the reply-to queue in the request message, and sends the message to a request queue. Then it waits until a response message is delivered to the temporary queue.
Listing 5 is a portion of the JMSListener class for the service provider side.
Listing 5: JMSListener Class
public class JMSListener implements MessageListener { public void onMessage(javax.jms.Message msg) { BytesMessage bytesMsg = null; org.apache.axis.Message respMessage = null; MessageContext msgContext = null; String msgTxt = null; AxisEngine engine = AxisServer.getSingleton(); msgContext = new MessageContext(engine); try { if (!msg instanceof BytesMessage) { // do error handling ...... } bytesMsg = (BytesMessage) msg; replyQueue = (Queue)(bytesMsg.getJMSReplyTo()); sender = session.createSender(replyQueue); msgTxt = bytesMsg.readUTF(); org.apache.axis.Message soapMessage = [ccc] new org.apache.axis.Message(msgTxt); msgContext.setRequestMessage(soapMessage); msgContext.setTransportName(transportName); engine.invoke(msgContext); respMessage = msgContext.getResponseMessage(); String respString = respMessage.getAsString(); BytesMessage reply = session.createBytesMessage(); reply.writeUTF(respString); sender.send(reply); } catch (Exception e) { // do error handling } } }
The central method in this class is onMessage(). Here, we get the reply queue from the incoming message and create a queue sender for returning the response. Main processing is invoked with engine.invoke(). Finally, we respond via the temporary queue created by the sender.
To execute SOAP over JMS, visit /ch5/ex6/index.jsp in the example navigator (see Figure 3). Like other pages, specify some parameters and click the Submit PO button.
Figure 3 Example navigator GUI for SOAP over JMS.