How do I set the timeout for a JAX-WS webservice client?
Asked Answered
L

8

108

I've used JAXWS-RI 2.1 to create an interface for my web service, based on a WSDL. I can interact with the web service no problems, but haven't been able to specify a timeout for sending requests to the web service. If for some reason it does not respond the client just seems to spin it's wheels forever.

Hunting around has revealed that I should probably be trying to do something like this:

((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.ws.request.timeout", 10000);
((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.ws.connect.timeout", 10000);

I also discovered that, depending on which version of JAXWS-RI you have, you may need to set these properties instead:

((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.internal.ws.request.timeout", 10000);
((BindingProvider)myInterface).getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", 10000);

The problem I have is that, regardless of which of the above is correct, I don't know where I can do this. All I've got is a Service subclass that implements the auto-generated interface to the webservice and at the point that this is getting instanciated, if the WSDL is non-responsive then it's already too late to set the properties:

MyWebServiceSoap soap;
MyWebService service = new MyWebService("http://www.google.com");
soap = service.getMyWebServiceSoap();
soap.sendRequestToMyWebService();

Can anyone point me in the right direction?!

Lavender answered 27/1, 2010 at 17:21 Comment(2)
I don't think I have an answer for you, but your question helped me solve my problem. I knew about the com.sun.xml.ws.request.timeout property but not about the com.sun.xml.internal.ws.request.timeout one.Rosary
@RonTuffin I think the internal one is legacy and probably the non-internal one as well. I think in the future, the one starting with javax.xml.ws will become the standard. A good way to find out which is right is to search for a class named JAXWSProperties in your project and the right property is in there. You can even import it from there so that if you change an implementation, you will get notified of the change instead of having the functionality break as it happened to me while switching to Jakarta for an upgrade from Java 8 upwards :-)Carnify
P
106

I know this is old and answered elsewhere but hopefully this closes this down. I'm not sure why you would want to download the WSDL dynamically but the system properties:

sun.net.client.defaultConnectTimeout (default: -1 (forever))
sun.net.client.defaultReadTimeout (default: -1 (forever))

should apply to all reads and connects using HttpURLConnection which JAX-WS uses. This should solve your problem if you are getting the WSDL from a remote location - but a file on your local disk is probably better!

Next, if you want to set timeouts for specific services, once you've created your proxy you need to cast it to a BindingProvider (which you know already), get the request context and set your properties. The online JAX-WS documentation is wrong, these are the correct property names (well, they work for me).

MyInterface myInterface = new MyInterfaceService().getMyInterfaceSOAP();
Map<String, Object> requestContext = ((BindingProvider)myInterface).getRequestContext();
requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 3000); // Timeout in millis
requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 1000); // Timeout in millis
myInterface.callMyRemoteMethodWith(myParameter);

Of course, this is a horrible way to do things, I would create a nice factory for producing these binding providers that can be injected with the timeouts you want.

Photodisintegration answered 3/10, 2010 at 22:11 Comment(8)
Note that the REQUEST_TIMEOUT / CONNECT_TIMEOUT properties are actually inherited from the SUN-internal class com.sun.xml.internal.ws.developer.JAXWSProperties and (at least on 32-bit Linux) javac 1.6.0_27 and javac 1.7.0_03 fail to compile this code (similar to bugs.sun.com/view_bug.do?bug_id=6544224 )... you need to pass -XDignore.symbol.file to javac to make it work.Hartill
What doesn't work? I just double checked this and it is working for me.Photodisintegration
Just confirming that I just used this with JAX-WS RI 2.2.8 and JDK 1.7 and it worked just fine. Thank You!Scarletscarlett
Classes and parameters which have "internal" in their fully qualified name, should not be used, since are vendor-dependent and thus not portable among different JDK implementations. In the case of jax-ws parameters, for example, the corresponding non-internal properties exist in com.sun.xml.ws.client.BindingProviderProperties class.Detroit
@Detroit i am having the same problem, whats troubling is that my java 7 does not have the com.sun.xml.client package. i am not sure why, because im using the standard version java 7 from oracle - specifically java 7.0_79 and its missing the jaxws-rt.jar - why would that be the case?Melbamelborn
@Matt1776 yes of course it's missing: while JAX-WS is an API specification, you need a library implementation, in this case jaxws-ri.jar or jaxws-rt.jar, which is not part of the JDK. You just need to download and add it to your ptoject and you'll have those properties available.Detroit
Thank you. I've discovered this on another thread. Apparently its an external dependency. This was so completely counter intuitive to me that I assumed it had to be "missing".Melbamelborn
I have set the timeout as suggested but I still get some thread stuck at java.net.SocketInputStream.socketRead0(Native Method) what can I do?Pirogue
D
53

The properties in the accepted answer did not work for me, possibly because I'm using the JBoss implementation of JAX-WS?

Using a different set of properties (found in the JBoss JAX-WS User Guide) made it work:

//Set timeout until a connection is established
((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.connectionTimeout", "6000");

//Set timeout until the response is received
((BindingProvider) port).getRequestContext().put("javax.xml.ws.client.receiveTimeout", "1000");

UPDATE Newer JBoss spec location (names haven't changed). Request to standardize network timeout names.

Denizen answered 6/8, 2014 at 4:45 Comment(5)
I am not using JBoss, but only the properties in this comment worked for me, nothing else did.Matthiew
The property names depend on the JAX-WS implementation. A list can be found here: java.net/jira/browse/JAX_WS-1166Orland
java.net link is broken. github.com/javaee/metro-jax-ws/issues/1166Abdella
This worked for me on Wildfly 18 with java 11Atalee
For those who prefer to use contants I found these here: org.apache.cxf.message.Message#CONNECTION_TIMEOUT and org.apache.cxf.message.Message#RECEIVE_TIMEOUTMarkman
C
14

Here is my working solution :

// --------------------------
// SOAP Message creation
// --------------------------
SOAPMessage sm = MessageFactory.newInstance().createMessage();
sm.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
sm.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");

SOAPPart sp = sm.getSOAPPart();
SOAPEnvelope se = sp.getEnvelope();
se.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
se.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");

SOAPBody sb = sm.getSOAPBody();
// 
// Add all input fields here ...
// 

SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
// -----------------------------------
// URL creation with TimeOut connexion
// -----------------------------------
URL endpoint = new URL(null,
                      "http://myDomain/myWebService.php",
                    new URLStreamHandler() { // Anonymous (inline) class
                    @Override
                    protected URLConnection openConnection(URL url) throws IOException {
                    URL clone_url = new URL(url.toString());
                    HttpURLConnection clone_urlconnection = (HttpURLConnection) clone_url.openConnection();
                    // TimeOut settings
                    clone_urlconnection.setConnectTimeout(10000);
                    clone_urlconnection.setReadTimeout(10000);
                    return(clone_urlconnection);
                    }
                });


try {
    // -----------------
    // Send SOAP message
    // -----------------
    SOAPMessage retour = connection.call(sm, endpoint);
}
catch(Exception e) {
    if ((e instanceof com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl) && (e.getCause()!=null) && (e.getCause().getCause()!=null) && (e.getCause().getCause().getCause()!=null)) {
        System.err.println("[" + e + "] Error sending SOAP message. Initial error cause = " + e.getCause().getCause().getCause());
    }
    else {
        System.err.println("[" + e + "] Error sending SOAP message.");

    }
}
Cooney answered 1/12, 2010 at 10:5 Comment(3)
Are these configurations equivalent to "javax.xml.ws.client.connectionTimeout" and "javax.xml.ws.client.receiveTimeout" ??Backplate
For me this solution doesn't work on weblogic. On running in a normal java class this works fine. Any idea what could be the reason as i don't see any error stack for this.Litt
Worked for me using both com.sun.xml.internal.ws.request.timeout and URLConnection clone_urlconnection = clone_url.openConnection(); instead of HttpURLConnection clone_urlconnection = (HttpURLConnection) clone_url.openConnection();Anuria
U
12
ProxyWs proxy = (ProxyWs) factory.create();
Client client = ClientProxy.getClient(proxy);
HTTPConduit http = (HTTPConduit) client.getConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);
http.setClient(httpClientPolicy);

This worked for me.

Undemonstrative answered 14/7, 2011 at 21:37 Comment(2)
This uses Apache CXF classes though, it might be best to add this in the answer. A link to which CXF jars contain them would also help a lot.Ayurveda
@Ayurveda I agree. I answered this years ago and can't remember. Feel free to edit the answer.Undemonstrative
C
9

If you are using JAX-WS on JDK6, use the following properties:

com.sun.xml.internal.ws.connect.timeout
com.sun.xml.internal.ws.request.timeout
Chemmy answered 15/11, 2010 at 17:35 Comment(2)
System.setProperty("com.sun.xml.internal.ws.connect.timeout ", "300"); System.setProperty("com.sun.xml.internal.ws.request.timeout", "300") worked for me.Corrosive
In some contexts, you don't know programming-time which JAXWS version (internal or standalone) will be used run-time. The two are quite compatible, except for this timeout-feature. The keys are different (com.sun.xml.internal.ws.connect.timeout vs com.sun.xml.ws.connect.timeout) also the class (or interface) that define them (com.sun.xml.internal.ws.developer.JAXWSProperties/com.sun.xml.internal.ws.client.BindingProviderProperties vs com.sun.xml.ws.developer.JAXWSProperties/com.sun.xml.ws.client.BindingProviderProperties). My best idea is setting both, using literal values as keys.Lucid
L
5

In case your appserver is WebLogic (for me it was 10.3.6) then properties responsible for timeouts are:

com.sun.xml.ws.connect.timeout 
com.sun.xml.ws.request.timeout
Lethalethal answered 26/4, 2018 at 16:33 Comment(0)
R
3

Not sure if this will help in your context...

Can the soap object be cast as a BindingProvider ?

MyWebServiceSoap soap;
MyWebService service = new MyWebService("http://www.google.com");
soap = service.getMyWebServiceSoap();
// set timeouts here
((BindingProvider)soap).getRequestContext().put("com.sun.xml.internal.ws.request.timeout", 10000);
    soap.sendRequestToMyWebService();

On the other hand if you are wanting to set the timeout on the initialization of the MyWebService object then this will not help.

This worked for me when wanting to timeout the individual WebService calls.

Rosary answered 10/6, 2010 at 11:47 Comment(0)
B
2

the easiest way to avoid slow retrieval of the remote WSDL when you instantiate your SEI is to not retrieve the WSDL from the remote service endpoint at runtime.

this means that you have to update your local WSDL copy any time the service provider makes an impacting change, but it also means that you have to update your local copy any time the service provider makes an impacting change.

When I generate my client stubs, I tell the JAX-WS runtime to annotate the SEI in such a way that it will read the WSDL from a pre-determined location on the classpath. by default the location is relative to the package location of the Service SEI


<wsimport
    sourcedestdir="${dao.helter.dir}/build/generated"
    destdir="${dao.helter.dir}/build/bin/generated"
    wsdl="${dao.helter.dir}/src/resources/schema/helter/helterHttpServices.wsdl"
    wsdlLocation="./wsdl/helterHttpServices.wsdl"
    package="com.helter.esp.dao.helter.jaxws"
    >
    <binding dir="${dao.helter.dir}/src/resources/schema/helter" includes="*.xsd"/>
</wsimport>
<copy todir="${dao.helter.dir}/build/bin/generated/com/helter/esp/dao/helter/jaxws/wsdl">
    <fileset dir="${dao.helter.dir}/src/resources/schema/helter" includes="*" />
</copy>

the wsldLocation attribute tells the SEI where is can find the WSDL, and the copy makes sure that the wsdl (and supporting xsd.. etc..) is in the correct location.

since the location is relative to the SEI's package location, we create a new sub-package (directory) called wsdl, and copy all the wsdl artifacts there.

all you have to do at this point is make sure you include all *.wsdl, *.xsd in addition to all *.class when you create your client-stub artifact jar file.

(in case your curious, the @webserviceClient annotation is where this wsdl location is actually set in the java code

@WebServiceClient(name = "httpServices", targetNamespace = "http://www.helter.com/schema/helter/httpServices", wsdlLocation = "./wsdl/helterHttpServices.wsdl")
Biliary answered 25/6, 2010 at 20:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.