3

I inherited a CXF based project, with the following (relevant) original dependencies (in pom.xml):

<dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>2.2.7</version>
</dependency>
<dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>2.2.7</version>
</dependency>
<dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-ws-security</artifactId>
        <version>2.2.7</version>
</dependency>

And

<plugin>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-codegen-plugin</artifactId>
        <version>2.2.8-SNAPSHOT</version>

By "original" I mean that this is the source code snapshot I received that used to build fine years ago, has been dormant for all these years and now, that some modifications to the code are needed, it will no longer build as is.

The main problem with trying to build it "as is", is that the 2.2.8-SNAPSHOT version of cxf-codegen-plugin is nowhere to be found... Maven can't find it and fails the build.

So, I replaced the above with (note that the only differences is 2.2.8 vs. 2.2.8-SNAPSHOT)

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>2.2.8</version>

The build succeeds now past this point but fails on 2 symbols not found:

  1. Password.set_value(String value) -- from the package org.oasis_open.docs.wss._2004._01.oasis_200401_wss_wssecurity_secext_1_0.
  2. SQLService.setENDPOINT(String sei) from own package based on javax.xml.ws.Service.

Both source files for the classes Password and SQLService are generated on-the-fly by Apache CXF 2.2.8, as designed by the original author of this project.

So, I quickly examined the new generated versions of this files and discovered that:

  1. Password.set_value(String value) seems to have been substituted by Password.setValue(String value).
  2. SQLService.setENDPOINT(String sei) has been eliminated completely, and instead requiring that sei be passed in the constructor: SQLService(URL wsdlLocation, QName serviceName)

So I modified the source code that calls these methods to adapt to this 2 seemingly minor changes and the project now builds successfully!

But... it fails at runtime with the following exceptions:

WARNING: Interceptor for {http://rservice.rorg.net/sql}SQLService#{http://rservice.rorg.net/sql}Get has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Could not send Message.
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:243)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:487)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:313)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:265)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
    at $Proxy38.get(Unknown Source)
        ...
Caused by: java.net.ConnectException: ConnectException invoking http://localhost:8080/rservice/services/SQLServiceSoap: Connection refused
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:67)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:522)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:2058)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:2043)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:66)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:639)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    ... 14 more
Caused by: java.net.ConnectException: Connection refused
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:413)
    at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:274)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:261)
    at java.net.Socket.connect(Socket.java:556)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:403)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:521)
    at sun.net.www.http.HttpClient.<init>(HttpClient.java:246)
    at sun.net.www.http.HttpClient.New(HttpClient.java:320)
    at sun.net.www.http.HttpClient.New(HttpClient.java:337)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:996)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:948)
    at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:873)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1040)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1955)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1907)
    at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:42)
    at org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1974)
    ... 17 more


04-Jan-2013 12:07:17 ERROR [SQLModule] Error running SQL module: Could not send Message.
javax.xml.ws.WebServiceException: Could not send Message.
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)
    at $Proxy38.get(Unknown Source)
    at net.rorg.rservice.client.base.sql.SQLClientBase.get(SQLClientBase.java:306)
    at net.rorg.rservice.client.module.sql.SQLModule.getBatch(SQLModule.java:149)
    at net.rorg.rservice.client.module.sql.SQLModule.getAndProcessSQL(SQLModule.java:110)
    at net.rorg.rservice.client.module.sql.SQLModule.run(SQLModule.java:280)
    at net.rorg.rservice.client.RClient.exec(RClient.java:398)
    at net.rorg.rservice.client.RClient.run(RClient.java:173)
    at net.rorg.rservice.client.RClient.main(RClient.java:166)
Caused by: 
java.net.ConnectException: ConnectException invoking http://localhost:8080/rservice/services/SQLServiceSoap: Connection refused
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:67)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:522)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:2058)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:2043)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:66)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:639)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:243)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:487)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:313)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:265)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
    ... 8 more
Caused by: 
java.net.ConnectException: Connection refused
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:413)
    at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:274)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:261)
    at java.net.Socket.connect(Socket.java:556)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:403)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:521)
    at sun.net.www.http.HttpClient.<init>(HttpClient.java:246)
    at sun.net.www.http.HttpClient.New(HttpClient.java:320)
    at sun.net.www.http.HttpClient.New(HttpClient.java:337)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:996)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:948)
    at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:873)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1040)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1955)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1907)
    at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:42)
    at org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1974)
    ... 17 more

Note: Even if I hardcode the actual (www) server URL in the WSDL (i.e. replacing http://localhost:8080 with https://test.rserver.com), I get the ConnectException error displaying http://localhost:8080 as the destination. Clearly, some CXF-substitution or resolution is not performed. Could that be a clue to where the problem is? Which component of CXF is responsible for that magical transformation from http://localhost:8080 to the real URL?

Is it right where the stack trace hints (i.e. JaxWsClientProxy or frontend.ClientProxy or...)?

at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:243)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:484)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:310)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:262)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)

If so, why is this happening and how do I fix this?

Now... if I were a CXF and/or JAX-WS expert, I would have probably figured out the root cause of that misleading "Connection refused" hint in the stack trace.

But at this point I am pretty much lost, since I know beyond certainty that the SEI is there, the authentication username/password are correct: The older binary (JAR with dependencies) runs just fine against this service.

I am therefore looking for a clue or an insight from an expert who may have seen this type of "Connection refused" stack trace and knows that it could be trigger by other than the typical reasons. For example, some type of mismatch that has been introduced once the cxf-codegen-plugin 2.2.8-SNAPSHOT was replaced by 2.2.8?

Or additional tips on how to troubleshoot this problem?

Community
  • 1
  • 1
Withheld
  • 4,603
  • 10
  • 45
  • 76

1 Answers1

2

I think your change to SQLService might be the problem

SQLService.setENDPOINT(String sei) has been eliminated completely, and instead requiring that sei be passed in the constructor: SQLService(URL wsdlLocation, QName serviceName)

Did you put a new URL in the constructor call? What was sei before? If you've put in a URL, it's probably that whose connection is failing. You should be able to use the no-arg constructor.

If you want to set the URL at runtime (I guess that's what the setENDPOINT call was doing) you need to manipulate the BindingProvider. See this thread http://cxf.547215.n5.nabble.com/How-to-change-the-service-URL-at-runtime-td3242927.html

artbristol
  • 32,010
  • 5
  • 70
  • 103
  • Answering your question: Yes, of course I put the new URL in the constructor call: prior to the constructor statement, I a create a QNAME object: `final QName SERVICE = new QName("http://rservice.rorg.net/sql", "SQLService");`. Also, the original code doesn't really manipulate the URL at runtime, as it calls `setENDPOINT` immediately after the constructor statement. Additional insights? Thanks (+1). – Withheld Jan 07 '13 at 16:22
  • 1
    @Daniel It's not so much 'at runtime' as 'not at compile time' - if you have a WSDL that has a placeholder endpoint location, you *need* to set the destination URL 'at runtime'. Is this the case for you? (I.E. does your WSDL have the correct location in it?) – artbristol Jan 07 '13 at 16:23
  • Yes, of course the WSDL has the correct location in it (it hasn't changed BTW since the original build years ago). What I meant by *"doesn't really manipulate the URL at runtime"* was that of course the SEI is set at runtime by both the old & the new code, but this is done immediately after the constructor, not at some point down the code depending on later information to be retrieved. Does this make sense? – Withheld Jan 07 '13 at 16:30
  • 1
    Yeah that makes sense. So does the no-arg constructor version of `SQLService` work? (Does it exist?) – artbristol Jan 07 '13 at 16:35
  • Yes, a no-arg constructor version of SQLService exists. CXF actually generates 3 constructors: **1.** `SQLService()`, **2.** `SQLService(URL wsdlLocation)`, **3.** `SQLService(URL wsdlLocation, QName serviceName)`. I initially tested with the 1-arg version and it didn't work. I never tried the no-arg version because I don't understand how something like this could even work... (doesn't it need both the WSDL location *and* the SEI?) – Withheld Jan 07 '13 at 16:42
  • 1
    If you use the no-arg one, it uses the WSDL location from disk when you generated the classes. What is the actual, real, WSDL location for the application in deployment? It's not `http://localhost:8080/rservice/services/SQLServiceSoap` (from your stack trace), I presume? – artbristol Jan 07 '13 at 16:47
  • The actual URL string in the WSDL is `http://localhost:8080/rservices/services/SQLServiceSoap` which is magically substituted at runtime (I still don't know how CXF does that) to run on any machine, be it test or production. **Or is it really?** See, I am still new to this and the fellow teammate that was instructing me about this, just said that the `localhost:8080` is what's supposed to be there. As for the actual WWW location, I am not at liberty to disclose this for employer confidentiality reasons. I will try the no-args to see if that makes any difference. Thanks so much. – Withheld Jan 07 '13 at 16:57
  • 1
    I tried the no-arg version and it fails due the fact that the default constructor is using wsdlLocation that equals to `file:/C:/Users/daniel/workspace/rservice-client/src/main/wsdl/SQLServiceSoap.ws‌​dl` (actual WSDL source file in workspace). Looks like both paramters need to be explicitly provided at construction time. Also, see the update to my OP. I believe the **mapping/translation/conversion** between `http://localhost:8080` to the real www server URL is **the key**. – Withheld Jan 07 '13 at 18:49
  • 1
    The 'mapping/translation/conversion' is the `provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, target);` call in the link I provided. Why does your co-worker think `http://localhost:8080/rservices/services/SQLServiceSoap` is the correct WSDL location? I also don't understand why the default constructor call fails. Does that WSDL source file *not* exist in your workspace? – artbristol Jan 08 '13 at 08:43
  • Some progress: The WSDL in the workspace is supposed to be overridden at runtime by values loaded from a config.xml file. But it doesn't. And the reason is that CXF 2.2.8-SNAPSOT produces a `wsdlLocation` equals to `"classpath:/net/rorg/rservice/sql/SQLServiceSoap.wsdl"` while CXF 2.2.8 produces `file:/C:/Users/daniel/workspace/rservice-client/src/main/wsdl/SQLServiceSoap.ws‌​‌​dl`. The question now is why??? – Withheld Jan 08 '13 at 14:41
  • 1
    @Daniel I gather you've already tried http://stackoverflow.com/a/9875701/116509 ? (You would need to update to a newer version of CXF) – artbristol Jan 08 '13 at 14:43
  • Oh Wow! I totally forgot about this. I implemented this and sure enough the generated SQLService class has `"classpath:/net/rorg/rservice/sql/SQLServiceSoap.wsdl"` in it now (although I'm still using CXF 2.2.8). But the problem persists, because the client still attempts to connect to `http://localhost:8080/rservice/services/SQLServiceSoap`, which means the `config.xml` is nowhere to be injected (although it loads fine by the program). This may seem like an application-specific issue, but I couldn't find any place in the code where this substitution should occur. Ideas? – Withheld Jan 08 '13 at 15:55
  • 1
    Are you calling `provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, target)` with the correct run-time URL? Can you update question with the WSDL's `wsdl:service/wsdl:port/soap:address` (which I guess is set to `http://localhost:8080/rservice/services/SQLServiceSoap`) – artbristol Jan 08 '13 at 16:07
  • 2
    Indeed, the `...getRequestContext()...` is what was missing. Turns out the wsdl2java wasn't generating that code and some "hidden trick" in the build environment copied "pre-manually-tweaked" version of that `SQLService.java` file. All is well now (work with CXF 2.2.8 but **not** with CXF 2.5.2 for some reason). Thanks! – Withheld Jan 08 '13 at 19:56
  • 2
    @Daniel phew! Glad you got it working. And boo to confusing build tricks! – artbristol Jan 08 '13 at 20:11