JAX-WS Client timeout Example
1. Introduction
In this post, we feature a comprehensive Example on JAX-WS Client timeout. Java API for XML Web Services (JAX-WS) specification was introduced in 2005. There are several tools that implement JAX-WS specification: JDK (since version 6), Apache CXF, Apache Axis, JBossWS, IBM WebSphere, and Oracle Weblogic. There are two common timeouts in client-server architecture:
- Read timeout – the timeout while waiting for the data from the server. Specifically, if the server fails to send the last byte within the read timeout setting, a read timeout error will be raised.
- Connection timeout – the timeout while making the initial connection between the client and server.
In this example, I will demonstrate how to set up these two timeout properties for JAX-WS clients.
2. Technologies Used
The example code in this article was built and run using:
- Java 1.8.101
- Maven 3.3.9
- Apache CXF 3.2.6
- Eclipse Oxygen
- Logback 1.2.3
3. Maven Project
In this step, I will create a Maven project which generates Java stubs from a calculator service.
3.1 Dependencies
The project contains several dependencies, the most important one is the JAX-WS JDK runtime library.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>jax-ws-client-timeout</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-rt --> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>2.1.3</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- logback --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-access</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>2.5</version> <executions> <execution> <id>jaxws-calculator_wsdl</id> <goals> <goal>wsimport</goal> </goals> <configuration> <wsdlUrls> <wsdlUrl>http://www.dneonline.com/calculator.asmx?wsdl</wsdlUrl> </wsdlUrls> <keep>true</keep> <packageName>jcg.zheng.demo.jaxws.client.calculator</packageName> <sourceDestDir>${basedir}/src/main/jaxws</sourceDestDir> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>3.2.6</version> <executions> <execution> <id>generate-sources</id> <phase>generate-sources</phase> <configuration> <sourceRoot>${basedir}/src/main/cxf</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl>http://www.dneonline.com/calculator.asmx?wsdl</wsdl> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
4. Generated Java Stubs
Execute mvn clean install
to generate the Java stubs from http://www.dneonline.com/calculator.asmx?wsdl.
We should not modify the generated files.
4.1 Generated Files from wsimport
Use wsimport
from jaxws-maven-plugin
to generate files at /src/main/jaxws
.
List of Java Files Generated
C:\gitworkspace\jax-ws-client-timeout\src\main\jaxws\jcg\zheng\demo\jaxws\client\calculator>dir Volume in drive C is OSDisk Volume Serial Number is 3A10-C6D4 Directory of C:\gitworkspace\jax-ws-client-timeout\src\main\jaxws\jcg\zheng\demo\jaxws\client\calculator 09/08/2018 08:31 AM <DIR> . 09/08/2018 08:31 AM <DIR> .. 09/08/2018 08:31 AM 1,622 Add.java 09/08/2018 08:31 AM 1,367 AddResponse.java 09/08/2018 08:31 AM 2,976 Calculator.java 09/08/2018 08:31 AM 3,806 CalculatorSoap.java 09/08/2018 08:31 AM 1,628 Divide.java 09/08/2018 08:31 AM 1,403 DivideResponse.java 09/08/2018 08:31 AM 1,632 Multiply.java 09/08/2018 08:31 AM 1,427 MultiplyResponse.java 09/08/2018 08:31 AM 2,290 ObjectFactory.java 09/08/2018 08:31 AM 190 package-info.java 09/08/2018 08:31 AM 1,632 Subtract.java 09/08/2018 08:31 AM 1,427 SubtractResponse.java 12 File(s) 21,400 bytes 2 Dir(s) 22,013,812,736 bytes free
4.2 Generated Files from wsdl2java
Use wsdl2java
from cxf-codegen-plugin
to generate stubs at /src/main/cxf
.
List of Java Files Generated
C:\gitworkspace\jax-ws-client-timeout\src\main\cxf\org\tempuri>dir Volume in drive C is OSDisk Volume Serial Number is 3A10-C6D4 Directory of C:\gitworkspace\jax-ws-client-timeout\src\main\cxf\org\tempuri 09/09/2018 08:39 AM <DIR> . 09/09/2018 08:39 AM <DIR> .. 09/09/2018 08:39 AM 1,625 Add.java 09/09/2018 08:39 AM 1,367 AddResponse.java 09/09/2018 08:39 AM 3,629 Calculator.java 09/09/2018 08:39 AM 3,178 CalculatorSoap.java 09/09/2018 08:39 AM 1,631 Divide.java 09/09/2018 08:39 AM 1,403 DivideResponse.java 09/09/2018 08:39 AM 1,635 Multiply.java 09/09/2018 08:39 AM 1,427 MultiplyResponse.java 09/09/2018 08:39 AM 2,209 ObjectFactory.java 09/09/2018 08:39 AM 163 package-info.java 09/09/2018 08:39 AM 1,635 Subtract.java 09/09/2018 08:39 AM 1,427 SubtractResponse.java 12 File(s) 21,329 bytes 2 Dir(s) 22,013,902,848 bytes free C:\gitworkspace\jax-ws-client-timeout\src\main\cxf\org\tempuri>
5. Calculator Service Clients
We can set the JAX-WS clients’ read and connection timeout values via the BindingProviderPropertie's
two constants: CONNECT_TIMEOUT
and REQUEST_TIMEOUT
.
5.1 JAX-WS Client
In this step, I will create the JAXWS_CalculatorServiceClient
class. It has a constructor which sets the read and connection timeouts.
JAXWS_CalculatorServiceClient.java
package jcg.zheng.jaxws.client.timeoutdemo; import java.util.Map; import javax.xml.ws.BindingProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sun.xml.ws.client.BindingProviderProperties; import jcg.zheng.demo.jaxws.client.calculator.Calculator; import jcg.zheng.demo.jaxws.client.calculator.CalculatorSoap; public class JAXWS_CalculatorServiceClient { private final Logger lOG = LoggerFactory.getLogger(this.getClass()); private CalculatorSoap service; public JAXWS_CalculatorServiceClient() { super(); Calculator calculator = new Calculator(); service = calculator.getCalculatorSoap(); } public JAXWS_CalculatorServiceClient(Integer connectTimeoutInMS, Integer readTimeoutInMS) { this(); if (readTimeoutInMS != null || connectTimeoutInMS != null) { Map requestCtx = ((BindingProvider) service).getRequestContext(); lOG.info("JAX_WS Client Read_Timeout=" + readTimeoutInMS + " Connect_Timeout=" + connectTimeoutInMS); requestCtx.put(BindingProviderProperties.REQUEST_TIMEOUT, readTimeoutInMS); requestCtx.put(BindingProviderProperties.CONNECT_TIMEOUT, connectTimeoutInMS); } } public int addTwoNumber(int num1, int num2) { return service.add(num1, num2); } }
5.2 CXF Client
In this step, I will create the CXF_CalculatorServiceClient
class similar to JAXWS_CalculatorServiceClient
but with the stubs generated from the CXF plugin.
CXF_CalculatorServiceClient.java
package jcg.zheng.jaxws.client.timeoutdemo; import java.util.Map; import javax.xml.ws.BindingProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tempuri.*; import com.sun.xml.ws.client.BindingProviderProperties; public class CXF_CalculatorServiceClient { private final Logger lOG = LoggerFactory.getLogger(this.getClass()); private CalculatorSoap service; public CXF_CalculatorServiceClient() { super(); Calculator calculator = new Calculator(); service = calculator.getCalculatorSoap(); } public CXF_CalculatorServiceClient(Integer connectTimeoutInMS, Integer readTimeoutInMS) { this(); if (readTimeoutInMS != null || connectTimeoutInMS != null) { Map requestCtx = ((BindingProvider) service).getRequestContext(); lOG.info("CXF JAX_WS Client Read_Timeout=" + readTimeoutInMS + " Connect_Timeout=" + connectTimeoutInMS); requestCtx.put(BindingProviderProperties.REQUEST_TIMEOUT, readTimeoutInMS); requestCtx.put(BindingProviderProperties.CONNECT_TIMEOUT, connectTimeoutInMS); } } public int timesTwoNumber(int num1, int num2) { return service.multiply(num1, num2); } }
5.3 Demo Client Timeout with Junit Test
In this step, I will create a ServiceClientTimeoutTest
to test the timeout settings.
ServiceClientTimeoutTest.java
package jcg.zheng.jaxws.client.timeoutdemo; import static org.junit.Assert.assertEquals; import org.junit.Test; public class ServiceClientTimeoutTest { private static final int READ_TIMEOUT_OK = 1000; private static final int READ_TIMEOUT_EXCEPTION = 10; private static final int CONNECT_TIMEOUT_OK = 10; private JAXWS_CalculatorServiceClient jaxCalculatorService; private CXF_CalculatorServiceClient cxfCalculatorService; @Test public void jaxwsClient_returns_data_happyPath() { jaxCalculatorService = new JAXWS_CalculatorServiceClient(CONNECT_TIMEOUT_OK, READ_TIMEOUT_OK); int sum = jaxCalculatorService.addTwoNumber(3, 4); assertEquals(7, sum); } @Test public void cxfClient_returns_data_happyPath() { cxfCalculatorService = new CXF_CalculatorServiceClient(CONNECT_TIMEOUT_OK, READ_TIMEOUT_OK); int product = cxfCalculatorService.timesTwoNumber(3, 4); assertEquals(12, product); } @Test(expected = javax.xml.ws.WebServiceException.class) public void jaxwsClient_throw_Exception_when_fails_to_read() { jaxCalculatorService = new JAXWS_CalculatorServiceClient(CONNECT_TIMEOUT_OK, READ_TIMEOUT_EXCEPTION); jaxCalculatorService.addTwoNumber(3, 4); } @Test(expected = javax.xml.ws.WebServiceException.class) public void cxfClient_throw_Exception_when_fails_to_read() { cxfCalculatorService = new CXF_CalculatorServiceClient(CONNECT_TIMEOUT_OK, READ_TIMEOUT_EXCEPTION); cxfCalculatorService.timesTwoNumber(3, 4); } }
6. JDK Timeout
JDK provides a list of network properties. We are interested in the defaultConnectionTimeout
and the defaultReadTimeout
, which specifies the default connection and read timeout for the protocol handler used by java.net.URLConnection
.
sun.net.client.defaultConnectTimeout
– the timeout in milliseconds to establish the connection to the host.sun.net.client.defaultReadTimeout
– the timeout in milliseconds when reading from input stream when a connection is established to a resource.
In this step, I will create a Java application which sets up the JDK network connection timeout properties.
TimeoutDemo .java
package jcg.zheng.jaxws.client.timeoutdemo; import java.util.Scanner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TimeoutDemo { private static final Logger LOG = LoggerFactory.getLogger(TimeoutDemo.class); private static final String JDK_READ_TIMEOUT = "sun.net.client.defaultReadTimeout"; private static final String JDK_CONNECTION_TIMEOUT = "sun.net.client.defaultConnectTimeout"; public static void main(String[] args) { JAXWS_CalculatorServiceClient calculator = null; CXF_CalculatorServiceClient calculator_cxf = null; Scanner scanIn = new Scanner(System.in); displayJVMTimeout(); System.out.println("Enter JVM Timeout in Milliseconds: (-1 to ignore) "); String jvmTimeoutInput = scanIn.nextLine(); System.out.println("Enter JAX-WS Client Timeout in Milliseconds: (-1 to ignore) "); String clientTimeoutInput = scanIn.nextLine(); if( jvmTimeoutInput.equalsIgnoreCase("-1")) { LOG.info("Ingore JVM Timeout setting."); } else { setTimeOutWithJVMProperties(jvmTimeoutInput); displayJVMTimeout(); } if (clientTimeoutInput.equalsIgnoreCase("-1")) { LOG.info("Ingore Client Timeout setting."); calculator = new JAXWS_CalculatorServiceClient(); calculator_cxf = new CXF_CalculatorServiceClient(); } else { Integer timeoutInt = Integer.parseInt(clientTimeoutInput); calculator = new JAXWS_CalculatorServiceClient(timeoutInt, timeoutInt); calculator_cxf = new CXF_CalculatorServiceClient(timeoutInt, timeoutInt); } try { int sum = calculator.addTwoNumber(3, 4); LOG.info("Calculator.add returns: " + sum + " for 3 + 4"); } catch (Exception e) { e.printStackTrace(); } try { int product = calculator_cxf.timesTwoNumber(4, 5); LOG.info("Calculator.multiply returns: " + product + " for 4 x 5 "); } catch (Exception e) { e.printStackTrace(); } scanIn.close(); } private static void setTimeOutWithJVMProperties(String timeoutValue) { LOG.info("Update the JVM timeout setting:" + timeoutValue); System.setProperty(JDK_CONNECTION_TIMEOUT, timeoutValue); System.setProperty(JDK_READ_TIMEOUT, timeoutValue); } private static void displayJVMTimeout() { System.out.println("Current JDK Connection Timeout setting:" + System.getProperty(JDK_CONNECTION_TIMEOUT)); System.out.println("Current JDK Read Timeout setting:" + System.getProperty(JDK_READ_TIMEOUT)); } }
6.1 Demo 1
Execute TimeoutDemo
as a Java application. Use the default value by ignoring the timeout setting.
Console Output
Current JDK Connection Timeout setting:null Current JDK Read Timeout setting:null Enter JVM Timeout in Milliseconds: (-1 to ignore) -1 Enter JAX-WS Client Timeout in Milliseconds: (-1 to ignore) -1 11:47:51.422 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Ingore JVM Timeout setting. 11:47:51.433 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Ingore Client Timeout setting. 11:47:52.886 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Calculator.add returns: 7 for 3 + 4 11:47:52.981 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Calculator.multiply returns: 20 for 4 x 5
6.2 Demo 2
Execute TimeoutDemo
as a Java application. Set the JVM timeout to 10 seconds and ignore the client’s timeout setting.
Console Output
Current JDK Connection Timeout setting:null Current JDK Read Timeout setting:null Enter JVM Timeout in Milliseconds: (-1 to ignore) 10000 Enter JAX-WS Client Timeout in Milliseconds: (-1 to ignore) -1 11:52:38.623 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Update the JVM timeout setting:10000 Current JDK Connection Timeout setting:10000 Current JDK Read Timeout setting:10000 11:52:38.635 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Ingore Client Timeout setting. 11:52:40.098 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Calculator.add returns: 7 for 3 + 4 11:52:40.239 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Calculator.multiply returns: 20 for 4 x 5
6.3 Demo 3
Execute TimeoutDemo
as a Java application. Set the client’s timeout to 10 seconds and JVM timeout to 1 ms.
Console Output
Current JDK Connection Timeout setting:null Current JDK Read Timeout setting:null Enter JVM Timeout in Milliseconds: (-1 to ignore) 1 Enter JAX-WS Client Timeout in Milliseconds: (-1 to ignore) 10000 11:53:41.421 [main] INFO jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo - Update the JVM timeout setting:1 Current JDK Connection Timeout setting:1 Current JDK Read Timeout setting:1 Exception in thread "main" javax.xml.ws.WebServiceException: Failed to access the WSDL at: http://www.dneonline.com/calculator.asmx?wsdl. It failed with: connect timed out. at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(RuntimeWSDLParser.java:162) at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:144) at com.sun.xml.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:263) at com.sun.xml.ws.client.WSServiceDelegate.(WSServiceDelegate.java:226) at com.sun.xml.ws.client.WSServiceDelegate.(WSServiceDelegate.java:174) at com.sun.xml.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:104) at javax.xml.ws.Service.(Service.java:77) at jcg.zheng.demo.jaxws.client.calculator.Calculator.(Calculator.java:42) at jcg.zheng.jaxws.client.timeoutdemo.JAXWS_CalculatorServiceClient.(JAXWS_CalculatorServiceClient.java:22) at jcg.zheng.jaxws.client.timeoutdemo.JAXWS_CalculatorServiceClient.(JAXWS_CalculatorServiceClient.java:27) at jcg.zheng.jaxws.client.timeoutdemo.TimeoutDemo.main(TimeoutDemo.java:39) Caused by: java.net.SocketTimeoutException: connect timed out at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at sun.net.NetworkClient.doConnect(NetworkClient.java:178) at sun.net.www.http.HttpClient.openServer(HttpClient.java:432) at sun.net.www.http.HttpClient.openServer(HttpClient.java:527) at sun.net.www.http.HttpClient.(HttpClient.java:211) at sun.net.www.http.HttpClient.New(HttpClient.java:308) at sun.net.www.http.HttpClient.New(HttpClient.java:326) at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1168) at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1104) at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:998) at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:932) at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1512) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1440) at java.net.URL.openStream(URL.java:1038) at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.createReader(RuntimeWSDLParser.java:805) at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.resolveWSDL(RuntimeWSDLParser.java:262) at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:129) ... 9 more
7. JAX-WS Client timeout – Summary
In this article, I demonstrated how to generate JAX-WS clients and set the client read and connection timeout values. There are timeout setting at JVM, OS, and Socket. You should consider these settings when troubleshooting the timeout issues.
8. Download the Source Code
This tutorial consists of a Maven project which demonstrated how to set JAX-WS Client connection and request timeout values.
You can download the full source code of this example here: JAX-WS Client Timeout Example