Senthadev

{ Think. Ask Why. Do it. }


Using JBossWS to implement SOAP with attachment (SwA)

Recently I was developing a prototype to send MMS (Multimedia Messaging Service) messages to the end user mobiles from our web server. Typically I have to use an operator API to do this and that API is built according the MM7 protocol standards. MM7 protocol is defined by 3GPP and it says to use SOAP with attachment when communicating with the service provider. This article will focus as a service provider to implement the SOAP with attachment service.

Simply, SOAP with attachment (SWA) is one of the way to attach data (binary/plain) along with SOAP message as reference. There are many open source web service stack supports SWA for example Axis2, GlassFish Metro (previously known as JWSDP) and JbossWS. These web service stack implements many JSR like JAXB etc. (refer Java EE 5/6 web service specification). Here I will use the JbossWS to implement the SWA and I have used Java 6 and Jboss 4.2.3 GA. Java 6 already includes the web service stack in the SDK. By using the jboss lib endorsed directory we will use the jboss web service implementation.

Let me create a simple web service which accepts a MM7 message and log the details in the console. Real business scenario would be to process the MM7 message and submits to the operators MMSC. Our aim is to look at the steps rather than real business requirement :) .

  • Lets define a simple MM7 class which accepts any type of attachment.

package com.sentha.service;

import javax.activation.DataHandler;
import javax.xml.bind.annotation.XmlAttachmentRef;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class MM7 {
    private int transId;
    private String receiver;
    private String sender;
    private String text;
    private DataHandler attachment;

    public int getTransId() {
        return transId;
    }
    public void setTransId(int transId) {
        this.transId = transId;
    }
    public String getReceiver() {
        return receiver;
    }
    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }
    public String getSender() {
        return sender;
    }
    public void setSender(String sender) {
        this.sender = sender;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    @XmlElement
    @XmlAttachmentRef
    public DataHandler getAttachment() {
        return attachment;
    }
    public void setAttachment(DataHandler attachment) {
        this.attachment = attachment;
    }
}


Using JAXB, I have annotated MM7 as a xml root element and property “attachment” as a xml attachment reference which will be containing the data in this case it will be a image file.

  • Now, we define the interface for the web service.

package com.sentha.service;

public interface MM7Endpoint {

    public String pushMMS(MM7 mm7message);
}

  • Now we define the implementation class which implements the MM7EndPoint.

package com.sentha.service;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;

import org.apache.log4j.Logger;

@WebService(name="MM7Endpoint",
targetNamespace="http://www.senthadev.com/mm7",
serviceName="MM7Service")
@SOAPBinding(style=Style.DOCUMENT, use=Use.LITERAL, parameterStyle=ParameterStyle.BARE)
public class MM7EndpointImpl implements MM7Endpoint{

private static final Logger log = Logger.getLogger(MM7EndpointImpl.class);

@WebMethod
public String pushMMS(MM7 mm7message) {
    if (mm7message == null){
        return "No mms message received..";
    }

    log.info("MMS message received from client");
    log.info("MMS TransId=" + mm7message.getTransId());
    log.info("MMS Receiver=" + mm7message.getReceiver());
    log.info("MMS Sender=" + mm7message.getSender());
    log.info("MMS Text=" + mm7message.getText());
    log.info("MMS Attachement mime content type=" + mm7message.getAttachment().getContentType());

    return "MMS has been pushed to MMSC";
}
}

This class will be used by JbossWS to handle the client request and generate the WSDL. Lets look into it.
@WebWebService = defines the web service endpoint details such as name, target name space etc.
@SOAPBinding = defines that the web service style is document/literal based.
@WebMethod = states that this operation which can be invoked by client.
Operation “pushMMS” accepts a MM7 as a parameter and returns the status as String. And it will print the received MM7 object details along with the attachment’s content type.

  • Now we have to publish this web service. Thats the easy part :)

We declare the class ‘MM7EndpointImpl’ as a Servlet in the web.xml. This servlet will accept POST request only.


<servlet>
<servlet-name>MM7Endpoint</servlet-name>
<servlet-class>com.sentha.service.MM7EndpointImpl</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>MM7Endpoint</servlet-name>
<url-pattern>/mm7</url-pattern>
</servlet-mapping>


We can access the service in following url:

http://www.senthadev.com:8080/testmms/mm7

URL pattern and the web context can also specified as annotation, but I like to use the web.xml and jboss.xml to define them.

When we call ‘http://www.senthadev.com:8080/testmms/mm7?wsdl’, jboss will automatically generate the WSDL using the MM7EndpointImpl class definition.
Following code shows how the MM7 class is defined in the WSDL


<xs:complexType name='mm7'>
<xs:sequence>
<xs:element minOccurs='0' name='attachment' type='swaRef:swaRef'/>
<xs:element minOccurs='0' name='receiver' type='xs:string'/>
<xs:element minOccurs='0' name='sender' type='xs:string'/>
<xs:element minOccurs='0' name='text' type='xs:string'/>
<xs:element name='transId' type='xs:int'/>
</xs:sequence>

parameter “attachement” is defined as a “swaRef:swaRef”, means attachment will be attached to the soap message. And it will be referred in the soap message by using the content id. Therefore we don’t need to pack the large data in the soap message.

  • To test the soap service, we can use the soap ui tool.

This is SOAP request in raw level


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mm7="http://www.senthadev.com/mm7">
<soapenv:Header/>
<soapenv:Body>
<mm7:pushMMS>
<attachment>cid:Norway.gif</attachment>
<receiver>47xxxxxx</receiver>
<sender>testsoap</sender>
<text>Guess what</text>
<transId>100</transId>
</mm7:pushMMS>
</soapenv:Body>
</soapenv:Envelope>

------=_Part_0_14396291.1316730309616
Content-Type: image/gif; name=Norway.gif
Content-Transfer-Encoding: binary
Content-ID: Norway.gif>
Content-Disposition: attachment; name="Norway.gif"; filename="Norway.gif"
.. data in base64
------=_Part_0_14396291.1316730309616--


  • Following sample output is printed on the server side when we submit the soap request


[MM7EndpointImpl] MMS message received from client
[MM7EndpointImpl] MMS TransId=100
[MM7EndpointImpl] MMS Receiver=47xxxxxx
[MM7EndpointImpl] MMS Sender=testsoap
[MM7EndpointImpl] MMS Text=Guess what
[MM7EndpointImpl] MMS Attachement mime content type=image/gif; name=Norway.gif


  • I have used following web site to study more about the SWA

http://docs.jboss.org/jbossas/6/WebServices_Guide/en-US/html_single/
http://community.jboss.org/wiki/JBossWS-SecurityAndAttachmentsSample
http://www.ibm.com/developerworks/webservices/library/ws-tip-swaref/index.html
http://www.soapui.org/SOAP-and-WSDL/adding-headers-and-attachments.html
http://www.coderanch.com/how-to/java/WebServicesFaq
http://wiki.apache.org/ws/StackComparison

2011-09-23
By @Senthadev