Showing posts with label Web Services. Show all posts
Showing posts with label Web Services. Show all posts

Thursday, March 1, 2012

Friday, November 11, 2011

Enabling Proxy server for CXF Client

If you ever have the need to enable proxy server for a CXF based webservice client, this is the way to go about it:

Assuming a Spring based application, add this new namespace to the Spring configuration file:

 xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
....
 xsi:schemaLocation="...
    http://cxf.apache.org/transports/http/configuration
    http://cxf.apache.org/schemas/configuration/http-conf.xsd">
...



Now, if all outbound requests are via a proxy server then make the following entry in your Spring configuration:

 <http-conf:conduit name="*.http-conduit">
  <http-conf:client ProxyServer="${proxy.server}" ProxyServerPort="${proxy.port}" />  
 </http-conf:conduit>

If you need to disable the proxy server, just provide an empty proxy.server parameter.

If you need to enable it only for specific WS requests, then the conduit name has to be modified to the specific services portType:
http-conf:conduit name="{http://apache.org/hello_world_soap_http}SoapPort.http-conduit"

More information here.

Wednesday, October 19, 2011

SOAP-Fault for a Contract First service using Spring-WS

This is a follow up to the simple webservice described in this post

Just to recap, my webservice was responsible for returning the details of a "member" given the identifier for the member. If a member was not found for the identifier, the service did not return a member.

For this request, which matches a member in the system:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mem="http://bk.org/memberservice/">
   <soapenv:Header/>
   <soapenv:Body>
      <mem:MemberDetailsRequest xmlns:mem="http://bk.org/memberservice/">
         <mem:id>1</mem:id>
      </mem:MemberDetailsRequest>
   </soapenv:Body>
</soapenv:Envelope>

this is the response:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <ns2:MemberDetailsResponse xmlns:ns2="http://bk.org/memberservice/">
         <ns2:memberdetail>
            <ns2:id>1</ns2:id>
            <ns2:name>john doe</ns2:name>
            <ns2:phone>111-111-1111</ns2:phone>
            <ns2:city>City</ns2:city>
            <ns2:state>State</ns2:state>
         </ns2:memberdetail>
      </ns2:MemberDetailsResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


and for a case where there is no match, this is the response:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <ns2:MemberDetailsResponse xmlns:ns2="http://bk.org/memberservice/"/>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Now, what I want to do is, instead of giving a response of this form, I want my contract to explicitly declare a Fault, in case a member is not found.

There are a couple of different ways of doing it.

The first way is to simply throw a RuntimeException, this would be trapped by the Spring-WS stack(using a SimpleFaultMessageResolver) and returned as a Soap fault.
So now my endpoint implementation is:
...
@Endpoint
public class GetMemberDetailsEndpoint {
 @Autowired private MemberManager memberManager;

 @PayloadRoot(namespace = "http://bk.org/memberservice/", localPart = "MemberDetailsRequest")
 @ResponsePayload
 public MemberDetailsResponse getMemberDetails(@RequestPayload MemberDetailsRequest request) throws Exception {
  MemberDetail memberDetail = memberManager.findByMemberId(request.getId());
  if (memberDetail==null){
   throw new RuntimeException("Member Not Found");
  }
  MemberDetailsResponse response = new MemberDetailsResponse(memberDetail);
  return response;

 }
...

and the response for a case where a member is not found is a clean Soap fault with the message set in the exception as the fault detail:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Server</faultcode>
         <faultstring xml:lang="en">Member Not Found</faultstring>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


The second way is to define a custom exception class, and throw this custom exception from the endpoint:
@PayloadRoot(namespace = "http://bk.org/memberservice/", localPart = "MemberDetailsRequest")
 @ResponsePayload
 public MemberDetailsResponse getMemberDetails(@RequestPayload MemberDetailsRequest request) throws Exception {
  MemberDetail memberDetail = memberManager.findByMemberId(request.getId());
  if (memberDetail==null){
   throw new MemberDetailsFault("Member Not Found");
  }
  MemberDetailsResponse response = new MemberDetailsResponse(memberDetail);
  return response;

 }

and define a resolver, which will map exceptions of this new type(MemberDetailsFault) to a more descriptive text:
<bean class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
        <property name="defaultFault" value="SERVER"/>
        <property name="exceptionMappings">
            <value>
                org.bk.memberservice.message.MemberDetailsFault=SERVER,No Member-message from application context
            </value>
        </property>
    </bean> 

the exceptionresolver is discovered by type, so there is no need to give the bean a name. With this in place, the Soap fault, will have the fault detail based on the exceptionMapping:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Server</faultcode>
         <faultstring xml:lang="en">No Member-message from application context</faultstring>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

A third way, is to annotate the custom exception class with a @SoapFault annotation, describing the exception to be returned as part of the faultdetail:
@SoapFault(faultCode = FaultCode.SERVER, faultStringOrReason = "No Member Found - From @SoapFault annotation")
public class MemberDetailsFault extends RuntimeException{


A new resolver is required to interpret exception with annotations to a Soap Fault, SoapFaultAnnotationExceptionResolver:
<bean class="org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver"/>

With this in place, the response is:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Server</faultcode>
         <faultstring xml:lang="en">No Member Found - From @SoapFault annotation</faultstring>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

I personally prefer the third approach, it is a little more concise.

Sample available at this location: git://github.com/bijukunjummen/memberservice-contractfirst.git

Monday, June 20, 2011

Writing Integration tests for Spring WS endpoints

Writing Integration tests for Spring WS endpoints is easy, based on this resource from Spring-WS reference site. Spring WS provides a MockWebServiceClient class to test the Spring-WS endpoints.

My endpoint has the following signature:


@Endpoint
public class GetMemberDetailsEndpoint {

 @Resource private MemberManager memberManager;

 @PayloadRoot(namespace = "http://bk.org/memberservice/", localPart = "MemberDetailsRequest")
 @ResponsePayload
 public MemberDetailsResponse getMemberDetails(@RequestPayload MemberDetailsRequest request) throws Exception {
  MemberDetail memberDetail = memberManager.findByMemberId(request.getId());
                ......
 }

I have a memberManager bean dependency in my endpoint, I mock this up using easymock first:
<bean name="memberManager" class="org.easymock.EasyMock" factory-method="createMock">
  <constructor-arg value="org.bk.memberservice.service.MemberManager"/>
 </bean>

this way Spring will wire it to the endpoint when starting up the bean factory. Record the easymock with appropriate expectations:
MemberDetail memberDetail = new MemberDetail("john doe", "111-111-1111", "City", "State");
        memberDetail.setId(1L);
        expect(memberManager.findByMemberId(1L)).andReturn(memberDetail);
        replay(memberManager);

Initialize MockWebserviceClient, set up the test:
mockClient = MockWebServiceClient.createClient(applicationContext);
        Source requestPayload = new StringSource(
                "<mem:MemberDetailsRequest xmlns:mem=\"http://bk.org/memberservice/\">"
                        + "<mem:id>1</mem:id>" 
                        + "</mem:MemberDetailsRequest>");
        Source responsePayload = new StringSource(
                "<ns3:MemberDetailsResponse xmlns:ns3=\"http://bk.org/memberservice/\">"
          + "<memberDetail>" 
          + "<id>1</id>"
          + "<name>john doe</name>"
          + "<phone>111-111-1111</phone>"
          + "<city>City</city>"
          + "<state>State</state>"
          + "</memberDetail>"
      + "</ns3:MemberDetailsResponse>");

        mockClient.sendRequest(withPayload(requestPayload)).andExpect(payload(responsePayload));
        verify(this.memberManager);
This completes the test, MockWebserviceClient would take care of packaging up the raw xml request, dispatching it the appropriate WS endpoint, getting the response and validating it. Updated codesample with integration test available at: git://github.com/bijukunjummen/memberservice-contractfirst.git

Saturday, June 18, 2011

Supporting Spring-WS and Spring MVC integration in a project

Spring WS and Spring MVC provide different front controller implementations as a gateway to the webservice and the MVC functionality respectively. The Dispatcher Servlet used by Spring-WS is :

org.springframework.ws.transport.http.MessageDispatcherServlet
and the one used by Spring MVC is :
org.springframework.web.servlet.DispatcherServlet
To have a combined Spring MVC and Spring-WS project, it is possible to configure these front controllers based on the URI pattern of the request, in the following way:
<servlet>
        <servlet-name>member-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/META-INF/spring/applicationContext-ws.xml</param-value>
        </init-param>
    </servlet>
    
    <servlet>
        <servlet-name>member-web</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
        </init-param>
    </servlet>    

    <servlet-mapping>
        <servlet-name>member-ws</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
        <servlet-name>member-ws</servlet-name>
        <url-pattern>*.wsdl</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
        <servlet-name>member-web</servlet-name>
        <url-pattern>/web/*</url-pattern>
    </servlet-mapping>    


In this specific instance, all requests to /web/ is handled by the Spring MVC DispatcherServlet whereas all requests to /services is handled by Spring-WS DispatcherServlet. Further, each dispatcher servlet is configured with its custom Spring configuration file, the one for Spring MVC loads up the contollers, the one for Spring WS loads up the Webservice endpoints.

I am not sure if this is a optimal configuration, but it works for me in this project available at: git://github.com/bijukunjummen/memberservice-contractfirst.git


OR An alternate way to hook up DispatcherServlet to handle Spring-WS requests is described here!: http://static.springsource.org/spring-ws/sites/2.0/reference/html/server.html#d4e884

Sunday, May 22, 2011

Enabling WS-Security Username Token Profile for Apache CXF service

This article describes how to create a code first webservice. I am going to extend the sample provided to support WS-Security Username Token profile. It is a way for the callers of the service to prove their identity by providing username and a password.

To recap the previous article, it is very simple to expose a code first webservice using Apache CXF with Spring. Apache CXF provides a custom Spring namespace to easily configure the endpoint:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jaxws="http://cxf.apache.org/jaxws"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

 <import resource="classpath:META-INF/cxf/cxf.xml"/>
 <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
 

 <bean id="memberendpoint" class="org.bk.memberservice.endpoint.DefaultMemberEndpoint"/>
 
 <jaxws:endpoint address="/memberservice" id="memberservicehttp" implementor="#memberendpoint" >
 </jaxws:endpoint>

</beans>

This exposes the memberendpoint bean above as a fully configured webservice.

To secure this service using usernametoken, first implement a callback for CXF to invoke to validate the credentials passed by the user:

package org.bk.memberservice.endpoint;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class UsernameTokenCallback implements CallbackHandler {

 @Override
 public void handle(Callback[] callbacks) throws IOException,
   UnsupportedCallbackException {
  Callback callback = callbacks[0];
  WSPasswordCallback pc = (WSPasswordCallback) callback;
//              Retrieve and set the real password..which will be validated 
//              by CXF validator against the digest password
pc.setPassword("test");
  System.out.println("Received cred: " + pc.getIdentifier() + " : " + pc.getPassword());
//  validate the credentials
//              boolean isValid = true;
//              throw IO Exception if the credentials are not valid
//  if (!isValid) {
//   throw new IOException("Bad Credentials");
//  }
 }
}

To wire this Callback handler with the service endpoint, CXF uses a concept called the interceptor, basically the webservice call is handled by the interceptors before being handed over to the service.


<jaxws:endpoint address="/memberservice" id="memberservicehttp"
  implementor="#memberendpoint">
  <jaxws:inInterceptors>
   <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
    <constructor-arg>
     <map>
      <entry key="action" value="UsernameToken" />
      <entry key="passwordType" value="PasswordDigest" />
      <entry key="passwordCallbackRef">
       <ref bean="usernameTokenCallback" />
      </entry>
     </map>
    </constructor-arg>
   </bean>
  </jaxws:inInterceptors>
 </jaxws:endpoint>

That's it!! the endpoint is now secured using UsernameToken profile. To test this, bring up the endpoint, use SOAP UI to send a normal request, it will fail with the message that a ws-security header is required - this is the username token soap header that is expected as part of the request.

 Fix this by adding the username and password, select "digest" as the password type and the service invocation should just work.
Updated Sample available at: git://github.com/bijukunjummen/memberservice-codefirst.git
Reference:
1. WS-Security reference in Wikipedia: http://en.wikipedia.org/wiki/WS-Security
2. WS-Secuirty usernametoken profile specs at OASIS: http://www.oasis-open.org/committees/download.php/16782/wss-v1.1-spec-os-UsernameTokenProfile.pdf
3. Apache CXF reference: http://cxf.apache.org/docs/ws-security.html
4. New changes as part of WSS4J - http://coheigea.blogspot.com/2011/02/wspasswordcallback-changes-in-wss4j-16.html


Saturday, May 14, 2011

Sample Contract First Service using Spring-WS 2.0

I have now updated the sample for this article, to use Spring WS 2.0, which now provides a annotation based model for Webservice endpoints. The amount of configuration required to define a Webservice endpoint has reduced considerably between Spring WS 1.x and Spring WS 2.0  - most of the routine boilerplate to define an endpoint has moved from configuration to an annotation:
Whereas earlier, the endpoint would have been defined by a code of the following signature:
public class GetMemberDetailsEndpoint extends
  AbstractMarshallingPayloadEndpoint {
 private MemberManager memberManager;
 protected Object invokeInternal(Object requestObject) throws Exception {
  MemberDetailsRequest request = (MemberDetailsRequest) requestObject;
  MemberDetail memberDetail = memberManager.getMemberDetails(request
    .getId());
  MemberDetailsResponse response = new MemberDetailsResponse(memberDetail);
  return response;
 }

......
}
With Spring-WS 2.0 the endpoint can be more intuitively defined with the following signature:
@Endpoint
public class GetMemberDetailsEndpoint {

 @Autowired private MemberManager memberManager;

 @PayloadRoot(namespace = "http://bk.org/memberservice/", localPart = "MemberDetailsRequest")
 @ResponsePayload
 public MemberDetailsResponse getMemberDetails(@RequestPayload MemberDetailsRequest request) throws Exception {
  MemberDetail memberDetail = memberManager.getMemberDetails(request
    .getId());
  MemberDetailsResponse response = new MemberDetailsResponse(memberDetail);
  return response;

 }

.....

}
Updated code available at:
git://github.com/bijukunjummen/memberservice-contractfirst.git

Contract First and Code First Webservice Development

There are generally two styles for Webservice Development - Contract First and Code First.

Contract First is an approach where the developer starts from defining a contract for the webservice using a WSDL and then goes about generating/developing the codebase - typically using stacks that allow code to be generated from the wsdl.

Code First on the other hand is an approach where the developer starts by defining an interface, then generates the contract for the webservice using tools that allow translating an interface to wsdl.

I have used both approaches now for different projects over time and but am not very opinionated about either of the approaches. A purist approach would be to start with the contract, which I have personally advocated in the past, however in some real world projects I have tended to go with a code first approach, for a few reasons:

  1. Good tool support is required to define a reasonably involved wsdl - Eclipse is not good enough to create a quality wsdl - I would recommend IBM RAD or XML Spy for creating wsdl's
  2. A very deep knowledge of XML schema language is required to generate good constructs
  3. Development time is generally slower -  as creating a wsdl takes a good amount of time


Code First Approach on the other hand is quick. Let me illustrate by changing my DZone Example which is a Contract First example to a Code First using Apache CXF:

The contract for the service was:
<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ms="http://bk.org/memberservice/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="memberservice" targetNamespace="http://bk.org/memberservice/">
 <wsdl:types>
  <xsd:schema targetNamespace="http://bk.org/memberservice/" elementFormDefault="qualified">
   <xsd:complexType name="MemberDetailType">
    <xsd:sequence>
     <xsd:element name="name" type="xsd:string"/>
     <xsd:element name="phone" type="xsd:string"/>
     <xsd:element name="city" type="xsd:string"/>
     <xsd:element name="state" type="xsd:string"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="MemberDetailsRequest">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="id" type="xsd:string"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="MemberDetailsResponse">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="memberdetail" type="ms:MemberDetailType"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
  </xsd:schema>
 </wsdl:types>
 <wsdl:message name="MemberDetailsRequest">
  <wsdl:part element="ms:MemberDetailsRequest" name="parameters"/>
 </wsdl:message>
 <wsdl:message name="MemberDetailsResponse">
  <wsdl:part element="ms:MemberDetailsResponse" name="parameters"/>
 </wsdl:message>
 <wsdl:portType name="memberservice">
  <wsdl:operation name="GetMemberDetails">
   <wsdl:input message="ms:MemberDetailsRequest"/>
   <wsdl:output message="ms:MemberDetailsResponse"/>
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="memberserviceSOAP" type="ms:memberservice">
  <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
  <wsdl:operation name="GetMemberDetails">
   <soap:operation soapAction="http://bk.org/memberservice/GetMemberDetails"/>
   <wsdl:input>
    <soap:body use="literal"/>
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal"/>
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="memberservice">
  <wsdl:port binding="ms:memberserviceSOAP" name="memberserviceSOAP">
   <soap:address location="http://localhost:8081/memberservice/services/MemberDetailsRequest"/>
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>

Let us start by defining a java interface that can sufficiently mimic this WSDL:
package org.bk.memberservice.endpoint;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

import org.bk.memberservice.message.MemberDetailsRequest;
import org.bk.memberservice.message.MemberDetailsResponse;

@WebService
public interface MemberEndpoint {
 @WebMethod(operationName = "MemberDetailsRequest")
 @WebResult(name = "MemberDetailsResponse", targetNamespace = "http://bk.org/memberservice/")
 MemberDetailsResponse getMemberDetails(
   @WebParam(name = "MemberDetailsRequest") MemberDetailsRequest memberDetailsRequest);
}

and the JAXB2 annotations on the request and response types:

package org.bk.memberservice.message;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "MemberDetailsRequest", namespace="http://bk.org/memberservice/")
public class MemberDetailsRequest {

 public MemberDetailsRequest() {
 }

 public MemberDetailsRequest(String id) {
  this.id = id;
 }

 private String id;

 public String getId() {
  return id;
 }

 public void setId(String id) {
  this.id = id;
 }

}

package org.bk.memberservice.message;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.bk.memberservice.types.MemberDetail;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "MemberDetailsResponse", namespace="http://bk.org/memberservice/")
public class MemberDetailsResponse {

 public MemberDetailsResponse() {
 }

 @XmlElement(name="memberdetail", namespace="http://bk.org/memberservice/")
 private MemberDetail memberDetail;

 public MemberDetailsResponse(MemberDetail memberDetail) {
  this.memberDetail = memberDetail;
 }

 public MemberDetail getMemberDetail() {
  return memberDetail;
 }

 public void setMemberDetail(MemberDetail memberDetail) {
  this.memberDetail = memberDetail;
 }

}
This generates a wsdl fairly close to the manually generated one, but not quite there - there does not seem to be a good way of controlling the namespace of operation name, and the wrappers around the request and the response xml structures.

So considering these factors, a rule that I have used is:

  • If a service is consumed only by a known internal client(say for cases where the same team is the producer AND the consumer) then go for code first, for the speed of development
  • If a service is expected to be more widely used, then go for contract first, with careful wsdl design

Sample code used here is available at :
git://github.com/bijukunjummen/memberservice-codefirst.git