6

The problem

I am taking over the development of a java web service client and in order to test an evolution I have to request a method from a distant web service server (which is embedded in an Apache Axis2 running in a tomcat instance).

In the first place, I requested the method through SOAP UI, using the WSDL provided by the server. It works fine.

Now I try to request the method through my Java web service client, but I cannot connect to the server even though the test with SOAP UI proves that everything is fine about it.

The java web service client relies on Spring-WS.


Calling the web service from the client

// Setting the kycScoreRequest
...

// Trying to connect and to get the kycScoreResponse 
KycScoreResponse kycScoreResponse = (KycScoreResponse) getWebServiceTemplate().marshalSendAndReceive(kycScoreRequest);

The resulting error

[main] DEBUG com.foo.AbstractMain - org.springframework.ws.client.WebServiceIOException: I/O error: Connection timed out: connect; nested exception is java.net.ConnectException: Connection timed out: connect
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:545)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:386)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:380)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:372)
    at com.foo.MainKycScore.getReturn(MainKycScore.java:37)
    at com.foo.MainKycScore.main(MainKycScore.java:244)
Caused by: java.net.ConnectException: Connection timed out: connect
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.SocksSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:121)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:326)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445)
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
    at org.springframework.ws.transport.http.HttpComponentsConnection.onSendAfterWrite(HttpComponentsConnection.java:119)
    at org.springframework.ws.transport.AbstractWebServiceConnection.send(AbstractWebServiceConnection.java:47)
    at org.springframework.ws.client.core.WebServiceTemplate.sendRequest(WebServiceTemplate.java:624)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:587)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:539)
    ... 5 more

Hypothesis 1 : Do I use the right web service URL ?

I'm kinda sure Spring is given the right URL, because it is the same as before I took over the code and nothing changed about the wsdl nor the server (and our client never complained, it was working for him, but never on our machines at work. So don't ask me how the developer before me tested it although it was not working, because idk) :

WebServiceGatewaySupport.setDefaultUri("http://82.36.138.182:8080/axis2/services/KYCService01.KYCService01HttpSoap11Endpoint/")

I have the following in the WSDL :

<wsdl:service name="KYCService01">
    <wsdl:port name="KYCService01HttpSoap11Endpoint" binding="ns:KYCService01Soap11Binding">
        <soap:address location="http://82.36.138.182:8080/axis2/services/KYCService01.KYCService01HttpSoap11Endpoint/"/>
    </wsdl:port>
</wsdl:service>

I also tried the EPR instead as the url, but it doens't change anything :

WebServiceGatewaySupport.setDefaultUri("http://82.36.138.182:8080/axis2/services/KYCService01")

Hypothesis 2 : Is it the proxy I'm behind ?

Then, I thought that the error must have been caused because of the proxy which I'm behind. Indeed, when I tried to write a little piece of code to connect to the wsdl url, at first I couldn't and got a "connection timed out". To resolve this I set the proxy as java System properties, allowing me to now access the wsdl from the web service client.

Setting the proxy

System.setProperty("http.proxyHost", "<my_proxy_hostname>");
System.setProperty("http.proxyPort", "<my_proxy_port>");

Connecting to the WSDL URL

URL wsdlAddress = null;
HttpURLConnection connection = null;

wsdlAdress = new URL("<wsdl_url>");
connection = (HttpURLConnection) wsdlAdress.openConnection();
connection.connect(); // It works if the proxy is set as System properties

Unfortunately, when I try to call the web service server with my proxy set, I still have the exact same error as mentioned above. Now I am already out of idea. How is it possible that my Java client can access the web service WSDL but not its methods ?


(edit) Hypothesis 3 : Is it the http header ?

I intercepted the HTTP msg from SOAP UI and the WS client thanks to membrane interceptor. See the headers :

SOAP UI

POST http://82.36.138.182:8080/axis2/services/KYCService01.KYCService01HttpSoap11Endpoint/ HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "urn:kycScore"
Content-Length: 1301
Host: 84.37.138.182:8080
Proxy-Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

WS client (the destination URL is a SOAP UI mock server, because obviously if I use the URL I really try to connect to there is nothing sent and thus nothing to intercept)

POST /mock HTTP/1.1
Accept-Encoding: gzip
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml; charset=utf-8
Content-Length: 1032
Host: localhost:8088
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_101)

I don't really know anything about http headers, but the main difference seems to be SOAPAction. I set the SOAPAction attribute of my ws client message to the same value as SOAP UI, but it didn't change anything.

public Object marshalWithSoapActionHeader(KycScore o) {

        return getWebServiceTemplate().marshalSendAndReceive(o, new WebServiceMessageCallback() {

            public void doWithMessage(WebServiceMessage message) {
                ((SoapMessage) message).setSoapAction("urn:kycScore");
            }
        });
    }

Otherwise, is it possible that the java version we can see in the User-Agent attribute is important ? (edit) I don't think so because I tried to use a 1.6 jre and the version does change in the User-Agent attribute but I still have the same error.

Community
  • 1
  • 1
Flyout91
  • 782
  • 10
  • 31
  • Are you able to use your remote debugger and drill down into `getWebServiceTemplate()` and `marshalSendAndReceive()` to see exactly what is going on? Also, have you checked whether or not a firewall issue is happening? Your clients may have had their IPs whitelisted, while yours may not be. – entpnerd Feb 07 '18 at 00:31
  • Thank you for your answer. No I cannot drilldown into these methods because I don't have the sources. I could possibly attach them to my project I think (never did Something like that before). I don't know how to check if a firewall issue is happening. I think that my IP is whitelisted, otherwise I could not retrieve the wsdl with my app nor use a browser to access the wsdl url, which I can do. Or may be their firewall settings are differents for the wsdl URL and the server methods ? – Flyout91 Feb 07 '18 at 14:47
  • I think it as nothing to do wih their firewall, because it works with SOAP UI ! – Flyout91 Feb 07 '18 at 15:27
  • You're using Soap UI from the same host that you're running code from correct? As for sources, attach them to your project so that you can dive into the code. Diving into third party code will help you see the real values that are used when calling the API. – entpnerd Feb 07 '18 at 16:05
  • I attached the source. Honestly it gave me no clue. As you can see in the trace I posted, the sequence of calls goes far beyond Spring Framework until the error is thrown. I stopped digging in the AbstractHttpClient apache class. – Flyout91 Feb 08 '18 at 09:51
  • And yes I am using soap UI from the same host. – Flyout91 Feb 08 '18 at 10:03
  • what is your connection timeout set to? – entpnerd Feb 08 '18 at 11:15
  • @entpnerd 1000 secs. The code does a HttpComponentsMessageSender.setReadTimeOut(1000) and then put this object in the WebServiceGatewaySupport (extended by my java ws client) through its setMessageSender method. I have to wait around 20 seconds until I have the timeout error. In SOAP UI the response is instantanenous. – Flyout91 Feb 08 '18 at 11:46
  • 1
    Interesting... so that method actually uses milliseconds as its unit so your timeout is only 1 second. Additionally, that's for setting [the read timeout, not the connection timeout](https://stackoverflow.com/a/34008123/4851565). Instead, try calling `HttpComponentsMessageSender.setConnectionTimeout(10000)`. That should set a 10 second connection timeout. – entpnerd Feb 08 '18 at 11:52
  • Good idea but unfortunately it doesn't work (I also set the read timeout to 10 000). When connection timeout is set to 10 000, an error is thrown before the precedent one (see the trace), in `PlainSocketFactory.connectSocket(Socket, InetSocketAddress, InetSocketAddress, HttpParams) line: 123`. It is a `org.apache.http.conn.ConnectTimeoutException`. When set to 100 000, I have the original `java.net.ConnectException`. My guess is that a connection timeout superior to 10 000 is already set. I cannot verify this as there is no get method for this attribute. – Flyout91 Feb 08 '18 at 12:15
  • does the webservice you are trying to connect to have some kind of health check API? A lot of times there is usually some endpoint like `ping` or `healthCheck` that you can call `GET` on, without much trouble. – entpnerd Feb 08 '18 at 12:20
  • No I don't think so.The server is in axis2 and axis2 offers a default ws method called `getVersion`, which returns the version of axis2. I will try to call this method instead if I have the time. Tomorrow I will also get the server wsdl and use it to start a SOAP UI mock server on my computer at home. Then I will try to request my mock server from my computer at work with SOAP UI, and if it succeed I will try to request my mock server with my ws client. If I can, it will mean that the problem is not on my side. – Flyout91 Feb 08 '18 at 13:07
  • 1
    Additionally, try to see if your Soap UI is calling the web service using any default headers. If you see any, replicate that in your client code call. – entpnerd Feb 08 '18 at 13:20
  • Yes I didn't mention it but I kind of tried this before. I used the app called membrane interceptor to intercept the http msg coming from my ws client. I saw that a main difference with the header used by SOAP UI was the SOAPAction attribute. SOAP UI has `SOAPAction: "urn:kycScore"` but my ws client has `SOAPAction: ""`. I wrote a piece of code to set the soap action to `urn:kycScore`, but it didn't change anything (might have done it poorly because I only tested it quickly before erasing everyhting). Futhermore SOAP UI doesn't allow to edit headers, so I couldn't try the other way around. – Flyout91 Feb 08 '18 at 13:31
  • @entpnerd I edited my post to show the headers. – Flyout91 Feb 08 '18 at 14:08
  • 1
    Have you tried [myKong's blog article on this](https://www.mkyong.com/webservices/jax-ws/jax-ws-hello-world-example-document-style/)? I know that the article is largely about creating a SOAP web service, but at the bottom, it discusses creating a client. At this point, I'd recommend rewriting your client using myKong's client template using the `QName` and `Service` classes. By calling `[Service#getPort()](https://docs.oracle.com/javase/8/docs/api/javax/xml/ws/Service.html#getPort-java.lang.Class-)`, I think you'll be able to establish a successful connection. Maybe?... :-) – entpnerd Feb 08 '18 at 14:12
  • I will not be able to rewrite the client (I mean it is a client developped at my work so it is complicated) but I will sure take a look for my own knowledge, thanks. – Flyout91 Feb 08 '18 at 15:10
  • I get that you can't rewrite the client. That sometimes happens in enterprise environments. But can you change your code that calls this complicated client to just bypass the use of this client code entirely and use myKong's template? Additionally, I have a stupid question... Since this web service client was supposedly developed in house and is maintained by your company, can you reach out to the team that maintains the client for an example of how to use it? Teams often have integration tests in their pipelines that use a client from which to call their own web service. – entpnerd Feb 08 '18 at 15:21
  • Well, I am only 4 weeks old in my company and they gave me this because it is a kind of mess, developped by someone about to quit and who tried to follow the standards imposed by the company when it comes to develop a web service client, but still did some stuff how he intended to. If I propose to rewrite some stuff or does it on my own, especially as myKong example which is not the standard way I have to follow, I will sure hear about it or be refused. So no one maintains this client. No one but me now ! – Flyout91 Feb 08 '18 at 16:26
  • Yesterday I consulted someone who wrote several web service clients for our company, but he couldn't see the problem. He proposed to ask the client whose I am requesting the server if he actually sees our requests (or attemps to connect). May be in the end this is what we will have to do. – Flyout91 Feb 08 '18 at 16:26
  • If some guy wrote this and is about to quit, and you are going to be responsible for maintaining this client, if I were you, I would do whatever I could to extract as much knowledge from him about this client before he leaves. – entpnerd Feb 08 '18 at 17:44
  • 1
    Another question... I can't stop digging on this one... :-) Is the client that you're trying to integrate with internally calling `getWebserviceTemplate()`, or are you explicitly that method, or are you still using the `HttpUrlConnection` approach that you showed in the "Hypothesis 2" section? Either way, would you please post the code for `getWebserviceTemplate()`? If the template is constructed in different code/XML config, please post that as well. Basically, I would like to see the configuration of the `WebserviceTemplate`. – entpnerd Feb 08 '18 at 18:00

3 Answers3

3

Summarizing troubleshooting tips to try that summarize longwinded discussions in comments:

  1. Try checking whether or not you are missing any required headers.
  2. Try accessing a simple-to-connect-to health check or ping endpoint of the service.
  3. Try reducing your connection timeout if you keep getting a connection timeout.
  4. Check for Firewall rules if you can't connect.
  5. When using custom client libraries that were developed in house, try to reach out to devs who know that library for help.
  6. When using custom client libraries, attach sources to debug.
  7. Try copying a template like myKong's SOAP Web Service example if you can get away with it.
entpnerd
  • 10,049
  • 8
  • 47
  • 68
1

Please check the proxy settings in your Internet explorer

DevEmani
  • 15
  • 3
  • proxy in explorer is set to automatic. At first I didn't know the proxy adress and port. So I used a library called "proxy-vole" (sample code I used can be found here : https://stackoverflow.com/questions/10324996/does-javas-proxyselector-not-work-with-automatic-proxy-configuration-scripts, see the post from deradam) to retrieve this information from the os/ie configuration. It gave me the proxy adress and port that I now use in the code. That is how I was able to connect to the wsdl exposed by the server from my java client. – Flyout91 Feb 08 '18 at 09:38
0

Possible solutions 1. Please try accessing the WSDL from browser 2. Please see if any authorisation headers or proxy settings already configured in the SOAP UI

DevEmani
  • 15
  • 3
  • Thank you for your answer. 1 : I can access the wsdl from my brower. 2 : SOAP UI has the proxy settings set to automatic. If I disable it by clicking the "Proxy" button, I cannot request the server anymore, which seems logic. I don't know where SOAP UI is taking the proxy configuration from though. – Flyout91 Feb 07 '18 at 14:39
  • From https://www.soapui.org/getting-started/soapui-interface/preferences-and-settings.html#Proxy-Settings : "Automatic tries to automatically determine proxy by looking at Java settings, environment variables, browser settings and operating system settings." – Flyout91 Feb 08 '18 at 13:20
  • Instead of "Automatic" I used "Manual" and used the same hostname and port as I use in my java ws client. It still works, so we can assume I set the right configuration. – Flyout91 Feb 08 '18 at 13:42