Version of Designer: 5.5.2.2
Version of TIBCO EMS: 4.4.3
Some time ago I did a post about developing web-services using TIBCO BusinessWorks. In this post I would like to discuss how to develop a web-service which uses JMS as the SOAP transport instead of HTTP. The problem with developing a web-service bound to a JMS Queue instead of an HTTP transport, is that it can be used only in a homogeneous TIBCO environment. In other words we need to have TIBCO at both (client and server) ends if we are using a web-service bound to a JMS Queue.
This is so because the WSDL representation of the binding is proprietary to TIBCO (more on this later) as there is no agreed standard for binding SOAP to JMS. Although when I was digging around I did find a ‘working draft’ at W3.org for SOAP over JMS (http://www.w3.org/TR/soapjms/) so something is being done to plug this gap!
Why all this hassle for SOAP over JMS you ask? Why not stick with good old SOAP over HTTP? Well simply because JMS transport is whole lot more robust and can be scaled up easily without affecting QoS etc.
Introducing the Example
The web-service we are going to create in this example is a relatively simple one. It will take in two integers and return their sum. A fairly simple example but this post is about using SOAP over JMS so that is what we will concentrate on.
The schema for the request and response messages is given below:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.tibco.com/schemas/WebServiceTest/Schema/Schema.xsd" targetNamespace="http://www.tibco.com/schemas/WebServiceTest/Schema/Schema.xsd" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="add"> <!-- Request - two integers a and b to be added --> <xs:complexType> <xs:sequence> <xs:element name="a" type="xs:int"/> <xs:element name="b" type="xs:int"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="result" type="xs:int"/> <!-- Response - the sum of a and b --> </xs:schema>
Now the next thing we need to do is to setup the Service Resource. I won't go into the details of how it is done as I have already covered most of the steps in a different post.
The reason I don’t need to go into details is because web-services are designed to decouple the operation from the ways of accessing that operation (i.e. the binding). Obviously as binding = message format + transport AND each operation can have different bindings, the only thing that will be different when setting up the Service Resource will be the Binding Section. Furthermore as we are still using SOAP as the message format the only difference that you will see in the Service Resource, as compared to SOAP over HTTP configuration, will be in the Transport sub-tab (see image below).
In the Transport sub-tab, if instead of selecting a HTTP connection, a JMS connection is selected in the Transport box (see image above), then you will get options to setup the JMS transport.
Setting up the JMS Transport
Setting up the Transport in case of JMS is bit more involved than HTTP. For the sake of clarity we will use Queues for our web-service instead of Topics. There are four main things to setup once you have selected a JMS connection in the Transport box. These settings are similar to those in the JMS activities such as JMS Queue Sender.
1) JMS Destination – the queue or topic which will contain the JMS message carrying the SOAP as payload.
2) JMS Destination Type – Queue or Topic (depending on what kind of interaction is required).
3) JMS Message Type – Text or Bytes message – we go for Text in the example so that we can examine the SOAP message being sent over the EMS.
4) Acknowledgement Mode – Auto for the example otherwise all the standard and TIBCO EMS specific options are available for selection.
If you select ‘Topic’ as the JMS Destination Type then you can also decide which of the Operations have a ‘durable subscription’.
That is the only difference in changing from SOAP over HTTP to SOAP over JMS as far as the Service Resource is concerned.
Looking at the WSDL
Once everything is setup navigate to the WSDL Source tab in the Service Resource configuration to look at the WSDL which has been generated for the web-service.
<?xml version="1.0" encoding="UTF-8"?> <!--Created by TIBCO WSDL--> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://xmlns.example.com/1301947961037" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:jms="http://www.tibco.com/namespaces/ws/2004/soap/binding/JMS" xmlns:jndi="http://www.tibco.com/namespaces/ws/2004/soap/apis/jndi" xmlns:ns0="http://www.tibco.com/schemas/WebServiceTest/Schema/Schema.xsd" name="Untitled" targetNamespace="http://xmlns.example.com/1301947961037"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.tibco.com/schemas/WebServiceTest/Schema/Schema.xsd" targetNamespace="http://www.tibco.com/schemas/WebServiceTest/Schema/Schema.xsd" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="add"> <xs:complexType> <xs:sequence> <xs:element name="a" type="xs:int"/> <xs:element name="b" type="xs:int"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="result" type="xs:int"/> </xs:schema> </wsdl:types> <wsdl:service name="JMSAddService"> <wsdl:port name="AddPortEndpoint1" binding="tns:AddPortEndpoint1Binding"> <soap:address location=""/> <jndi:context> <jndi:property name="java.naming.provider.url" type="java.lang.String">tibjmsnaming://localhost:7222</jndi:property> <jndi:property name="java.naming.factory.initial" type="java.lang.String">com.tibco.tibjms.naming.TibjmsInitialContextFactory</jndi:property> </jndi:context> <jms:connectionFactory>QueueConnectionFactory</jms:connectionFactory> <jms:targetAddress destination="queue">inQueue</jms:targetAddress> </wsdl:port> </wsdl:service> <wsdl:portType name="AddPort"> <wsdl:operation name="AddOperation"> <wsdl:input message="tns:InMessage"/> <wsdl:output message="tns:OutMessage"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="AddPortEndpoint1Binding" type="tns:AddPort"> <soap:binding style="document" transport="http://www.tibco.com/namespaces/ws/2004/soap/binding/JMS"/> <jms:binding messageFormat="Text"/> <wsdl:operation name="AddOperation"> <soap:operation style="document" soapAction="/Connections/JMSAddService.serviceagent/AddPortEndpoint2/AddOperation" soapActionRequired="true"/> <wsdl:input> <soap:body use="literal" parts="part1"/> </wsdl:input> <wsdl:output> <soap:body use="literal" parts="part1"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:message name="InMessage"> <wsdl:part name="part1" element="ns0:add"/> </wsdl:message> <wsdl:message name="OutMessage"> <wsdl:part name="part1" element="ns0:result"/> </wsdl:message> </wsdl:definitions>
Let get back to the issue of lack of standards for SOAP over JMS and why we need TIBCO at both ends.
For that we need to focus down into the Binding and Service elements of the WSDL.
Looking at the Service element (see below), where the method of connecting to the web-service is defined. We find that it contains information about the EMS server (from the Connection resource we set in the Transport box) as well as the queue name we set in the Transport sub-tab.
<wsdl:service name="JMSAddService"> <wsdl:port name="AddPortEndpoint1" binding="tns:AddPortEndpoint1Binding"> <soap:address location=""/> <jndi:context> <jndi:property name="java.naming.provider.url" type="java.lang.String">tibjmsnaming://localhost:7222</jndi:property> <jndi:property name="java.naming.factory.initial" type="java.lang.String">com.tibco.tibjms.naming.TibjmsInitialContextFactory</jndi:property> </jndi:context> <jms:connectionFactory>QueueConnectionFactory</jms:connectionFactory> <jms:targetAddress destination="queue">inQueue</jms:targetAddress> </wsdl:port> </wsdl:service>
We also find two strange new namespaces being used - jms and jndi. Let us see what these namespace prefixes stand for. Scroll right up to the top of the WSDL and you will see the following entries:
xmlns:jms="http://www.tibco.com/namespaces/ws/2004/soap/binding/JMS"
xmlns:jndi="http://www.tibco.com/namespaces/ws/2004/soap/apis/jndi"
These two namespaces have been defined by TIBCO so they are internal and are not 'standardized' as are other namespaces in the WSDL such as xs ( xmlns:xs="http://www.w3.org/2001/XMLSchema") for the schema in Types or soap (xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/") for SOAP related properties in Binding.
Thus if you are a non-TIBCO client you will have no idea what jms:targetAddress element means in the WSDL.
Once there is a standard for SOAP over JMS then instead of TIBCO specific namespaces we will see a prefix like soapjms with the definition xmlns:soapjms = "http://www.w3.org/2010/soapjms/" [1] .
Next we look at the Binding element (see below). Here also we find the TIBCO specific JMS namespace as well as SOAP over JMS transport definition (in bold).
<wsdl:binding name="AddPortEndpoint1Binding" type="tns:AddPort"> <soap:binding style="document" transport="http://www.tibco.com/namespaces/ws/2004/soap/binding/JMS"/> <jms:binding messageFormat="Text"/> <wsdl:operation name="AddOperation"> <soap:operation style="document" soapAction="/Connections/JMSAddService.serviceagent/AddPortEndpoint2/AddOperation" soapActionRequired="true"/> <wsdl:input> <soap:body use="literal" parts="part1"/> </wsdl:input> <wsdl:output> <soap:body use="literal" parts="part1"/> </wsdl:output> </wsdl:operation> </wsdl:binding>
Again once we have a standardized way of binding SOAP to JMS then instead of the TIBCO specific listing in transport attribute we will have something like “http://www.w3.org/2010/soapjms/”[1].
If we compare the Service and Binding elements above to those in the same web-service but using HTTP instead of JMS we that all namespaces being used to define the connection and binding properties are standardized. That is what makes SOAP over HTTP web-services independent of vendors and implementation languages.
Next we test the web-service. Make sure you save the WSDL Source (i.e. the concrete WSDL) so that our test client can use it.
Testing
To test the web-service we will create a client using BusinessWorks. We will use a SOAP Request Reply activity to test the web-service. The images below show how to configure the activity to access the web-service.
In the configuration simply select the namespace from the concrete WSDL file we saved for the client. As we are using TIBCO to create the client once you set the WSDL everything will be auto-populated. Go to the Transport Details tab (see below) and there you will see the JNDI and JMS sub-tabs which have also been auto-populated from the WSDL. This is so because TIBCO understands the jms and jndi namespaces and knows what to do with the information in the WSDL.
JNDI Sub-tab:
After loading the WSDL and saving the changes the SOAP Request Reply activity will ask you for an input (the two integers to be added).
Save everything and load the relevant processes. On starting the test you should see the Request being fired. If you monitor the relevant queue you will see a message being posted on the queue. The message will be consumed by the web-service and it will return the result back to the queue which in turn will be consumed by the client and you will see the output in the process. As we provided ‘3’ and ‘4’ as the two integers to be added in the input (see image above) the result we get is ‘7’ (see below).
<?xml version = "1.0" encoding = "UTF-8"?> <outputMessage> <ns0:result xmlns:SOAP-ENV = "http://www.w3.org/2003/05/soap-envelope" xmlns:ns0 = "http://www.tibco.com/schemas/WebServiceTest/Schema/Schema.xsd">7</ns0:result> </outputMessage>
If you want to take a look at the actual messages being sent in the JMS Message you can always stop the server before sending the request or after sending the request stop the client. The request or response message will remain in the queue and you can view the content (as we are using JMS Message Type of Text) by browsing the queue.
That is the end of the tutorial. Let me know if I have made any mistakes or if you have any suggestions.
Thank you for reading!
hi azahar,
yourweb-service articles are great! i tried all the steps mentioned in this post but in the test process JMSTest i can’t select port and operation for the SOAPRequestReply activity because the combos are empty?! do you have any hint on that issue or can you post a zip containing the whole project?
regards, rainer
LikeLike
hi again,
i solved the problem by using the concrete WSDL as you mentioned it in the tutorial 😉
regards, rainer
LikeLike
Hey Azhar,
Excellent article. very thank full to u.
Thanks,
Kishore Podili
LikeLike
Hi Azhar,
Could you please tell me the SOAPJMS parameters and corresponding values that need to be used by a non-TIBCO client to connect to a SOAP over JMS service setup in TIBCO.
Thanks,
Ankit
LikeLike