Writing the WSDL extensions that let the WSIF service access a service at a JMS destination
Use the native Java Message Service (JMS) provider, Web Services Invocation Framework (WSIF) clients can treat a service available at a JMS destination as a Web service. Use this information, and associated code fragments, to help you to write the WSDL extensions.
This topic assumes that we chose and configured a JMS provider when we installed WebSphere Application Server (either the default messaging provider, or another provider such as the IBM MQ messaging provider). If not, do so now as described in Choose a messaging provider.
The WSDL extensions for JMS are identified with the namespace prefix jms. For example, <jms:binding>.
The supported operations are either one-way operations (send for JMS point-to-point messaging, or publish for JMS publish and subscribe messaging) or request-response operations (send and receive for JMS point-to-point messaging). The WSDL operations therefore specify either an input message only, or an input and an output message.
Operations that describe message interfaces with a native JMS binding do not have fault messages. No assumptions are made about the message schema or the semantics of message properties, therefore no distinction can be made between output and fault messages.
Use the following procedure, and associated code fragments, to help you to write the WSDL extensions that enable the WSIF service to access an underlying service at a JMS destination.
Tasks
- Set the JMS message body type.
We use the <jms:binding> extension to specify the JMS message body type:
<wsdl:binding ... > <jms:binding type="messageBodyType" /> ... </wsdl:binding>where messageBodyType is either ObjectMessage or TextMessage.- Parts to use for the input and output messages.
For JMS text messages and JMS object messages created from one or more WSDL message parts, we use the <jms:input> and <jms:output> extensions to specify the message parts to use for the JMS messages:
<wsdl:input ... > <jms:input parts="part1 part2 ..." /> </wsdl:input> <wsdl:output ... > <jms:output parts="part1 part2 ..." /> </wsdl:output>In the next example, the WSDL message has just one part containing the complete message body. This message body might result from a mapping of some other representation. See the next step on mapping the data types.
<wsdl:input ... > <jms:input parts="part1" /> </wsdl:input>If no parts are defined, then all the message parts are used.
- Map the data types.
We use the <format> extensions to map data types:
<wsdl:binding ... > <jms:binding type="..." /> <format:typeMapping encoding="Java" style="Java"> <format:typeMap typeName="..." formatType="targetType"/> </format:typemapping> ... </wsdl:binding>The value of targetType is dependent on the JMS message body type. See the step on setting the JMS message body type. For JMS object messages, the target data type implements the java.io.Serializable class. For JMS text messages, the target data type is always java.lang.String.
The <format> extensions are also used in other bindings that deal with Java interfaces.
- Set the JMS headers and properties.
JMS does not make assumptions about message headers. For example, if the JMS provider is MQSeries then each JMS message carries an RFH2 header. However we can access data in this message header indirectly, by getting and setting JMS message properties.
When we want the application to pass a property into the Web Services Invocation Framework (WSIF) as a part on the WSIF message, we use a <jms:property> tag. When we want to hard code a property value into the WSDL, we use a <jms:propertyValue> tag. The <jms:propertyValue> tag contains a specification of a literal value and its associated XML schema type.
We can specify <jms:property> and <jms:propertyValue> extensions within the <wsdl:input> tag in the binding operation, and also within the <jms:address> tag. For the<wsdl:output> tag in the binding operation, we can only specify the <jms:property> extension. Property values that are set in the <jms:property> tag take precedence over values set in the <<jms:propertyValue> tag, and property values that are set in the binding operation (in the <input> and <output> tags) take precedence over values set in the <jms:address> tag.
Here is an example of the <jms:property> and <jms:propertyValue> tags nested within the <input> and <output> tags:
<wsdl:input ... > <jms:property name="propertyName" part="partName" /> <jms:propertyValue name="propertyName" type="xsdType" value="actualValue" /> </wsdl:input> <wsdl:output ... > <jms:property name="propertyName" part="partName" /> </wsdl:output>where propertyName identifies the JMS property associated with the header field, and partName identifies the message part associated with the property.
The JMS property identified by propertyName can be user-defined, or it can be one of the following predefined header fields:
Value Java type JMSMessageId java.lang.String JMSTimeStamp long JMSCorrelationId byte [ ] or java.lang.String JMSReplyTo javax.jms.Destination JMSDestination javax.jms.Destination JMSDeliveryMode int JMSRedelivered boolean JMSType java.lang.String JMSExpiration long JMSTimeToLive long See the JMS specification for restrictions that apply when setting JMS header field values. Attempts to set restricted values are ignored.
For application-defined JMS message properties, the Java types used in the native JMS binding implementation (used for calls to the corresponding JMS methods) are derived from the XML schema type in the abstract interface (<wsdl:part> tag), and from the type mapping information in the format binding (<format:typemap> tag).
- Handle transactions.
Independent of other JMS properties, the asynchronous processing of request-response operations has implications for callers running in a transaction scope. The send request part and the receive response part are separated into two transactions, because the send needs to be committed in order for the request message to become visible. Implementations that process WSDL for asynchronous request-response operations (such as WSIF) must therefore take the following additional actions:
- They must ensure that the send request transaction returns a correlation ID to the user, and provides a callback with which users can pass in the response message to process the receive response transaction.
- They might implement their own response message listener in order to recognize the arrival of response messages, and to manage the correlation to the request message.
Example 1: JMS Text Message
The JMS text message contains a java.lang.String. In this example, the WSDL message contains only one part that represents the whole message body:
<wsdl:definitions ... > <!-- simple or complex types for input and output message --> <wsdl:types> ... </wsdl:types> <wsdl:message name="JmsOperationRequest"> ... </wsdl:message> <wsdl:message name="JmsOperationResponse"> ... </wsdl:message> <wsdl:portType name="JmsPortType"> <wsdl:operation name="JmsOperation"> <wsdl:input name="Request" message="tns:JmsOperationRequest"/> <wsdl:output name="Response" message="tns:JmsOperationResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="JmsBinding" type="JmsPortType"> <jms:binding type="TextMessage" /> <format:typemapping style="Java" encoding="Java"> <format:typemap name="xsd:String" formatType="String" /> </format:typemapping> <wsdl:operation name="JmsOperation"> <wsdl:input message="JmsOperationRequest"> <jms:input parts="requestMessageBody" /> </wsdl:input> <wsdl:output message="JmsOperationResponse"> <jms:output parts="responseMessageBody" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="JmsService"> <wsdl:port name="JmsPort" binding="JmsBinding"> <jms:address destinationStyle="queue" jndiConnectionFactoryName="myQCF" jndiDestinationName="myDestination"/> </wsdl:port> </wsdl:service> </wsdl:definitions>As an extension to the previous JMS message example, the following example WSDL describes a request-response operation in which specific JMS property values of the request and response message are set for the request message and retrieved from the response message.
The JMS properties in the request message are set according to the values in the input message. Likewise, selected JMS properties of the response message are copied to the corresponding values of the output message. The direction of the mapping is determined by the appearance of the <jms:property> tag in the input or output section, respectively.
<wsdl:definitions ... > <!-- simple or complex types for input and output message --> <wsdl:types> ... </wsdl:types> <wsdl:message name="JmsOperationRequest"> <wsdl:part name="myInt" type="xsd:int"/> ... </wsdl:message> <wsdl:message name="JmsOperationResponse"> <wsdl:part name="myString" type="xsd:String"/> ... </wsdl:message> <wsdl:portType name="JmsPortType"> <wsdl:operation name="JmsOperation"> <wsdl:input name="Request" message="tns:JmsOperationRequest"/> <wsdl:output name="Response" message="tns:JmsOperationResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="JmsBinding" type="JmsPortType"> <!-- the JMS message type might be any of the preceding types --> <jms:binding type="..." /> <format:typemapping style="Java" encoding="Java"> <format:typemap name="xsd:int" formatType="int" /> ... </format:typemapping> <wsdl:operation name="JmsOperation"> <wsdl:input message="JmsOperationRequest"> <jms:property message="tns:JmsOperationRequest" parts="myInt" /> <jms:propertyValue name="myLiteralString" type="xsd:string" value="Hello World" /> ... </wsdl:input> <wsdl:output message="JmsOperationResponse"> <jms:property message="tns:JmsOperationResponse" parts="myString" /> ... </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="JmsService"> <wsdl:port name="JmsPort" binding="JmsBinding"> <jms:address destinationStyle="queue" jndiConnectionFactoryName="myQCF" jndiDestinationName="myDestination"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
Related:
WSIF and WSDL Writing the WSDL extension that lets the WSIF service access a SOAP over JMS service Enable a WSIF client to invoke a web service through JMS JMS message header: The TimeToLive property reference