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

I work with a slightly outdated component in which we interact with the SOAP web service (a technology that I absolutely, positively hate) using some client code built using the JAXRPC-RI library (reference implementation).

I am interested in setting a timeout using stubs so that if the web services server does not respond within X seconds, the application does not set there to wait for a response forever.

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

Throughout life, I cannot figure out how to set a timeout when using Stubs created using JAXRPC-RI:

  • The port class that I create extends com.sun.xml.rpc.client.StubBase and implements javax.xml.rpc.Stub and com.sun.xml.rpc.spi.runtime.StubBase .
  • In JavaDocs, none of these classes mention any timeout or method for this.
  • Attempted code like stub._setProperty("axis.connection.timeout", 1000); raises 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 / apply a timeout when using the JAXRPC-RI client? Is it possible?

+6
java java-ee soap web-services jax-rpc
source share
8 answers

You may have luck settings properties such as sun.net.client.defaultConnectTimeout or sun.net.client.defaultReadTimeout , although this will bypass the entire system.

In the code, property values ​​are set using the lines:

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

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

 java -Dsun.net.client.defaultConnectTimeout="1000" ... 
+4
source share

I am not sure why this particular JAXRPC implementation does not allow a timeout. Perhaps there is a good reason for this. Other implementations, such as Axis and, I believe, JAX-WS, make it easy to call the setTimeout () method on Stub. After some pain, I was able to come up with this solution. Hope this will be helpful. To set the timeout in the base URL connection, you will need to do the following:

  • Create a new ClientTransport class. It should extend the class com.sun.xml.rpc.client.http.HttpClientTransport. Override the createHttpConnection (String, SOAPMessageContext) method. Call super.createHttpConnection (), which will return an HttpURLConnection object. On the HttpURLConnection object, you can call setReadTimeout (), which will force the client-side timeout in X milliseconds. After that, return the modified HttpURLConnection object.
  • Extend the client side Stub class yourself. Override the _getTransport () method to return a new instance of the ClientTransport class that you created in step (1).
  • Extend the client-side _Impl class. Override the get ... Port () method to use the Stub created in step (2) instead of the generated one.
  • Change the client code that you wrote to call the web service so that it uses the Stub created in step (2) and the _Impl that you created in step (3).

Note. Make sure that everything you call to create Stubs via wscompile (Ant script?) Does not overwrite the 3 Java classes that you just created / modified. It probably makes sense to move them to another package so that they do not correspond.

+2
source share

Eugene Traivus' answer is very good, but leads to the creation of a new HTTPUrlConnection for each SOAP call. I found out by checking his approach that you can install ClientTransportFactory. Now I use CustomClientTransportFactory and set it to Stub (dropping it to StubBase). Then you do not need steps 2 and 3.

In step 4, a new ClientTransportFactory is then installed as follows: ((StubBase) myPort) ._ setTransportFactory (new CustomClientTransportFactory ());

+1
source share

I’m going to try to earn generosity, so don’t shoot me if I’m completely mistaken :) If your application "constantly evokes an expectation of an answer" than you could make a request in a separate thread and after spawning your requestThread you could just say requestThread.join(max_time_to_wait); , the next call will check if the requestThread file is alive, and if it tries to kill it.

Your application will move after a timeout, and this is not the most inelegant solution ...

0
source share

Ray,

Thanks for your input. It seems your approach is excellent, as it avoids a few extraneous steps. I need to take a look. However, if I am missing something, I don’t think that an additional HttpConnection is being created, because YourClientTransport.createHttpConnection (String s, SOAPMessageContext ctx) should override HttpClientTransport:

 public class YourClientTransport extends HttpClientTransport { @Override protected HttpUrlConnection createHttpConnection(String s, SOAPMessageContext ctx) throws IOException { HttpURLConnection httpURLConnection = super.createHttpConnection(s, ctx); httpURLConnection.setReadTimeout(1000); httpURLConnection.setConnectTimeout(1000); return httpURLConnection; } } 
0
source share

I know you use Axis, but I struggled to find the same answer for Weblogic, and since your question name and tags are common, here is my solution.

In my client class that implements the generated MyObject interface, I adapted 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 really is in milliseconds!

0
source share

Perhaps a little late for this question, but today I came to this problem. Based on the solution proposed by Eugene Trayvus (thanks for that!), I came up with the following:

 ((com.sun.xml.rpc.client.StubBase)myRemoteStub)._setTransportFactory(new ClientTransportFactory() { @Override public ClientTransport create() { return new HttpClientTransport() { @Override protected HttpURLConnection createHttpConnection(String endpoint, SOAPMessageContext context) throws IOException { HttpURLConnection conn = super.createHttpConnection(endpoint, context); conn.setConnectTimeout(2000); conn.setReadTimeout(2000); return conn; } }; } }); 

This is basically the same as Eugene, but with a slightly less redefinition (using the factory connection).

0
source share

You should use:

 import javax.xml.rpc.Stub; ... int timeout = <number of milliseconds>; ((Stub) port)._setProperty( "axis.connection.timeout", timeout); 
-one
source share

All Articles