Published on

Integrating with SOAP Web Services in Java

Authors

I spent most of my time in 2017 and 2018 integrating with different systems within the organization I was at. This post is my key learnings from this experience.

Like most organizations, that are old enough, integrating with systems involves communicating using SOAP web services. In the last couple of years, I integrated with TIBCO exposed soap services as well as WCF services. Throughout my career, I have also integrated with Oracle services, IBM services and a number of others. Despite WSDLs being a standard I found there were some key differences that made it really painful to integrate with. I get into some of these nuances in this post.

The phases of an integration project

In any integration project, I have found there are set phases. These phases should ideally be followed in the order detailed below if the project is being started from inception as you will potentially get stuck later on in the process otherwise. The phases are:

  • Discovery: You are trying to get as much information as possible about the system that you are integrating with. You will need the following information:
    • Endpoints: The different endpoints to use for different environments. This will be in the form of http://some.url:somePort/SomeServiceName.wsdl
      • You can normally see the endpoint in the WSDL for each environment under a section similar to: <soap:address location="http://some.url:somePort/SomeServiceName"/>
      • For WCF WSDLs append ?singlewsdl to the end of the WSDL URI to get a full WSDL instead of a partial WSDL e.g. http://some.url:somePort/SomeServiceName?singlewsdl
    • Credentials: If the endpoint is secured you will need credentials for each environment to access it. You may have to get credentials created for your system depending on the endpoint you are integrating with.
  • Walking Skeleton and Build Out: This refers to the JAXB configuration and scaffolding needed to consume the web service.
    • You should always download a copy of the WSDL and use that in your project as opposed to downloading it every time you build. Downloading it every time will prevent you from being able to run JAXB locally and on CI servers.
  • Mapping:This is where you map your project's domain to the web service domain
    • This mapping should ideally be done by a business analyst (BA) or technical analyst (TA) and handed over to the developer to implement.
    • The mapping step is by far the most time consuming and difficult step in the process as it requires an understanding of the business as well as an understanding of the nuisances of how and why a WSDL was structured the way it was with the field names that were given.
    • First prize for this is to get as many real-world requests and associated responses as possible. You should get both success responses and error responses as references.
    • Second prize you would need the assistance of a Subject Matter Expert (SME) to help you map these fields. SMEs are generally business people or a combination of business people and developers on that team who worked on the service and understand how to use it.
  • Testing: this involves both manual testing and automated testing. You will need some test cases written up to ensure you cover as many scenarios as possible. This ideally should be done by the BA/TA.

Discovery

This involves you (as the dev) or/and a business/technical analyst requesting the information through an email or by going to the team running the system. Ideally, if this team has documentation or a wiki you can refer to then it is a huge win. They also should give you access to their dev environment to allow you to interact with the service to get your mapping polished.

The Walking Skeleton and Build Out

POM Configuration

Despite the fact that WSDLs are meant to be a standard they are surprisingly inconsistent. This configuration is the hardest part of configuring a web service.

This came after a lot of fiddling and trial and error. In the end, a colleague of mine who was also trying to integrate with a web service came upon the most solid configuration.

The below pom config ended up working the best with both Tibco as well as WCF web services:

...
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>2.3.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>4.3.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
    </dependencies>
...
    <build>
        <plugins>
            <plugin>
                <!-- wsimport -->
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxws-maven-plugin</artifactId>
                <version>2.5</version>
                <dependencies>
                    <dependency>
                        <groupId>org.glassfish.metro</groupId>
                        <artifactId>webservices-tools</artifactId>
                        <version>2.3.1</version>
                        <exclusions>
                            <exclusion>
                                <artifactId>istack-commons-runtime</artifactId>
                                <groupId>com.sun.istack</groupId>
                            </exclusion>
                        </exclusions>
                    </dependency>
                    <dependency>
                        <groupId>org.glassfish.metro</groupId>
                        <artifactId>webservices-rt</artifactId>
                        <version>2.3.1</version>
                        <exclusions>
                            <exclusion>
                                <artifactId>istack-commons-runtime</artifactId>
                                <groupId>com.sun.istack</groupId>
                            </exclusion>
                        </exclusions>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <goals>
                            <goal>wsimport</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <args>
                        <arg>-XadditionalHeaders</arg>
                    </args>
                    <vmArgs>
                        <vmArg>-Djavax.xml.accessExternalDTD=all</vmArg>
                        <vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
                    </vmArgs>
                    <xadditionalHeaders>true</xadditionalHeaders>
                    <extension>true</extension>
                    <wsdlDirectory>src/main/resources/wsdl</wsdlDirectory>
                    <wsdlLocation>/wsdl/YourClient.wsdl</wsdlLocation>
                </configuration>
            </plugin>
            ...
        </plugins>
    </build>

The key section in the above is the plugin section. This will generate code under target/generated-sources/wsimport.

I could not work out how the plugin decides which package to put these generated classes under but if you look in the previously mentioned location you should see Java classes corresponding to the names in the WSDL you generated sources for.

Web Service Client Configuration with Spring

Environment Specific Configuration

To achieve this you need to create a Spring component that wires in the correct property based on the profile that is being used. This is done by creating a file similar to the below (name it whatever makes sense in your project):

package your.company.some.service.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class YourClientProperties {

    private final Environment environment;

    private final String prefix = "your.client.";

    @Autowired
    public YourClientProperties(Environment environment) {
        this.environment = environment;
    }

    @Configuration
    @Profile("default")
    @PropertySource("classpath:your-client.properties")
    class Defaults {
    }

    @Configuration
    @Profile("dev")
    @PropertySource("classpath:your-client-development.properties")
    class Development {
    }

    @Configuration
    @Profile("test") @PropertySource("classpath:your-client-test.properties")
    class Test { }

    @Configuration
    @Profile("prod")
    @PropertySource("classpath:your-client-production.properties")
    class Production { }

    public String getUrl() {
        return environment.getProperty(prefix + "url");
    }
}
  • Configuration Approach Used: There are easier ways of creating configurations in Spring but I opted for using the above as web service clients are generally standalone JARs and cannot have the full Spring container running inside them. Instead, pull just the spring configuration JARs in to allow you to configure client-specific settings.

  • URL Property: In the above note the url property.

    • This is something I generally always add to the client environment properties file as it is always needed and generally does change based on the environment that the client is running in.
  • Property File Names: Ensure that your file names are as unique as possible so that these do not clash with files of the same name in projects that your client is pulled into - your client jar may not be the only web service client loaded into a project.

Client Configuration

WSDL Generated Client Bean

When Jaxb runs it generates a client stub which you can use to communicate with the web service. It is best to wrap this generated web service client with your own web service client API as:

  • You are free to then expose whatever client API you want hiding the complexity of these systems away from consumers of your client.
  • If the WSDL you are communicating with changes in future you simply need to change the internals of your wrapper and not anything consuming your client as your clients outer API is independent of the inner API it wraps.
    • Your outer API should be tied to your domain and not the domain of the system you are integrating with.
    • Your wrapper client should be seen as a black box to consumers of it. They should only need to worry about what goes in and out, not what happens inside.

Below is an example Spring configuration exposing the generated WSDL stub as a bean in the Spring application context. This will be used later by our wrapper class.

package your.company.some.service.client.configuration;

import com.example.xmlns._1457685884689.YourClientServiceagent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile({"PROD", "TEST"})
public class YourClientConfiguration {

    @Bean
    public YourClientServiceServiceagent yourClientServiceagent(){
        return new YourClientServiceagent();
    }
}

In the above, this could have any name. It generally corresponds to a Java class that is generated from something that looks like the below in the source WSDL:

...
    <wsdl:service name="YourClient.serviceagent">
        <wsdl:port name="YourClientServiceOperationEndpoint" binding="tns:YourClientServiceOperationEndpointBinding">
            <soap:address location="http://some.url:7777/YourService"/>
        </wsdl:port>
    </wsdl:service>
...
Client Wrappers

These wrappers use the generated WSDL client and do the actual business mapping. Basically, these clients are responsible for mapping from your domain to the web service domain and visa versa.

I generally create an interface I code against which works with our domains objects (i.e. not the web service domain's objects). I then make multiple wrappers to allow our domain service to be used in any environment and in tests:

  • A web service client wrapper: This hits the actual web service client (the one generated by JAXB) which we exposed as a Spring bean in the previous section.
package your.company.client

import com.example.xmlns._1457685884689.YourClientServiceOperation
import com.example.xmlns._1457685884689.YourClientServiceagent
import com.sun.xml.internal.ws.developer.WSBindingProvider
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Profile
import org.springframework.stereotype.Component
import javax.xml.ws.BindingProvider
import javax.xml.ws.handler.soap.SOAPHandler
import javax.xml.ws.handler.soap.SOAPMessageContext
import your.company.dto.DomainSpecificRequest
import your.company.dto.DomainSpecificResponse
import your.company.ObjectFactory as YourClientObjectFactory

@Component
@Profile("PROD", "TEST")
class YourClientWebServiceClient(@Autowired private val yourClientProperties: YourClientProperties) : YourClient {

    companion object {
        val LOGGER: Logger = LoggerFactory.getLogger(YourClientWebServiceClient::class.java)
    }

    init {
        LOGGER.info("Endpoint being used:[${yourClientProperties.url}]")
    }

    private val defaultHandlerChain = listOf<SOAPHandler<SOAPMessageContext>>(SOAPLoggingHandler())

    var optionalHandlerChain: MutableList<SOAPHandler<SOAPMessageContext>> = mutableListOf()

    override fun someDomainSpecificOperation(domainSpecificRequest: DomainSpecificRequest): DomainSpecificResponse {
        LOGGER.debug("START :: someDomainSpecificOperation")
        val serviceDomainRequest = DomainSpecificRequestTransformer().transform(domainSpecificRequest)
        val securityHeaderType = SecurityHeaderTypeTransformer().transform(bookBondRequest.webServiceCredentials)

        val tradeEntryReply = getYourClient().someServiceOperation(serviceDomainRequest, securityHeaderType)
        LOGGER.debug("END :: someDomainSpecificOperation")
        return DomainSpecificResponseTransformer().transform(tradeEntryReply)
    }

    private fun getYourClient(): YourClientServiceOperation {
        val tradeEntryServiceServiceagent = TradeEntryServiceServiceagent()
        val tradeEntryServicePort = tradeEntryServiceServiceagent.tradeEntryServiceOperationEndpoint

        val wsBindingProvider = tradeEntryServicePort as BindingProvider
        assignHandlerChain(wsBindingProvider)
        wsBindingProvider.requestContext.put(WSBindingProvider.ENDPOINT_ADDRESS_PROPERTY, yourClientProperties.url)

        return yourClientServicePort
    }

    private fun assignHandlerChain(wsBindingProvider: BindingProvider) {
        wsBindingProvider.binding.handlerChain = defaultHandlerChain.toList()
        if (optionalHandlerChain.isNotEmpty()) {
            wsBindingProvider.binding.handlerChain = optionalHandlerChain.toList()
        }
    }
}
  • For the getYourClient method we always use the generated client that is derived from the WSDL element that looks like the following:
    <wsdl:portType name="YourClientServiceOperation">
            <wsdl:operation name="someWebServiceOperation">
            <wsdl:input message="tns:SomeWebServiceInputType"/>
            <wsdl:output message="tns:SomeWebServiceInputType"/>
            <wsdl:fault name="fault1" message="tns:SomeWebServiceFaultMessage"/>
        </wsdl:operation>
        ...
    </wsdl:portType>
  • In the above we have various implementations of javax.xml.ws.handler.soap.SOAPHandler
    • This lets you intercept web service request and responses
      • For example, you can have a handler that logs out requests and responses for a web service. This goes a long way in making it easier to debug issues in production. This is really useful while you are in the mapping phase of an integration project.
    • These handlers are a list allowing you to have many of them, allowing you to achieve different things.
    • An example SOAP handler is given in the section that follows
    • Using the transformer pattern works really well when transforming from your domain to the web service domain and back.
      • It lets you break up the web service mapping into clear parts.
      • Each transformation is trivial to test and find.
package your.company.util.transformer

interface Transformer<in I, out O> {
    fun transform(objectToTransform: I): O
}

An example of a simple transformer implementation that converts from numbers to words is below:

package your.company.util.transformer.yourdomaintoservicedomain

class NumberToWordTransformer <Int, String> {

    private val numberToWordMap = mapOf( 1 to "one", 2 to "two", 3 to "three")

    override fun transform(objectToTransform: Int): String {
        return numberToWordMap[objectToTransform] ? throw IllegalArgumentException("Only numbers from 1 to 3 (inclusive) can be used")
    }
}

Another example transformer is one for transforming to the oasis security header (which is often needed):

package your.company.client.transformer

import org.oasis_open.docs.wss._2004._01.oasis_200401_wss_wssecurity_secext_1_0.AttributedString
import org.oasis_open.docs.wss._2004._01.oasis_200401_wss_wssecurity_secext_1_0.PasswordString
import org.oasis_open.docs.wss._2004._01.oasis_200401_wss_wssecurity_secext_1_0.SecurityHeaderType
import org.oasis_open.docs.wss._2004._01.oasis_200401_wss_wssecurity_secext_1_0.UsernameTokenType
import your.company.webservice.util.security.WebServiceCredentials
import your.company.util.transformer.Transformer
import javax.xml.bind.JAXBElement
import javax.xml.namespace.QName

class SecurityHeaderTypeTransformer : Transformer<WebServiceCredentials, SecurityHeaderType> {
    override fun transform(objectToTransform: WebServiceCredentials): SecurityHeaderType {
        val securityHeaderType = SecurityHeaderType()

        val userNameToken = UsernameTokenType()
        val userNameAttribute = AttributedString()
        userNameAttribute.value = objectToTransform.username
        userNameToken.username = userNameAttribute

        val passwordString = PasswordString()
        passwordString.value = objectToTransform.password

        val qNamePassword = QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Password")
        val jaxbPassword = JAXBElement(qNamePassword, PasswordString::class.java, passwordString)
        userNameToken.any.add(jaxbPassword)

        val qNameUsername = QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "UsernameToken")
        val jaxbUserName = JAXBElement(qNameUsername, UsernameTokenType::class.java, userNameToken)
        securityHeaderType.any.add(jaxbUserName)

        return securityHeaderType
    }
}
package your.company.webservice.util.security

data class WebServiceCredentials(username: String, password: String)
  • A web service stub: This returns dummy data. This is used for tests and environments where we cannot access the real web service (for example if you are developing locally).
package your.company.client

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Profile
import org.springframework.stereotype.Component
import your.company.dto.DomainSpecificRequest
import your.company.dto.DomainSpecificResponse

@Profile("default", "dev")
@Component
class YourClientStubClient(@Autowired private val yourClientProperties: YourClientProperties) : YourClient {

    companion object {
        val LOGGER: Logger = LoggerFactory.getLogger(YourClientStubClient::class.java)
    }

    override fun someDomainSpecificOperation(domainSpecificRequest: DomainSpecificRequest): DomainSpecificResponse {
        LOGGER.debug("someDomainSpecificOperation")
        // this can simply be raw data that you ha E captured from the real web service. Ideally, it should be as real as possible so that you can code against it
        return DomainSpecificResponse()
    }
}
  • The default profile is what is used in unit tests unless you explicitly tell the test to use a specific profile.
WSDL Handlers

These are classes that match a certain type of interface. These implementations can be injected into the generated webservice client to do things like intercept requests and/or responses.

They get inserted into the set defined earlier, specifically this line:

var optionalHandlerChain: MutableList<SOAPHandler<SOAPMessageContext>> = mutableListOf()

The below is an example of a handler that logs out all requests and responses

This is very useful if you are trying to debug in an environment that you do not have access to.

The below extends the ParentHandler which has some common helper functions.

The below also attempts to mask all passwords it finds in headers.

package your.company.util.soap.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class SOAPLoggingHandler implements ParentSOAPHandler<SOAPMessageContext> {

    private static final Logger LOGGER = LoggerFactory.getLogger(SOAPLoggingHandler.class);

    @Override
    public boolean handleMessage(SOAPMessageContext soapMessageContext) {
        logOutSOAPMessage(soapMessageContext.getMessage());
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext soapMessageContext) {
        logOutSOAPMessage(soapMessageContext.getMessage());
        return true;
    }

    private void logOutSOAPMessage(SOAPMessage message) {
        if (LOGGER.isDebugEnabled()) {
            String messageAsString = soapMessageAsStringOrThrowingErrors(message);
            LOGGER.debug(messageAsString);
        }
    }
}
package your.company.util.soap.handler;

import your.company.util.exception.IntegrationException;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;

public interface ParentSOAPHandler<T extends SOAPMessageContext> extends SOAPHandler<T> {

    @Override
    default Set<QName> getHeaders() {
        return Collections.emptySet();
    }

    @Override
    default void close(MessageContext messageContext) {
    }

    default String soapMessageAsStringOrThrowingErrors(SOAPMessage message) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            message.writeTo(byteArrayOutputStream);
            String messageAsString = new String(byteArrayOutputStream.toByteArray(), "UTF-8");
            return maskPassword(messageAsString);
        } catch (SOAPException | IOException e) {
            throw new IntegrationException(e);
        }
    }

    default String soapMessageAsStringUsingTransformerOrThrowingErrors(SOAPMessage message, Transformer transformer) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            Source source = message.getSOAPPart().getContent();
            StreamResult result = new StreamResult(byteArrayOutputStream);
            transformer.transform(source, result);
            String messageAsString = new String(byteArrayOutputStream.toByteArray(), "UTF-8");
            return maskPassword(messageAsString);
        } catch (SOAPException | IOException | TransformerException e) {
            throw new IntegrationException(e);
        }
    }

    static String maskPassword(String xmlString) {
        return xmlString.replaceAll("<Password>.*<\\/Password>", "<Password>***</Password>");
    }
}

This handler approach can easily be adapted to write requests and responses to a file. This is extremely useful if you want to inject real data into unit tests to confirm you mapping logic.

I used this approach to wire in real data into a unit test as described in a previous post.

Mapping

This is by far the hardest part of any integration. It is also, unfortunately, the part that has no easy way of completing.

The difficulty with this process is that you need to understand or find someone who understands how your domain maps to the target system domain. If there is no domain expert you need to read and learn as much as you can about the system in question to understand how your business area will map to the given system's web service.

As a starting point asking the owner of the web service to give you as much information about it as possible goes a long way to help in integrating with the service. The sort of information you are looking for is:

  • System wiki pages
    • With example requests and responses
    • With example error responses
    • With information about the system's domain
  • The codebase (highly unlikely this access will be given)
  • Example requests and responses
  • Example requests and error messages
  • A developer who worked on the system to assist with mapping
  • A business person/analyst who works/worked on the system to assist with the mapping

In an ideal world, all or even some of the above details and assistance can be provided. Unfortunately, this is often not the case.

Without this information, there are other ways to go about the mapping task. These other approaches are not ideal and are more cumbersome but in a pinch can help you converge on a mapping.

Mapping Option 1 - SoapUI

For this, you will need access to a dev/test environment. To map you:

  • Fill in all mandatory fields in a WSDL method's request
    • Ideally you will need a subject matter expert to assist you with this
    • Alternatively you can take a stab at it and use the response from the service to guide you
  • Once mandatory fields are going through correctly you can start looking at what optional fields you may need and repeat the process for them too.

This approach can work well as most BA's and business people in the space have some experience with SoapUI and as a result, can assist you with the mapping process.

The main issue with this approach is that it can be very time consuming and cumbersome - the SoapUI interface is still quite clunky.

Mapping Option 2 - JUnit Test

This is similar to the first approach (of using SoapUI) except that you use JUnit instead. In this approach, we write a unit test where the test is just a way to more quickly code up the mappings and check with trial and error if a mapping is correct.

As the mapping for this approach is done in the code we can more easily programmatically check a range of values heck even if each call takes ages you can save the request and response to a file, go home and check the responses the next day. I have used this testing approach to iterate through a list of possible values and pass that to a request object to more quickly see what effect different values have on a response. This significantly expedites the process of checking different values (the SoapUI approach would take ages). As this is in the code you can also commit the results of different mappings to version control which you can use as a historical reference.

This approach is great at making mini smoke tests where you hit an endpoint with a request you know is correct. You then assert the response has the information you are expecting. I have used this approach to successfully pick up an issue with an endpoint before the team managing the service knew about it. Teams often make changes to an endpoint without letting downstream systems know. Using a test like this in their earlier environments (Dev, Test and UAT) will alert you to breaking changes before they are promoted to production giving you time to delay their release to give you time to make the changes your side.

I generally opt for this mapping approach as I can test that my web service client is working correctly. I can also confirm that my web service client interface is intuitive to other classes that may need it. Web service clients should hide some of the mess and hacks that may have been needed to get the integration working correctly. Ideally, it should take in and spit out objects that are relevant to the domain the web service is being used for.

As this approach uses code it almost automatically excludes business people and BAs meaning you are on your own. I normally end up using a combination of the first SoapUI approach and this one. I use the first approach to explore a new endpoint while I use this approach to fine tune my mapping and keep smoke tests in place to confirm it still works in future.

Testing

To properly test an integration you will need access to the system you are integrating with or you will need someone who works with that system to get the data for you.

The general testing process is:

  • Use your web service client to hit the web service
  • Log into the system you integrated with and get the data resulting from this web service call
  • Confirm that your data reached the target system correctly
    • This is often not always the case. For example, you may think that the units used for a number are decimal when it is in fact percentage meaning that the numbers you pass in are off by a factor of 100

Conclusion

Integrating with a web service can be incredibly difficult especially if the service has been around long enough. Web services are just a layer above an existing code base. Anyone who has seen an old enough code base knows some of the horrors that await them. With a codebase, you at least have direct access to the code to see what is going on. Web services, on the other hand, are often black boxes to this code.

It is my hope that this post will help with the more boilerplaty configuration of a web service project which in turn will free up developers to focus on the hard process of mapping their business requirements to the given service and in so doing successfully integrate with another system. This post lays out these configs based on tried and tested setups from various integration projects. The mapping and testing sections are less detailed as unfortunately there is no silver bullet to easily accomplish this.