Wednesday, 21 October 2015

Implementing SOAP Fault in Top Down Web Service


Step-1

A SOAP fault is an error in a SOAP (Simple Object Access Protocol) communication 

resulting from incorrect message format, header-processing problems, or incompatibility 

between applications.


























Define the detail message in XSD

<complexType name="ConsultantFaultMessage">
<sequence>
<element  name="name" type="string" minOccurs="1" maxOccurs="1">
</element>
<element  name="email" type="string" maxOccurs="1" minOccurs="1">
<annotation>
<documentation>email id of the consultants</documentation>
</annotation>
</element>

<element  name="mobile" type="string" maxOccurs="1" minOccurs="1">
<annotation>
<documentation>mobile id of the consultants</documentation>
</annotation>
</element>

<element  name="description" type="string" maxOccurs="1" minOccurs="1">
<annotation>
<documentation>description of error message</documentation>
</annotation>
</element>
</sequence>

</complexType>

Step-2
Define the element of above complex type inside XSD
    

<element name="ConsultantFaultMessage" type="tns:ConsultantFaultMessage"/>

Step-3
Associate this element with WSDL message

   <wsdl:message name="ConsultantFaultMessageException">
<wsdl:part name="tempFault" element="tns:ConsultantFaultMessage" />

  </wsdl:message>


Step-4
attached above message as soap fault element in PortType with operation
<wsdl:portType name="ConsultantWebService">
<wsdl:documentation>Creating contract for the soap web service
</wsdl:documentation>
      <wsdl:operation name="uploadConsultant">
      <wsdl:input message="tns:wconsultantRequest" />
     <wsdl:output message="tns:wconsultantResponse" />
      <wsdl:fault name="tConsultantFaultMessageException" message="tns:ConsultantFaultMessageException"/>
</wsdl:operation>

<wsdl:operation name="findAllConsultants">
<wsdl:input message="tns:wvoidRequest" />
<wsdl:output message="tns:wallConsultantsResponse" />
</wsdl:operation>

</wsdl:portType>

Step-5
Define above fault finally in binding tag
<wsdl:binding name="ConsultantWebServiceBinding" type="tns:ConsultantWebService">
<wsdl:documentation>
http://schemas.xmlsoap.org/soap/http- this fix for http protocol
</wsdl:documentation>
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="uploadConsultant">
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
<wsdl:fault name="tConsultantFaultMessageException">
<soap:fault name="tConsultantFaultMessageException"/>
</wsdl:fault>

</wsdl:operation>
</wsdl:binding>

Generate the SEI from above WSDL

 /**
     * 
     * @param pconsultant
     * @return
     *     returns java.lang.String
     * @throws ConsultantFaultMessageException
     */
    @WebMethod
    @WebResult(name = "sresponse", targetNamespace = "http://www.consultants.com/it", partName = "presponse")
    public String uploadConsultant(
        @WebParam(name = "consultantRequest", targetNamespace = "http://www.consultants.com/it", partName = "pconsultant")
        Consultant pconsultant)
        throws ConsultantFaultMessageException ;


@WebService(name = "ConsultantWebService", targetNamespace = "http://www.consultants.com/it",
endpointInterface = "com.consultants.it.ConsultantWebService", portName = "ConsultantWebServicePort", 
serviceName = "ConsultantWebServiceService")
@XmlSeeAlso({ ObjectFactory.class })
public class ConsultantWebServiceProvider implements ConsultantWebService {

public String uploadConsultant(Consultant pconsultant) throws ConsultantFaultMessageException {
if(pconsultant.getEid().equals("400")) {
ConsultantFaultMessage faultInfo=new ConsultantFaultMessage();
faultInfo.setDescription("This id is not acceptable at all.....");
faultInfo.setEmail(pconsultant.getEmail().get(0));
faultInfo.setMobile(pconsultant.getMobile().getVendor());
faultInfo.setName(pconsultant.getName());
ConsultantFaultMessageException consultantFaultMessageException=new ConsultantFaultMessageException("Id cannot be 400", faultInfo);
throw consultantFaultMessageException;
}
return "uploaded";

}


Soap Fault with response :-

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>Id cannot be 400</faultstring>
         <detail>
            <ConsultantFaultMessage:ConsultantFaultMessage xmlns:ConsultantFaultMessage="http://www.consultants.com/it" xmlns="http://www.consultants.com/it">
               <name>Nagendra</name>
               <email>nagendra@gmail.com</email>
               <mobile>Nokia</mobile>
               <description>This id is not acceptable at all.....</description>
            </ConsultantFaultMessage:ConsultantFaultMessage>
         </detail>
      </S:Fault>
   </S:Body>

</S:Envelope>


Tuesday, 20 October 2015

Deploying Metro endpoint

Before you deploy or publish your endpoint, you would need to package your endpoint applciation in to a WAR file. The requirements when building a WAR
  • All WSDLs, Schema files should be packaged under WEB-INF/wsdl dir. It is recommended that they need not be packaged when the service is started from Java

  • WebService implementation class should contain @WebService annotation. Provider based endpoints should have @WebServiceProvider annotation.

  • wsdl, service, port attributes are mandatory for Provider based endpoints and can be specified in @WebServiceProvider annotation or deployment descriptor (sun-jaxws.xml).

  • Deployment descriptors, web.xml, web services deployment descriptor (sun-jaxws.xml or 109 or spring)

The WAR Contents

        WEB-INF/classes/hello/HelloIF.class SEI
        WEB-INF/classes/hello/HelloImpl.class Endpoint
        WEB-INF/sun-jaxws.xml JAX-WS RI deployment descriptor
        WEB-INF/web.xml Web deployment descriptor
        WEB-INF/wsdl/HelloService.wsdl WSDL
        WEB-INF/wsdl/schema.xsd WSDL imports this Schema


Using sun-jaxws.xml

<?xml version="1.0" encoding="UTF-8"?>
    <endpoints
            xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
            version="2.0">
        <endpoint
                name="MyHello"
                implementation="hello.HelloImpl"
                url-pattern="/hello"/>
    </endpoints>




web.xml

<?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">

        <web-app>
            <listener>
                <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
            </listener>
            <servlet>
                <servlet-name>hello</servlet-name>
           <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
                <load-on-startup>1</load-on-startup>
            </servlet>
            <servlet-mapping>
                <servlet-name>hello</servlet-name>
                <url-pattern>/hello</url-pattern>
            </servlet-mapping>
            <session-config>
                <session-timeout>60</session-timeout>
            </session-config>
        </web-app>
        


Using MTOM to optimize binary data transfer with JAX-WS web services

Reference : - http://www.codejava.net/java-ee/web-services/using-mtom-to-optimize-binary-data-transfer-with-jax-ws-web-services

By default, binary data is converted to base64Binary or hexBinary XML data type within a SOAP envelope, meaning that the raw bytes are encoded as a String using base64 technique. For example, the following XML snippet is content of such a SOAP message:

<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:upload xmlns:ns2="http://server.mtom.ws.codejava.net/">
            <arg0>binary.png</arg0>
            <arg1>iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoL...5CYII=</arg1>
        </ns2:upload>
    </S:Body>
</S:Envelope>


Look at the text inside the element <arg1> - it is the encoded form of the binary data in base64 format. Basically, the base64 encoding technique bloats the original data by a factor of 1.33x (with UTF-8 encoding) or 2.66x (with UTF-16), so it becomes very inefficient when dealing with a large amount of data. To overcome this drawback, MTOM is defined as a specification for optimizing the transmission of this kind of data type in SOAP messages, and XOP (XML-binary Optimized Packaging) is the concrete implementation. The following example is content of a HTTP POST request which is generated by MTOM/XOP:

Enabling MTOM in JAX-WS

In JAX-WS, it’s easy to enable MTOM for a web service endpoint by using either the @MTOM or @BindingTypeannotations. At the client side, MTOM can be enabled either by passing a new instance of MTOMFeature class when getting a reference to the web service endpoint (port), or by calling theSOAPBinding.setMTOMEnabled(true) method on the binding provider object. Here are the usages and examples in details.

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.soap.MTOM;
 
 
@WebService
@MTOM
public class FrogWebService {
     
    @WebMethod
    public void uploadFrogPhoto(byte[] data) {
        // implementation details...   
    }
}




That enables MTOM support for the MyWebService endpoint. The @MTOM annotation has two optional parameters:
  • enabled: specifies whether MTOM feature is enabled (true) or disabled (false).
  • threshold: specifies the size (in bytes) above which the binary data will be sent as attachment. This would be useful to enable MTOM only for data which is larger than a specified amount.



@WebService
@MTOM(enabled = false)
public class FrogWebService {
}


This example shows MTOM is enabled only for binary data which is larger than 12222 bytes:
1
2
3
4

@WebService
@MTOM(threshold = 12222)
public class FrogWebService {
}
An alternative way is using the @BindingType annotation with an appropriate value for the SOAP version used. For example:
  • Enabling MTOM with SOAP version 1.1:
    1
    2
    3
    4
    5
    6
    7
    import javax.xml.ws.BindingType;
    import javax.xml.ws.soap.SOAPBinding;
     
    @WebService
    @BindingType(value = SOAPBinding.SOAP11HTTP_MTOM_BINDING)
    public class MyWebService {
    }
  • Enabling MTOM with SOAP version 1.2:
    1
    2
    3
    4
    5
    6
    7
    import javax.xml.ws.BindingType;
    import javax.xml.ws.soap.SOAPBinding;
     
    @WebService
    @BindingType(value = SOAPBinding.SOAP12HTTP_MTOM_BINDING)
    public class MyWebService {
    }

Enabling MTOM for the client
The following example shows how to enable MTOM at the client by passing a new instance of the MTOMFeatureclass when getting a proxy reference the web service endpoint:
1
2
3
4
import javax.xml.ws.soap.MTOMFeature;
 
MyWebServiceService service = new MyWebServiceService();
MyWebService port = service.getMyWebServicePort(new MTOMFeature());
Suppose that the MyWebServiceService and MyWebService classes are generated by the wsimport tool. And similar to the @MTOM annotation, we can also specify the enabled and threshold parameters in the MTOMFeatureclass’ constructor like this:
1
2
3
boolean enabled = true;
int threshold = 10240;
MyWebService port = service.getMyWebServicePort(new MTOMFeature(enabled, threshold));
And here’s an alternative way, calling the SOAPBinding.setMTOMEnabled(true) method:
1
2
3
4
5
6
MyWebServiceService service = new MyWebServiceService();
MyWebService port = service.getMyWebServicePort();
 
BindingProvider provider = (BindingProvider) port;
SOAPBinding soapBinding = (SOAPBinding) provider.getBinding();
soapBinding.setMTOMEnabled(true);