Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly integrate a CXF client into Spring Boot

I was looking at various ways how to build a SOAP client with CXF into a Spring Boot application. In particular I'm interested in configuring request/response logging.

Precondition: the CXF Maven plugin is used to generate Java stubs from the WSDL files.

I studied a number of tutorials [1][2][3] and they all do that slightly differently. The question is whether there's an "officially endorsed" way of integrating a CXF client with Spring Boot. The CXF documentation doesn't seem to say.

Option 1: BindingProvider

The existing code I'm working with (not mine) does it like that:

@Bean
public PartnerServicePortType partnerServicePortType() {
  PartnerServicePortType partnerServicePortType = new PartnerServiceV0().getPartnerService();
  configureService((BindingProvider) partnerServicePortType, Services.PARTNER_SERVICE.serviceName());
  return partnerServicePortType;
}

private void configureService(BindingProvider bindingProvider, String path) {
  bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, baseUrl + path);
  if (!StringUtils.isEmpty(username)) {
    bindingProvider.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
    bindingProvider.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
  }

  /* add logging interceptors
  Client client = ClientProxy.getClient(bindingProvider);
  Endpoint cxfEndpoint = client.getEndpoint();

  cxfEndpoint.getInInterceptors().add(new PayloadExtractingLoggingInInterceptor());
  cxfEndpoint.getInFaultInterceptors().add(new PayloadExtractingLoggingInInterceptor());
  cxfEndpoint.getOutInterceptors().add(new PayloadExtractingLoggingOutInterceptor());
  cxfEndpoint.getOutFaultInterceptors().add(new PayloadExtractingLoggingOutInterceptor());
  */
}

PartnerServiceV0 is generated class that extends javax.xml.ws.Service and looks like this:

@WebServiceClient(name = "PartnerService_v0", 
                  wsdlLocation = "classpath:some.wsdl",
                  targetNamespace = "urn:some-namespace") 
public class PartnerServiceV0 extends Service {

As you can see I added the code to enable request/response logging to the configureServcie method. While this does work it feels somewhat odd that we'd have to go through all of that for every service.

Option 2: JaxWsProxyFactoryBean

For verification purposes I ported the above code to using JaxWsProxyFactoryBeans:

@Bean(name = "partnerService")
public PartnerServicePortType generateProxy() {

  JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean();
  proxyFactory.setServiceClass(PartnerServicePortType.class);
  proxyFactory.setAddress(baseUrl + Services.PARTNER_SERVICE.serviceName());
  if (!StringUtils.isEmpty(username)) {
    proxyFactory.setUsername(username);
    proxyFactory.setPassword(password);
  }
  return (PartnerServicePortType) proxyFactory.create();
}

Adding logging config is something I'd still have to figure out with this strategy.

Tutorials I checked

  1. https://blog.codecentric.de/2016/07/spring-boot-apache-cxf-logging-monitoring-logback-elasticsearch-logstash-kibana/
  2. http://www.baeldung.com/apache-cxf-with-spring
  3. http://www.littlebigextra.com/consume-secure-soap-web-service-spring-boot-application/
like image 353
Marcel Stör Avatar asked Aug 13 '17 15:08

Marcel Stör


People also ask

How does Apache CXF work?

Apache CXF™ is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.

What is CXF endpoint?

In Apache Camel, the Camel CXF component is the key to integrating routes with Web services. You can use the Camel CXF component to create a CXF endpoint, which can be used in either of the following ways: Consumer — (at the start of a route) represents a Web service instance, which integrates with the route.

What is JAX-RS CXF?

JAX-RS: Java API for RESTful Web Services is a Java programming language API that provides support in creating web services according to the Representational State Transfer (REST) architectural style. CXF supports JAX-RS 2.1 (JSR-370), 2.0 (JSR-339) and 1.1 (JSR-311).


2 Answers

You can directly use JaxWsProxyFactoryBean to set logging interceptors or directly use logging features as shown below.

    @Bean
    public HelloWorld bus(SpringBus bus) {
        JaxWsProxyFactoryBean bean = new JaxWsProxyFactoryBean();
        bean.setServiceClass(HelloWorld.class);
        bean.setAddress(serverUrl);
        bean.setBus(bus);
        //bean.setInInterceptors(Collections.singletonList(new LoggingInInterceptor()));
        bean.setFeatures(Collections.singletonList(new LoggingFeature()));
        return bean.create(HelloWorld.class);
    }

Here is complete example.

like image 64
Karthik Prasad Avatar answered Oct 12 '22 16:10

Karthik Prasad


I using some jax-ws web service with cxf like this code

package org.roshan.framework.config;

import java.io.IOException;
import java.net.MalformedURLException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

import javax.inject.Inject;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.roshan.framework.config.PaymentProperties.WebServiceDetail.SSL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import com.tosan.modern.epayment.webservice.merchant.paymentservice.TosanIPGWS;
import com.tosan.modern.yaghut.service.SoapServices;


@Configuration
public class WebServiceClient {

    @Inject
    private PaymentProperties paymentProperties;

    @Autowired
    private ResourceLoader resourceLoader;

    @Bean(name = "PaymentWebService")
    public TosanIPGWS PaymentWebServiceCLient() throws MalformedURLException {

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(TosanIPGWS.class);
        factory.setAddress(paymentProperties.getShaparak().getWsPublicUrl());

        TosanIPGWS service = (TosanIPGWS) factory.create();
        try {
            final Client client = ClientProxy.getClient(service);
            // client.getInInterceptors().add(new LoggingInInterceptor());
            // client.getOutInterceptors().add(new LoggingOutInterceptor());
            setupSsl((HTTPConduit) client.getConduit(), paymentProperties.getShaparak().getSsl());
        } catch (Exception e) {
//          System.out.println("PaymentWebServiceCLient v9898989898");
            System.out.println(e.getMessage());
        }
        return service;
    }



    private void setupSsl(HTTPConduit httpConduit, SSL ssl) throws Exception {

        final String keyStoreLoc = ssl.getKeyStore();
        final String keyPassword = ssl.getKeyStorePassword();
        final String keystoreType = ssl.getKeyStoreType();
        final String trustStoreLoc = ssl.getTrustStore();
        final String trustStorePassword = ssl.getTrustStorePassword();
        final String trustStoreType = ssl.getTrustStoreType();

        final TLSClientParameters tlsCP = new TLSClientParameters();

        tlsCP.setDisableCNCheck(true);

        if (ssl.getKeyStore() != null && !ssl.getKeyStore().isEmpty()) {
            final KeyStore keyStore = KeyStore.getInstance(keystoreType);
            Resource resource1 = resourceLoader.getResource(keyStoreLoc);
            keyStore.load(resource1.getInputStream(), keyPassword.toCharArray());
            final KeyManager[] myKeyManagers = getKeyManagers(keyStore, keyPassword);
            tlsCP.setKeyManagers(myKeyManagers);
        }

        if (ssl.getTrustStore() != null && !ssl.getTrustStore().isEmpty()) {
            final KeyStore trustStore = KeyStore.getInstance(trustStoreType);
            Resource resource2 = resourceLoader.getResource(trustStoreLoc);
            trustStore.load(resource2.getInputStream(), trustStorePassword.toCharArray());
            final TrustManager[] myTrustStoreKeyManagers = getTrustManagers(trustStore);
            tlsCP.setTrustManagers(myTrustStoreKeyManagers);
        }

        httpConduit.setTlsClientParameters(tlsCP);
    }

    private static TrustManager[] getTrustManagers(KeyStore trustStore) throws NoSuchAlgorithmException, KeyStoreException {
        String alg = KeyManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);
        fac.init(trustStore);
        return fac.getTrustManagers();
    }

    private static KeyManager[] getKeyManagers(KeyStore keyStore, String keyPassword) throws GeneralSecurityException, IOException {
        String alg = KeyManagerFactory.getDefaultAlgorithm();
        char[] keyPass = keyPassword != null ? keyPassword.toCharArray() : null;
        KeyManagerFactory fac = KeyManagerFactory.getInstance(alg);
        fac.init(keyStore, keyPass);
        return fac.getKeyManagers();
    }

}
like image 1
ali akbar azizkhani Avatar answered Oct 12 '22 16:10

ali akbar azizkhani