Saturday, 29 July 2017

SOAP client Custom Timeout


The interceptor-based solution provides a very flexible way of configuring timeouts for Apache CXF based SOAP clients.For custom timeout configuration per operation(Methods defined inside wsdl), we will use an interceptor that sets a MessageProperty. It must be configured in the right Phase, otherwise, the MessageProperty might not have an effect. 


Java Interceptor : 

package com.interceptor;

import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.cxf.interceptor.MessageSenderInterceptor;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;


/**
 * <p>
 * An SOAPCustomTimeoutInterceptor {@link AbstractPhaseInterceptor} that
 * timeout based on the QName of the operation.
 * </p>
 *
 */
public class SOAPCustomTimeoutInterceptor extends AbstractPhaseInterceptor<Message> {


  /** Keep all timeouts per OperationName in milliseconds */
  private Map<QName, Long> receiveTimeoutByOperationName = new HashMap<QName, Long>();

  public SOAPCustomTimeoutInterceptor(String phase) {
    super(phase);
    addBefore(MessageSenderInterceptor.class.getName());
  }

  public SOAPCustomTimeoutInterceptor() {
    this(Phase.PREPARE_SEND);
  }

  /**
   * Setting timeout based on QName in message
   * 
   * @param message
   */
  @Override
  public void handleMessage(Message message) {
    final QName operationName = message.getExchange().getBindingOperationInfo().getName();
    final Long receiveTimeout = receiveTimeoutByOperationName.get(operationName);
    if (receiveTimeout != null) {
      message.put(Message.RECEIVE_TIMEOUT, receiveTimeout);
    }
  }

  public void setReceiveTimeoutByOperationName(Map<QName, Long>receiveTimeoutByOperationName) {
    this.receiveTimeoutByOperationName = receiveTimeoutByOperationName;
  }
}

This handleMessage takes a Map of operation QNames and timeout-values. If it finds a match, it configures the timeout, otherwise, it does nothing.

Spring Configuration :

<?xml version="1.0" encoding="UTF-8"?>

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

<cxf:cxfEndpoint id="bookService"
address="http://locathost:8080/someServiceName"
serviceClass="someServiceClass" />
<cxf:outInterceptors>
<ref bean="timeoutPerOperation" />
</cxf:outInterceptors>
</cxf:cxfEndpoint>

<bean  id="timeoutPerOperation" class="sample.camel.CustomTimeoutInterceptor"
<property name="receiveTimeoutByOperationName">
<map key-type="javax.xml.namespace.QName" value-type="java.lang.Long">
<entry value="600">
<key>
<bean class="javax.xml.namespace.QName" factory-method="valueOf">
<constructor-arg value="{http://tempuri.org/}someMethod" />
</bean>
</key>
</entry>
</map>
</property>
</bean>   

</beans>

Above configuration defines timeout per operation wise.You can add N entries inside the map with different with operations.{http://tempuri.org/} - is target namespace defined in WSDL file.tns defines the target name space.
example : xmlns:tns="http://tempuri.org/"
someMethod - is operation name defined in WSDL file.Inside portType name tag, you can find all opertion name(method name).

No comments:

Post a Comment