Skip navigation
2011

Why Soap Header and Spring Interceptor

 

  • SOAP Header element can contain additional application-specific information such as  authentication, payment about the SOAP
  • Spring web service interceptor allows you to extract the header information

 

Steps to develop Spring WS with JAXB and Spring Interceptor:

 

 

  • Create WSDL service contract
  • Generate the JAXB Java classes from the xml schema file
  • Create Java Endpoint classes
  • Define and wire Endpoint in Spring context file
  • Compile, package and deploy the code to Tomcat
  • Test the code: “http://localhost:8080/holiday/holiday.wsdl”

 

Create the WSDL contract

 

<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://mycompany.hr.com/hr/v1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://mycompany.hr.com/hr/v1" targetNamespace="http://mycompany.hr.com/hr/v1">

  <wsdl:types>

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://mycompany.hr.com/hr/v1">

      <xs:element name="HolidayRequest" xmlns:xs="http://www.w3.org/2001/XMLSchema">

            <xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">

                  <xs:sequence xmlns:xs="http://www.w3.org/2001/XMLSchema">

                        <xs:element name="EmployeeName" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>

                        <xs:element name="StartDate" type="xs:date" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>

        <xs:element name="EndDate" type="xs:date" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>

                  </xs:sequence>

            </xs:complexType>

      </xs:element>

      <xs:element name="HolidayResponse" xmlns:xs="http://www.w3.org/2001/XMLSchema">

            <xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">

                  <xs:sequence xmlns:xs="http://www.w3.org/2001/XMLSchema">

                        <xs:element name="Answer" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>

                  </xs:sequence>

            </xs:complexType>

      </xs:element>

       <xs:element name="HolidayRequestHeader" xmlns:xs="http://www.w3.org/2001/XMLSchema">

            <xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">

                  <xs:sequence xmlns:xs="http://www.w3.org/2001/XMLSchema">

                         <xs:element name="requestTimestamp" type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> 

                  </xs:sequence>

            </xs:complexType>

      </xs:element>

  

</xs:schema>

  </wsdl:types>

  <wsdl:message name="HolidayRequest">

    <wsdl:part element="tns:HolidayRequest" name="HolidayRequest">

    </wsdl:part>

  </wsdl:message>

  <wsdl:message name="HolidayResponse">

    <wsdl:part element="tns:HolidayResponse" name="HolidayResponse">

    </wsdl:part>

  </wsdl:message>

   <wsdl:message name="HolidayHeader">

    <wsdl:part element="tns:HolidayRequestHeader" name="HolidayHeader">

    </wsdl:part>

  </wsdl:message>

  <wsdl:portType name="holiday">

    <wsdl:operation name="Holiday">

      <wsdl:input message="tns:HolidayRequest" name="HolidayRequest">

    </wsdl:input>

      <wsdl:output message="tns:HolidayResponse" name="HolidayResponse">

    </wsdl:output>

    </wsdl:operation>

  </wsdl:portType>

  <wsdl:binding name="holidaySoap11" type="tns:holiday">

    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

    <wsdl:operation name="Holiday">

      <soap:operation soapAction=""/>

      <wsdl:input name="HolidayRequest">

        <soap:header message="tns:HolidayHeader" part="HolidayHeader" use="literal" />

        <soap:body use="literal"/>

      </wsdl:input>

      <wsdl:output name="HolidayResponse">

        <soap:body use="literal"/>

      </wsdl:output>

    </wsdl:operation>

  </wsdl:binding>

  <wsdl:service name="holidayService">

    <wsdl:port binding="tns:holidaySoap11" name="holidaySoap11">

      <soap:address location="http://localhost:8080/holiday/"/>

    </wsdl:port>

  </wsdl:service>

</wsdl:definitions>

 

 

  • This  service exposes “HolidayRequest” and returns “HolidayResponse”
  • This  service defines  “HolidayRequestHeader” Soap Header element

    

 

 

 

 

 

 

 

 

 

Generate JAXB Java classes from the schema file

 

 

 

Executing “xjc -p com.mycompany.hr.jaxb.holidayService hr.xsd” will generate the following classes:

 

  • com\mycompany\hr\jaxb\holidayService\HolidayRequest.java
  • com\mycompany\hr\jaxb\holidayService\HolidayResponse.java
  • com\mycompany\hr\jaxb\holidayService\HolidayRequestHeader.java
  • com\mycompany\hr\jaxb\holidayService\ObjectFactory.java
  • com\mycompany\hr\jaxb\holidayService\package-info.java

    

 

Create Java Endpoint

 

 

 

package com.mycompany.hr.ws;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import com.mycompany.hr.jaxb.holidayService.HolidayRequest;
import com.mycompany.hr.jaxb.holidayService.HolidayResponse;

@Endpoint
public class HolidayEndpoint {

 

@PayloadRoot(localPart= "HolidayRequest", namespace="http://mycompany.hr.com/hr/v1")
  public HolidayResponse serveRequest(HolidayRequest request){
   HolidayResponse  response = new HolidayResponse();
     response.setAnswer("Approved");
  return response;
}

}

 

  • Spring @PayloadRoot annotation instructs Spring to map xml “HolidayRequest” to “serveRequest” Java method. 
  • The serveRequest method returns a HolidayResponse object

    

 

Define Spring WS Interceptor

 

 

public class HolidayInterceptor implements SoapEndpointInterceptor {

 

                private static final Log logger = LogFactory.getLog(HolidayInterceptor.class);

                private Jaxb2Marshaller marshaller;

               

                public boolean understands(SoapHeaderElement header) {

                                boolean u = header.getName().getNamespaceURI()

                                                                .equalsIgnoreCase("http://mycompany.hr.com/hr/v1");

                                return u;

                }

               

                public boolean handleRequest(MessageContext messageContext, Object endpoint)

                                                throws Exception {

 

                                SoapMessage soapMsg = (SoapMessage) messageContext.getRequest();

                                SoapHeader soapHeader = soapMsg.getSoapHeader();

                                Iterator<SoapHeaderElement> iter = soapHeader.examineAllHeaderElements();

                                boolean found= false;

                                while (iter.hasNext() & (!found)) {

                                                SoapHeaderElement she = (SoapHeaderElement) iter.next();

                                                if (understands(she)) {

                                                                // Process the header

                                                                process(she);      

                                                                found =true;                         

                                                }

                                }

                                if(found)

                                {

                                                return true;

                                }

                                else

                                {

                                                Exception ex= new Exception();

                                                throw ex;

                                }    

                }

 

                private void process(SoapHeaderElement she) {

                               

                                DOMResult result = (DOMResult)she.getResult();

                                Node node=  result.getNode();        

                                DOMSource ds= new DOMSource(node);

                                HolidayRequestHeader RequestHeader = (HolidayRequestHeader)marshaller.unmarshal(ds);

                                logger.debug("request time: "+RequestHeader.getRequestTimestamp());

                               

                }

               

 

  • The handleReques method  extracts HolidayRequestHeader object from soap header

 

     

 

 

 

 

 

Define and wire Endpoint in Spring

 

 

 

 

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

 

 

 

      <bean id="holiday" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">

<property name="wsdl" value="classpath:holiday.wsdl" />

    </bean> 

 

 

  <bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">

<property name="xsd" value="classpath:hr.xsd" />

    </bean>

 

<!-- Register PayloadRootAnnotationMethodEndpointMapping -->

    <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" >

                <property name="interceptors">

                                <list merge="true">             

                                                                <ref bean="holiday.interceptor"/>

                </list>

        </property>

    </bean>

 

 

  <bean  name="holiday.interceptor"

        class="com.mycompany.hr.interceptor.HolidayInterceptor"  >

        <property name="marshaller" ref="marshaller" />

       

   </bean>

   

    <!-- Register Endpoint -->

    <bean id="HolidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint">

    <description>

          

        </description>

    </bean> 

 

    

   

    <!-- Configure XML Marshaller -->

<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">

    <constructor-arg ref="marshaller" />

</bean> 

 

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">

    <property name="classesToBeBound">

        <list>

            <value>com.mycompany.hr.jaxb.holidayService.HolidayRequest</value>

            <value>com.mycompany.hr.jaxb.holidayService.HolidayResponse</value>

            <value>com.mycompany.hr.jaxb.holidayService.HolidayRequestHeader</value>

        </list>

    </property>

</bean>

</beans>

  • Spring bean “HolidayEndpoint” defines the end point mapping
  • Spring bean  “marshaller” un-marshalls the xml requests to Java objects and marshalls the response objects to xml response

Source code and war files are attached.

 

Deploy the code to Tomcat and let me what happened