Spring WS Intercept Request Response Soap Messages
In the previous tutorial we saw how to produce and consume a Spring WS Soap Service. This time, we show you how to use Spring Ws Endpoint Interceptors. These endpoint interceptors can be used for intercepting response and or request soap messages, intercepting exceptions and execute some code after completion. We can register interceptors for a specific endpoint only or a global interceptor. We use Java Configuration to register our custom interception and spring boot to bootstrap the application.
Spring WS Intercept Soap Messages
Global Interceptor
Interceptors must implement the EndpointInterceptor
interface. This interface defines 4 methods.
- handleRequest this method is invoked before the endpoint and returns a boolean value. You can use this method to interrupt or continue the processing of the invocation chain. When this method returns true, the endpoint execution chain will continue. When it returns false, the
MessageDispatcher
interrupts the invocation chain. Which means that it will not continue to invoke interceptors or endpoints in the chain. - handleResponse and handleFault are executed after the invocation of the endpoint and are used for post-processing. These methods all return a boolean when they return false, the response will not be sent back to the client.
- afterCompletion is executed after the endpoint is executed and does not return anything because it’s the last step in the chain.
package com.memorynotfound.server;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
@Component
public class GlobalEndpointInterceptor implements EndpointInterceptor {
private static final Log LOG = LogFactory.getLog(GlobalEndpointInterceptor.class);
@Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
LOG.info("Global Request Handling");
return true;
}
@Override
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
LOG.info("Global Response Handling");
return true;
}
@Override
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
LOG.info("Global Exception Handling");
return true;
}
@Override
public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {
LOG.info("Execute Code After Completion");
}
}
Endpoint Interceptor
We can also bind an interceptor to a specific endpoint. Here is the custom interceptor that we are going to bind to the endpoint. Note that this class also implements the EndpointInterceptor
. The binding happens in the Configuration.
package com.memorynotfound.server;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
@Component
public class CustomEndpointInterceptor implements EndpointInterceptor {
private static final Log LOG = LogFactory.getLog(CustomEndpointInterceptor.class);
@Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
LOG.info("Endpoint Request Handling");
return true;
}
@Override
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
LOG.info("Endpoint Response Handling");
return true;
}
@Override
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
LOG.info("Endpoint Exception Handling");
return true;
}
@Override
public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {
LOG.info("Execute code after completion");
}
}
Configure Interceptor using Spring Java Configuration
Now we have written our CustomEndpointInterceptor
we need to tell Spring WS to use it. We do this by overriding the addInterceptors
method of the WsConfigurerAdapter
. We define a global interceptor by just adding it to the interceptors list. For an endpoint specific interceptor we must use the PayloadRootSmartSoapEndpointInterceptor
class which takes a delegate interceptor, a namespace and a localPart as arguments. The interceptor uses the namespace and local part to map the interceptor to the endpoint.
package com.memorynotfound.server;
import org.springframework.context.annotation.Configuration;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.server.EndpointInterceptor;
...
@EnableWs
@Configuration
public class SoapServerConfig extends WsConfigurerAdapter {
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
// register global interceptor
interceptors.add(new CustomEndpointInterceptor());
// register endpoint specific interceptor
interceptors.add(new PayloadRootSmartSoapEndpointInterceptor(
new CustomEndpointInterceptor(),
BeerEndpoint.NAMESPACE,
BeerEndpoint.BEER_REQUEST_LOCAL_PART));
}
...
}
References
- EndpointInterceptor JavaDoc
- WsConfigurerAdapter JavaDoc
- Spring WS API
- Spring WS Reference Documentation
Thank you!
Thanks so much. It helped me tackling the problem.
In Spring-WS-Core 2.4.x, it doesn’t work this way anymore. It seems SmartInterceptors are obtained by their bean type, not in the interceptor array anymore.
So define PayloadRootSmartSoapEndpointInterceptor just as beans.
@Bean
PayloadValidatingInterceptor myEndpointValidatingInterceptor() {
PayloadValidatingInterceptor interceptor = new PayloadValidatingInterceptor()
interceptor.schema = new ClasspathResource(MyEndpoint.SCHEMA_FILE_NAME)
interceptor.validateRequest = true
interceptor.validateResponse = true
return interceptor
}
// Per Endpoint Namespace validator. Obtained by type.
@Bean
PayloadRootSmartSoapEndpointInterceptor myEndpointValidator() {
return new PayloadRootSmartSoapEndpointInterceptor(myEndpointValidatingInterceptor(), MyEndpoint.NAMESPACE_URI, null)
}
Thank you!
Thanks! How can I log raw body payload?