How do I set a timeout on a SAAJ SOAPConnection using JBossWS?

Solution Verified - Updated -

Environment

  • JBoss Enterprise Application Platform (EAP)
    • 5.x
    • 6.x

Issue

How do I set a timeout on a SAAJ SOAPConnection in JBoss EAP?

Resolution

There are several ways to do this, depending on the version of EAP and web service stack used. Each method is listed in the order of most to least preferred and from most recent version of EAP to least recent.

EAP 6: JBossWS/CXF

The recommended approach in EAP 6 is to configure the client Bus to use an HTTPConduitConfigurer.

Here's the code sample:

import org.apache.cxf.BusFactory;
import org.apache.cxf.Bus;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transport.http.HTTPConduitConfigurer;
import org.apache.cxf.configuration.Configurer;

final HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setReceiveTimeout(5000L);
myBus.setExtension(new HTTPConduitConfigurer() {
  public void configure(String name, String address, HTTPConduit conduit) {
    conduit.setClient(policy);
  }
}, HTTPConduitConfigurer.class);

myBus is an instance of the CXF Bus used the the SAAJ client. This can be created with BusFactory.getInstance().createBus(). You then need to set and unset the bus before and after each client invocation. Like this:

BusFactory.setThreadDefaultBus(myBus);
URL endpoint = new URL("http://localhost:8080/saajTest/echo");
SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConnFactory.createConnection();
soapResponse = connection.call(message, endpoint);
BusFactory.setThreadDefaultBus(null);

You'll also need to add a couple module dependencies. Here's an example META-INF/jboss-deployment-structure.xml:

<jboss-deployment-structure>
  <deployment>
    <dependencies>
      <module name="org.apache.cxf"/>
      <module name="org.apache.cxf.impl"/>
    </dependencies>
  </deployment>
</jboss-deployment-structure>

EAP 5: JBossWS/CXF

This method is similar to EAP 6, but the HTTPConduitConfigurer API is not available.

import org.apache.cxf.BusFactory;
import org.apache.cxf.Bus;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.configuration.Configurer;

final HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setReceiveTimeout(5000L);
myBus.setExtension(new Configurer() {
  public void configureBean(Object o) {
    configureBean(null, o);
  }
  public void configureBean(String name, Object o) {
    if(o instanceof HTTPConduit) {
      ((HTTPConduit)o).setClient(policy);
    }
  }
}, Configurer.class);

The Bus needs to be set and unset just as above:

BusFactory.setThreadDefaultBus(myBus);
URL endpoint = new URL("http://localhost:8080/saajTest/echo");
SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConnFactory.createConnection();
soapResponse = connection.call(message, endpoint);
BusFactory.setThreadDefaultBus(null);

EAP 5: JBossWS/CXF (Spring)

This alternate method configures the timeout in jbossws-cxf.xml.

  1. Create the file WEB-INF/jbossws-cxf.xml in your SAAJ client deployment.
  2. Inside that file you'll need to create a HTTP conduit configuration for the endpoint you're interacting with via your SAAJ client.
  3. If you have any JAX-WS endpoints deployed along with your SAAJ client, you'll need to explicitly define them in your jbossws-cxf.xml.

There is no additional configuration in the code; the timeout is set only through the XML file.

Note that you must use the endpoint URL for the HTTP conduit's name attribute. You can also configure other attributes described on this CXF documentation page. Also note that some some of those settings may not be available in the version of CXF included in EAP because that page is for the latest version of CXF, though most are likely avaialble.

A reference jbossws-cxf.xml:

<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:http="http://cxf.apache.org/transports/http/configuration" 
   xmlns:jaxws="http://cxf.apache.org/jaxws" 
   xsi:schemaLocation="
       http://cxf.apache.org/transports/http/configuration
       http://cxf.apache.org/schemas/configuration/http-conf.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://cxf.apache.org/jaxws
       http://cxf.apache.org/schemas/jaxws.xsd">

  <http:conduit name="http://localhost:8080/helloWorldSaaj/HelloWorldImpl">
    <http:client ReceiveTimeout="3000"/>
  </http:conduit>
  <jaxws:endpoint id="HelloWorldImplPort" address="http://localhost:8080/helloWorldSaaj/HelloWorldImpl" implementor="com.jboss.examples.ws.HelloWorldImpl">
    <jaxws:invoker>
      <bean class="org.jboss.wsf.stack.cxf.InvokerJSE"/>
    </jaxws:invoker>
  </jaxws:endpoint>
  <jaxws:endpoint id="ClientEndpointPort" address="http://localhost:8080/helloWorldSaaj/ClientEndpoint" implementor="com.jboss.examples.ws.ClientEndpoint">
    <jaxws:invoker>
      <bean class="org.jboss.wsf.stack.cxf.InvokerJSE"/>
    </jaxws:invoker>
  </jaxws:endpoint>
</beans>

Note that this solution could likely be used in EAP 6 as well, but Spring needs to be manually installed, and the jbossws-cxf.xml should not have the <jaxws:invoker> elements.

EAP 5: JBossWS Native

This is the only solution when using JBossWS Native. There are some internal classes and APIs that will need to be used to make JBossWS read the timeout. Note that these classes do not appear to be indended for direct use by customers.

import org.jboss.ws.core.StubExt;
import org.jboss.ws.core.client.EndpointInfo;
import org.jboss.ws.metadata.umdm.EndpointMetaData;
import org.jboss.ws.metadata.umdm.ServiceMetaData;
import java.util.HashMap;

URL endpoint = new URL("http://localhost:8080/saajTest/echo");
HashMap<String, Object> props = new HashMap<String, Object>();
props.put(StubExt.PROPERTY_CLIENT_TIMEOUT, 5000);
ServiceMetaData serviceMetaData = new ServiceMetaData(null, null);
EndpointMetaData epMetaData = new EndpointMetaDataImpl(serviceMetaData);
EndpointInfo epInfo = new EndpointInfo(epMetaData, endpoint.toString(), props);

SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();
log.info("SOAPConnectionFactory class: " + soapConnFactory.getClass().getName());
SOAPConnection connection = soapConnFactory.createConnection();
soapResponse = connection.call(message, epInfo);

This solution also includes a simple implementation of EndpointMetaData:

public class EndpointMetaDataImpl extends EndpointMetaData {
  String address = null;

  public EndpointMetaDataImpl(ServiceMetaData smd) {
    super(smd, null, null, null);
  }

  public void setEndpointAddress(String add) {
    this.address = add;
  }

  public String getEndpointAddress() {
    return address;
  }
}

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

Close

Welcome! Check out the Getting Started with Red Hat page for quick tours and guides for common tasks.