How to set a connection timeout when using JAXRPC-RI web services client?

30,696

Solution 1

You may have luck setting properties such as sun.net.client.defaultConnectTimeout or sun.net.client.defaultReadTimeout, though that would then introduce a system-wide timeout.

In code the properties values are set using Strings:

System.setProperty("sun.net.client.defaultConnectTimeout", "1000");
System.setProperty("sun.net.client.defaultReadTimeout", "1000");

For a quick test, it might be easier to set the environment variable JAVA_OPTS or use the command line:

java -Dsun.net.client.defaultConnectTimeout="1000" ...

Solution 2

I am not sure why this particular JAXRPC implementation goes out of its way to make it difficult to set the timeout. Perhaps, there's a good reason for it. Other implementations such as Axis and, I believe JAX-WS, let you simply call the setTimeout() method on the Stub. After some pains, I was able to come up with this solution. Hopefully, it will be helpful. You will need to do the following in order to set the timeout on the underlying URLConnection:

  1. Create a new ClientTransport class. It should extend the com.sun.xml.rpc.client.http.HttpClientTransport class. Override the createHttpConnection(String, SOAPMessageContext) method. Call super.createHttpConnection() which will return HttpURLConnection object. On the HttpURLConnection object you can call setReadTimeout() which will force client-side timeout in X number of milliseconds. Once that's done, return the modified HttpURLConnection object.
  2. Extend the client-side Stub class with your own. Override the _getTransport() method to return a new instance of the ClientTransport class that you created in step (1).
  3. Extend the client-side _Impl class with your own. Override the get...Port() method so that it uses the Stub you created in step (2) instead of the generated one.
  4. Modify the client code you wrote to call the Web Service so that it uses the Stub you created in step (2) and the _Impl that you created in step (3).

Note: Make sure that whatever it is that you're calling to generate the Stubs via wscompile (Ant script?) does not overwrite the 3 Java classes you just created/modified. It probably makes sense to move them to a different package so that they don't end up being overwritten.

Solution 3

Yevgeniy Treyvus answer is very good, but results in a new HTTPUrlConnection being created for every SOAP call. I found out while testing his approach, that one can set a ClientTransportFactory. I now use a CustomClientTransportFactory and set it on the Stub ( casting it to StubBase ). Then one doesn't need step 2 and 3.

In step 4 one then sets his new ClientTransportFactory like so: ((StubBase) myPort)._setTransportFactory(new CustomClientTransportFactory());

Solution 4

I know that you are using Axis but I struggled to find the same answer for Weblogic and since your question title and tags are generic, here is my solution.

In my client class that implements the generated MyObject interface, I have adapted the getServicePort() as follows (note that I also have security here).

protected MyObject getServicePort() throws java.rmi.RemoteException {
    if (port == null) {
        synchronized(this) {
            if (port == null) {
                try {
                    final MyObject_Impl service = new MyObject_Impl(wsdlURL);

                    // using a local variable until the object is completelly initialized
                    final MyObject localPort = service.getMyObjectPort();

                    // if username and password are provided: building a client which will include the 
                    // username and token
                    if (username != null && pwd != null) {
                        Stub localStub = ((Stub) localPort);

                        // We have UsernameToken Authentication too
                        localStub._setProperty(
                                WSSecurityContext.CREDENTIAL_PROVIDER_LIST, 
                                Collections.singletonList(
                                        new ClientUNTCredentialProvider(username.getBytes(), pwd.getBytes())));

                        if (timeout != null) {
                               log.debug("Setting timeout to " + timeout + " milliseconds");
                            localStub._setProperty("weblogic.wsee.transport.read.timeout", timeout);
                            localStub._setProperty("weblogic.wsee.transport.connection.timeout", timeout);
                        }
                    }

                    port = localPort;

                } catch (ServiceException e) {
                    throw new RemoteException("Could not initialize client to MyObject service", e);
                }
            }
        }
    }
    return port;
}

The Oracle documentation is here: http://docs.oracle.com/cd/E12840_01/wls/docs103/webserv_rpc/client.html#wp241849 but it incorrectly states that the timeout is in seconds. It actually is in milliseconds !

Share:
30,696
matt b
Author by

matt b

Hello, world!

Updated on July 09, 2022

Comments

  • matt b
    matt b almost 2 years

    I'm working with a bit of a legacy component in which we interact with a SOAP web service (a technology which I absolutely, positively abhor) using some client code built using the JAXRPC-RI (reference implementation) library.

    I'm interested in being able to set a timeout with the stubs so that in case the web services server does not reply within X seconds, the application isn't setting there forever waiting for a response.

    I'm using to working with clients/stubs generated by Apache Axis, in which you can simply use org.apache.axis.client.Stub.setTimeout() to set a timeout.

    For the life of me I can't figure out how to set a timeout when using Stubs created with JAXRPC-RI:

    • The port class I am instantiating extends com.sun.xml.rpc.client.StubBase and implements javax.xml.rpc.Stub and com.sun.xml.rpc.spi.runtime.StubBase.
    • The JavaDocs for none of these classes mention any sort of timeout or method to do this.
    • Trying code like stub._setProperty("axis.connection.timeout", 1000); results in an exception at runtime: javax.xml.rpc.JAXRPCException: Stub does not recognize property: axis.connection.timeout

    Does anyone have any ideas on how to set/enforce a timeout when using a JAXRPC-RI client? Is it even possible?

  • matt b
    matt b almost 15 years
    This is an option, but I'd really like to do it within the confines of the web services client code / API itself, if possible. Thank you.
  • matt b
    matt b almost 15 years
    Any idea if this affects not just outgoing connections but incoming ones as well?
  • Arjan
    Arjan almost 15 years
    I guess the first can only apply to outgoing requests, unless any handshakes would be taken into account as well. And given the names "net.client" I assume both properties affect outgoing only, which for the second property is supported by its definition "[..] specifies the timeout (in milliseconds) when reading from input stream when a connection is established to a resource." Indeed, this makes one wonder if there are similar properties for sockets that have accepted an incoming connection, but I cannot quickly find those.
  • Arjan
    Arjan almost 15 years
    And, "These properties specify the default connect and read timeout (resp.) for the protocol handler used by java.net.URLConnection." So, outgoing only for sure. java.sun.com/javase/6/docs/technotes/guides/net/properties.h‌​tml
  • Cuga
    Cuga about 12 years
    Thank you for this. I was struggling with a SocketTimeoutException on Google App Engine and this got me past it.
  • erik
    erik over 10 years
    I just discovered that these properties are supposed to be set on command line or before doing anything Net-Connection related because "Yes, it [default timeouts] is cached, or more precisely it is looked up only at startup time. This is by design." See bugs.sun.com/bugdatabase/view_bug.do?bug_id=6245589.