From ac030c2ff3ae1dd2879647a7aad3f4e2f4b0f7f6 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 18 Mar 2014 15:47:28 +0100 Subject: [PATCH] Added afterCompletion to ClientInterceptor Added the afterCompletion hook to ClientInterceptor, similar to the existing one in EndpointInterceptor. Issue: SWS-778 --- .../ws/client/core/WebServiceTemplate.java | 38 ++++++++++++++++++- .../AbstractValidatingInterceptor.java | 7 +++- .../interceptor/ClientInterceptor.java | 18 +++++++++ .../client/core/WebServiceTemplateTest.java | 4 ++ .../AbstractWsSecurityInterceptor.java | 9 ++++- 5 files changed, 72 insertions(+), 4 deletions(-) diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java index e22d2584..6cb9edb6 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java @@ -568,12 +568,12 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService WebServiceConnection connection, WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) throws IOException { + int interceptorIndex = -1; try { if (requestCallback != null) { requestCallback.doWithMessage(messageContext.getRequest()); } // Apply handleRequest of registered interceptors - int interceptorIndex = -1; if (interceptors != null) { for (int i = 0; i < interceptors.length; i++) { interceptorIndex = i; @@ -586,7 +586,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService if (!messageContext.hasResponse()) { sendRequest(connection, messageContext.getRequest()); if (hasError(connection, messageContext.getRequest())) { - return (T)handleError(connection, messageContext.getRequest()); + triggerAfterCompletion(interceptorIndex, messageContext, null); + return (T) handleError(connection, messageContext.getRequest()); } WebServiceMessage response = connection.receive(getMessageFactory()); messageContext.setResponse(response); @@ -595,10 +596,12 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService if (messageContext.hasResponse()) { if (!hasFault(connection, messageContext.getResponse())) { triggerHandleResponse(interceptorIndex, messageContext); + triggerAfterCompletion(interceptorIndex, messageContext, null); return responseExtractor.extractData(messageContext.getResponse()); } else { triggerHandleFault(interceptorIndex, messageContext); + triggerAfterCompletion(interceptorIndex, messageContext, null); return (T)handleFault(connection, messageContext); } } @@ -607,8 +610,19 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } } catch (TransformerException ex) { + triggerAfterCompletion(interceptorIndex, messageContext, ex); throw new WebServiceTransformerException("Transformation error: " + ex.getMessage(), ex); } + catch (RuntimeException ex) { + // Trigger after-completion for thrown exception. + triggerAfterCompletion(interceptorIndex, messageContext, ex); + throw ex; + } + catch (IOException ex) { + // Trigger after-completion for thrown exception. + triggerAfterCompletion(interceptorIndex, messageContext, ex); + throw ex; + } } /** Sends the request in the given message context over the connection. */ @@ -758,6 +772,26 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } } + /** + * Trigger afterCompletion callbacks on the mapped ClientInterceptors. Will just + * invoke afterCompletion for all interceptors whose handleRequest invocation has + * successfully completed and returned true, in addition to the last interceptor who + * returned false. + * @param mappedEndpoint the mapped EndpointInvocationChain + * @param interceptorIndex index of last interceptor that successfully completed + * @param ex Exception thrown on handler execution, or null if none + * @see ClientInterceptor#afterCompletion + */ + private void triggerAfterCompletion(int interceptorIndex, + MessageContext messageContext, Exception ex) + throws WebServiceClientException { + if (interceptors != null) { + for (int i = interceptorIndex; i >= 0; i--) { + interceptors[i].afterCompletion(messageContext, ex); + } + } + } + /** * Handles an fault in the given response message. The default implementation invokes the {@link * FaultMessageResolver fault resolver} if registered, or invokes {@link #handleError(WebServiceConnection, diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java index b64e7cbc..e44ae575 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java @@ -257,7 +257,12 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup return true; } - /** + /** Does nothing by default.*/ + public void afterCompletion(MessageContext messageContext, Exception ex) + throws WebServiceClientException { + } + + /** * Abstract template method that returns the part of the request message that is to be validated. * * @param request the request message diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java index 4c62ac5e..1353e63a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java @@ -58,6 +58,8 @@ public interface ClientInterceptor { /** * Processes the incoming response message. Called for non-fault response messages before payload handling in the * {@link org.springframework.ws.client.core.WebServiceTemplate}. + *

+ * Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed. * * @param messageContext contains the outgoing request message * @return true to continue processing of the request interceptors; false to indicate @@ -70,6 +72,8 @@ public interface ClientInterceptor { /** * Processes the incoming response fault. Called for response fault messages before payload handling in the {@link * org.springframework.ws.client.core.WebServiceTemplate}. + *

+ * Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed. * * @param messageContext contains the outgoing request message * @return true to continue processing of the request interceptors; false to indicate @@ -80,4 +84,18 @@ public interface ClientInterceptor { */ boolean handleFault(MessageContext messageContext) throws WebServiceClientException; + /** + * Callback after completion of request and response (fault) processing. Will be called on any outcome, thus + * allows for proper resource cleanup. + *

+ * Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed. + * + * @param messageContext contains both request and response messages, the response should contains a Fault + * @param ex exception thrown on handler execution, if any + * @throws WebServiceClientException in case of errors + * @since 2.2 + */ + void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException; + + } diff --git a/spring-ws-core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java b/spring-ws-core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java index e82b039a..da78f171 100644 --- a/spring-ws-core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java +++ b/spring-ws-core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java @@ -378,6 +378,8 @@ public class WebServiceTemplateTest { expect(interceptorMock2.handleRequest(isA(MessageContext.class))).andReturn(true); expect(interceptorMock2.handleResponse(isA(MessageContext.class))).andReturn(true); expect(interceptorMock1.handleResponse(isA(MessageContext.class))).andReturn(true); + interceptorMock2.afterCompletion(isA(MessageContext.class), (Exception)isNull()); + interceptorMock1.afterCompletion(isA(MessageContext.class), (Exception)isNull()); WebServiceMessageCallback requestCallback = createMock(WebServiceMessageCallback.class); requestCallback.doWithMessage(isA(WebServiceMessage.class)); @@ -409,6 +411,7 @@ public class WebServiceTemplateTest { template.setInterceptors(new ClientInterceptor[]{interceptorMock1, interceptorMock2}); expect(interceptorMock1.handleRequest(isA(MessageContext.class))).andReturn(false); expect(interceptorMock1.handleResponse(isA(MessageContext.class))).andReturn(true); + interceptorMock1.afterCompletion(isA(MessageContext.class), (Exception)isNull()); WebServiceMessageCallback requestCallback = createMock(WebServiceMessageCallback.class); requestCallback.doWithMessage(messageContext.getRequest()); @@ -441,6 +444,7 @@ public class WebServiceTemplateTest { template.setInterceptors(new ClientInterceptor[]{interceptorMock1, interceptorMock2}); expect(interceptorMock1.handleRequest(isA(MessageContext.class))).andReturn(false); expect(interceptorMock1.handleResponse(isA(MessageContext.class))).andReturn(true); + interceptorMock1.afterCompletion(isA(MessageContext.class), (Exception)isNull()); WebServiceMessageCallback requestCallback = createMock(WebServiceMessageCallback.class); requestCallback.doWithMessage(messageContext.getRequest()); diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java index a5a00ab8..8a72d078 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java @@ -175,6 +175,7 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter return true; } + public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) { cleanUp(); } @@ -252,7 +253,13 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter return true; } - /** + @Override + public void afterCompletion(MessageContext messageContext, Exception ex) + throws WebServiceClientException { + cleanUp(); + } + + /** * Handles an securement exception. Default implementation logs the given exception, and returns * false. *