5

I am trying to set timeout for WS call. I extended WebServiceGatewaySupport and was trying to set to Sender timeout like this:

public Object marshalSendAndReceive(Object requestPayload) {

        WebServiceTemplate wsTemplate = this.getWebServiceTemplate();
        for (WebServiceMessageSender sender : wsTemplate.getMessageSenders()) {
            try {
                HttpComponentsMessageSender httpSender = (HttpComponentsMessageSender) sender;
                httpSender.setReadTimeout(3000);
                httpSender.setConnectionTimeout(2000);
            } catch (ClassCastException | NumberFormatException cex) {
                logger.warn("Cannot set WS timeout: " + cex.getMessage());
            }
        }

        return wsTemplate.marshalSendAndReceive(requestPayload);
    }

(credit to question #6733744)

However I get: Cannot set WS timeout: org.springframework.ws.transport.http.HttpsUrlConnectionMessageSender cannot be cast to org.springframework.ws.transport.http.HttpComponentsMessageSender

Can timeout be set to HttpsUrlConnectionMessageSender somehow? Or is there any other way to set timeout to https ws call in spring-boot?

Thank you.

Wlad
  • 410
  • 1
  • 9
  • 27
  • Possible duplicate of [How to set timeout in Spring WebServiceTemplate](http://stackoverflow.com/questions/6733744/how-to-set-timeout-in-spring-webservicetemplate) – Michael Peacock Mar 30 '17 at 15:53
  • @MichaelPeacock it's different because I deal with HTTPS, not HTTP. – Wlad Apr 04 '17 at 08:12
  • Did you find any solution to your problem @Wlad, I'm dealing with the same issue :( – Soufiane ROCHDI Jun 27 '17 at 23:32
  • @SoufR unfortunately no :/ – Wlad Jun 28 '17 at 05:22
  • So what did you do, is there any work around ? – Soufiane ROCHDI Jun 28 '17 at 21:07
  • @SoufR I run communication in the future with timeout. However after future times out reply still can come, however my workflow doesn't wait for it anymore. Like this you can end up with many threads, depends on services you call and frequency... Project is not in the production yet, hopefully it won't backfire. – Wlad Jun 28 '17 at 21:50
  • @Wlad, I resolved the issue and put it as an answer, I hope it works for you. na dmark it as the solution. – Soufiane ROCHDI Jul 24 '17 at 10:57

2 Answers2

3

I had the same issue, and managed to make it work using HttpComponentsMessageSender. Here is my code:

HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
HttpClient httpClient = HttpClientFactory.getHttpsClient(sslUtils, timeout);
messageSender.setHttpClient(httpClient);
webServiceTemplate.setMessageSender(messageSender);

I also created a new factory class HttpClientFactory that sets the SSL and timeout:

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;

public class HttpClientFactory {

    private static CloseableHttpClient client;

    private HttpClientFactory() {
    }

    public static HttpClient getHttpsClient(SslUtils sslUtils, int timeout) throws Exception {

        if (client != null) {
            return client;
        }

        SSLContext sslcontext = getSSLContext(sslUtils);
        SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.addInterceptorFirst(new ContentLengthHeaderRemover());
        RequestConfig config = RequestConfig.custom()
                                    .setConnectTimeout(timeout)
                                    .setConnectionRequestTimeout(timeout)
                                    .setSocketTimeout(timeout)
                                    .build();

        return httpClientBuilder.setSSLSocketFactory(factory)
                    .setDefaultRequestConfig(config)
                    .build();
    }

    private static class ContentLengthHeaderRemover implements HttpRequestInterceptor {
        @Override
        public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
            request.removeHeaders(HTTP.CONTENT_LEN);
        }
    }

    public static void releaseInstance() {
        client = null;
    }

    private static SSLContext getSSLContext(SslUtils sslUtils) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException {

        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(sslUtils.getKeystore().getInputStream(), sslUtils.getKeyPwd().toCharArray());
        sslUtils.getKeystore().getInputStream().close();

        KeyStore ts = KeyStore.getInstance("JKS");
        ts.load(sslUtils.getTrustStore().getInputStream(), sslUtils.getTrustPwd().toCharArray());
        sslUtils.getTrustStore().getInputStream().close();

        SSLContextBuilder sslContextBuilder = SSLContexts.custom();
        try {
            sslContextBuilder = SSLContexts.custom().loadKeyMaterial(ks, ssl.getKeyPwd().toCharArray());
        } catch (UnrecoverableKeyException e) {
            e.printStack();
        }
        sslContextBuilder.loadTrustMaterial(ts, new TrustSelfSignedStrategy());
        return sslContextBuilder.build();
    }
}

For information the SslUtils is just a bean class that holds the keystore and truststore informations' :

public class SslUtils {

    private Resource keystore;
    private String keyPwd;
    private Resource trustStore;
    private String trustPwd;

    // Getters and Setters
}

This works for me and let me use both SSL and timeout at the same. I hope this will help others.

Soufiane ROCHDI
  • 1,543
  • 17
  • 24
0

You're getting a cast exception because HttpsUrlConnectionMessageSender and HttpComponentsMessageSender are not compatible types. They both share the same superclass (WebServiceMessageSender), but you can't cast one to the other. I think you can just use a HttpComponentsMessageSender in your WebServiceTemplate configuration. See How to set timeout in Spring WebServiceTemplate and Spring webServiceTemplate connection timeout property

Community
  • 1
  • 1
Michael Peacock
  • 2,011
  • 1
  • 11
  • 14