Popular Posts

Spring boot SOAP Web Service Performance

Consumng

This tutorial walks you through the process of consuming a SOAP-based web service with Spring.

It elucidates following items

  • Making parallel calls with RxJava (or WebFlux)

  • Sending large SOAP message payloads using AXIOM( AXis Object Model) AxiomSoapMessageFactory.(which improves performance)

  • Marshalling( is the process of transforming the memory representation of an object to a data format suitable for storage or transmission)

Marshalling (XML Serialization) done with O/X Mappers, different types of mappers out there and choose appropriate one for your need.

  1. Castor XML mapping is an open source XML binding framework. It allows you to transform the data contained in a java object model into/from an XML document. By default, it does not require any further configuration, though a mapping file can be used to have more control over the behavior of Castor. The Spring integration classes reside in the org.springframework.oxm.castor package

  2. JiBX The JiBX framework offers a solution similar to that which JDO provides for ORM: a binding definition defines the rules for how your Java objects are converted to or from XML. After preparing the binding and compiling the classes, a JiBX binding compiler enhances the class files, and adds code to handle converting instances of the classes from or to XML. Spring integration classes resides in org.springframework.oxm.jibx

Refer spring-web-service-example for more information.

  1. XStream is a simple library to serialize objects to XML and back again. It does not require any mapping, and generates clean XML. The Spring integration classes reside in the org.springframework.oxm.xstream package

Note
XStream is an XML serialization library, not a data binding library
  1. Eclipselink Moxy Eclipselink Moxy

jaxb overview

We will build a SOAP client that fetches city information based on zipCode.

From the above WSDL we will use following simple service calls

  1. ReturnCityState - This will return City and State Information

  2. AlternateCities - This will return alternate city names

Spring provides a mechanism to invoke soap based services using WebServiceTemplate

It has three main components to communicate with soap service, refer SoapTemplateConfig for full configuration.

  1. Message Sender - which is responsible for sending the XML message across a transport layer(HTTP/JMS/Email)

  2. Message Factory - A factory for creating SOAPMessage objects

  3. Marshaller - is the process of transforming the memory representation of an object to a data format suitable for storage or transmission

Message Sender (HTTP Transport)

There are two implementations of the WebServiceMessageSender interface for sending messages via HTTP.

  1. The default implementation is the HttpUrlConnectionMessageSender, which uses the facilities provided by Java itself.

  2. The alternative is the HttpComponentsMessageSender, which uses the Apache HttpComponents HttpClient. Use the latter if you need more advanced and easy-to-use functionality (such as authentication, HTTP connection pooling, and so forth).

messageSenderBean.java
    /**
     * Apache httpClient with default behaviour. customize as per need to handle https traffic
     *
     * @return httpClient
     */
    @Bean
    HttpClient httpClient() {
        return HttpClients.custom()
                .setDefaultRequestConfig(RequestConfig.DEFAULT)
                .addInterceptorFirst(httpRequestInterceptor())
                .build();
    }

    /**
     * Remove duplicate header
     */
    public HttpRequestInterceptor httpRequestInterceptor() {
        return (request, context) -> request.removeHeaders(HTTP.CONTENT_LEN);
    }


    /**
     * Transportation: HTTP (Other alternative Transportation like JMS, EMAIL, XMPP)
     * <p>
     * There are two implementations of the {@link org.springframework.ws.transport.WebServiceMessageSender}
     * interface for sending messages via HTTP.
     * 1. The default implementation is the
     * {@link org.springframework.ws.transport.http.HttpUrlConnectionMessageSender}, which uses the facilities
     * provided by Java itself.
     * <p>
     * 2.The alternative is the {@link HttpComponentsMessageSender}, which uses the Apache HttpComponents
     * {@link HttpClient}.
     * Use the latter if you need more advanced and easy-to-use functionality (such as authentication, HTTP connection
     * pooling, and so forth).
     *
     * @return HttpComponentsMessageSender {@link HttpComponentsMessageSender}
     */
    @Bean
    HttpComponentsMessageSender httpComponentsMessageSender() {
        HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
        httpComponentsMessageSender.setHttpClient(httpClient());
        return httpComponentsMessageSender;
    }

Message Factory

Concrete message implementations are created by a WebServiceMessageFactory.

This factory can create an empty message, or read a message based on an input stream.

There are two concrete implementations of WebServiceMessageFactory;

  1. one is based on SAAJ, the SOAP with Attachments API for Java,

  2. the other based on Axis 2’s AXIOM, the AXis Object Model.

AxiomSoapMessageFactory

The AxiomSoapMessageFactory uses the AXis 2 Object Model to create SoapMessage implementations. AXIOM is based on StAX, the Streaming API for XML. StAX provides a pull-based mechanism for reading XML messages, which can be more efficient for larger messages.

To increase reading performance on the AxiomSoapMessageFactory, you can set the payloadCaching property to false (default is true). This will read the contents of the SOAP body directly from the socket stream. When this setting is enabled, the payload can only be read once. This means that you have to make sure that any pre-processing (logging etc.) of the message does not consume it.

axiomSoapMessageFactory Bean
    /**
     * In addition to a message sender, the WebServiceTemplate requires a Web service message factory. There are two
     * message factories for SOAP: {@link SaajSoapMessageFactory} and
     * {@link AxiomSoapMessageFactory}. If no message factory is
     * specified (via the messageFactory property), Spring-WS will use the
     * {@link org.springframework.ws.soap.saaj.SaajSoapMessageFactory} by default.
     * <p>
     * The AxiomSoapMessageFactory uses the AXis 2 Object Model to create SoapMessage implementations. AXIOM is based
     * on StAX, the Streaming API for XML. StAX provides a pull-based mechanism for reading XML messages, which can
     * be more efficient for larger messages.
     *
     * @return AxiomSoapMessageFactory {@link AxiomSoapMessageFactory}
     */
  @Bean
    AxiomSoapMessageFactory axiomSoapMessageFactory() {
        AxiomSoapMessageFactory axiomSoapMessageFactory = new AxiomSoapMessageFactory();

        /*
         * To increase reading performance on the AxiomSoapMessageFactory, you can set the payloadCaching property to
         * false (default is true). This will read the contents of the SOAP body directly from the socket stream.
         * When this setting is enabled, the payload can only be read once. This means that you have to make sure
         * that any pre-processing (logging etc.) of the message does not consume it.
         */
        axiomSoapMessageFactory.setPayloadCaching(false);
        //axiomSoapMessageFactory.afterPropertiesSet();

        return axiomSoapMessageFactory;
    }

Sending and receiving POJOs - marshalling and un-marshalling

In order to facilitate the sending of plain Java objects, the WebServiceTemplate has a number of send(..) methods

that take an Object as an argument for a message’s data content.

The method marshalSendAndReceive(..) in the WebServiceTemplate class delegates the conversion of the request object to XML to a Marshaller,

and the conversion of the response XML to an object to an Unmarshaller.

To externalize the conversion logic we use Eclipselink Moxy Framework.

Refer https://wiki.eclipse.org/EclipseLink/Examples document for more information.

marshaller.java
/**
     * Handles conversion of JavaObjects to XML vice versa. (uses MOXY to externalize this conversion).
     * <p>
     * In order to facilitate the sending of plain Java objects, the WebServiceTemplate has a number of send(..)
     * methods that take an Object as an argument for a message's data content. The method marshalSendAndReceive(..)
     * in the WebServiceTemplate class delegates the conversion of the request object to XML to a Marshaller, and the
     * conversion of the response XML to an object to an Unmarshaller.
     *
     * @return Jaxb2Marshaller {@link Jaxb2Marshaller}
     */
    public Jaxb2Marshaller jaxb2Marshaller(String path) throws IOException {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("bindings/" + path + "/**");

        Map<String, Object> properties = Collections.singletonMap(JAXBContextProperties.OXM_METADATA_SOURCE,
                Arrays.stream(resources).map(resource -> "bindings/" + path
                + "/" + resource.getFilename()).collect(Collectors.toList()));

        LOGGER.info("JaxbContextProperties {} ", properties);
        jaxb2Marshaller.setJaxbContextProperties(properties);
        //used to specify java classes to bound. since we are using Moxy we need to provide
        //jaxb.properties file folder - javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
        jaxb2Marshaller.setContextPath("jaxb");//jaxb.context.path
        return jaxb2Marshaller;
    }

Client layer uses RxJava to make asynchronous calls and aggregates the result.

refer Github repository for complete codebase.

Summary

  1. Invoking SOAP web service using webServiceTemplate

  2. Understanding the different messageFactories (Axiom and SAAJ)

  3. Different message senders for different protocols ( HTTP, JMS etc)

  4. Integrating Moxy Marshaller framework( Java to XML conversion)

  5. Usage of RxJava for parallel calls

No comments:

Post a Comment