From 6bd78f39f5aa9c7eed661772926d9ae307df7a47 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 2 May 2012 14:09:31 +0000 Subject: [PATCH] SWS-754 - EndpointInterceptor.afterCompletion is not always invoked --- .../ws/server/MessageDispatcher.java | 79 +++++++++++-------- .../ws/server/MessageDispatcherTest.java | 49 +++++++++++- 2 files changed, 93 insertions(+), 35 deletions(-) diff --git a/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java b/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java index e8966db2..222fe756 100644 --- a/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java +++ b/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2011 the original author or authors. + * Copyright 2005-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.OrderComparator; +import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.ws.FaultAwareWebServiceMessage; @@ -206,46 +207,54 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa EndpointInvocationChain mappedEndpoint = null; int interceptorIndex = -1; try { - // Determine endpoint for the current context - mappedEndpoint = getEndpoint(messageContext); - if (mappedEndpoint == null || mappedEndpoint.getEndpoint() == null) { - throw new NoEndpointFoundException(messageContext.getRequest()); - } - if (!handleRequest(mappedEndpoint, messageContext)) { - return; - } - // Apply handleRequest of registered interceptors - if (mappedEndpoint.getInterceptors() != null) { - for (int i = 0; i < mappedEndpoint.getInterceptors().length; i++) { - EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i]; - interceptorIndex = i; - if (!interceptor.handleRequest(messageContext, mappedEndpoint.getEndpoint())) { - triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext); - triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, null); - return; + try { + // Determine endpoint for the current context + mappedEndpoint = getEndpoint(messageContext); + if (mappedEndpoint == null || mappedEndpoint.getEndpoint() == null) { + throw new NoEndpointFoundException(messageContext.getRequest()); + } + if (!handleRequest(mappedEndpoint, messageContext)) { + return; + } + // Apply handleRequest of registered interceptors + if (mappedEndpoint.getInterceptors() != null) { + for (int i = 0; i < mappedEndpoint.getInterceptors().length; i++) { + EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i]; + interceptorIndex = i; + if (!interceptor.handleRequest(messageContext, mappedEndpoint.getEndpoint())) { + triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext); + triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, null); + return; + } } } - } - // Actually invoke the endpoint - EndpointAdapter endpointAdapter = getEndpointAdapter(mappedEndpoint.getEndpoint()); - endpointAdapter.invoke(messageContext, mappedEndpoint.getEndpoint()); + // Actually invoke the endpoint + EndpointAdapter endpointAdapter = getEndpointAdapter(mappedEndpoint.getEndpoint()); + endpointAdapter.invoke(messageContext, mappedEndpoint.getEndpoint()); + } + catch (NoEndpointFoundException ex) { + // No triggering of interceptors if no endpoint is found + if (endpointNotFoundLogger.isWarnEnabled()) { + endpointNotFoundLogger.warn("No endpoint mapping found for [" + messageContext.getRequest() + "]"); + } + throw ex; + } + catch (Exception ex) { + Object endpoint = mappedEndpoint != null ? mappedEndpoint.getEndpoint() : null; + processEndpointException(messageContext, endpoint, ex); + } // Apply handleResponse methods of registered interceptors triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext); triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, null); } catch (NoEndpointFoundException ex) { - // No triggering of interceptors if no endpoint is found - if (endpointNotFoundLogger.isWarnEnabled()) { - endpointNotFoundLogger.warn("No endpoint mapping found for [" + messageContext.getRequest() + "]"); - } throw ex; } catch (Exception ex) { - Object endpoint = mappedEndpoint != null ? mappedEndpoint.getEndpoint() : null; - processEndpointException(messageContext, endpoint, ex); - triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext); + // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, ex); + throw ex; } } @@ -316,12 +325,14 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa */ protected void processEndpointException(MessageContext messageContext, Object endpoint, Exception ex) throws Exception { - for (EndpointExceptionResolver resolver : getEndpointExceptionResolvers()) { - if (resolver.resolveException(messageContext, endpoint, ex)) { - if (logger.isDebugEnabled()) { - logger.debug("Endpoint invocation resulted in exception - responding with Fault", ex); + if (!CollectionUtils.isEmpty(getEndpointExceptionResolvers())) { + for (EndpointExceptionResolver resolver : getEndpointExceptionResolvers()) { + if (resolver.resolveException(messageContext, endpoint, ex)) { + if (logger.isDebugEnabled()) { + logger.debug("Endpoint invocation resulted in exception - responding with Fault", ex); + } + return; } - return; } } // exception not resolved diff --git a/core/src/test/java/org/springframework/ws/server/MessageDispatcherTest.java b/core/src/test/java/org/springframework/ws/server/MessageDispatcherTest.java index 087e3cef..27fe5642 100644 --- a/core/src/test/java/org/springframework/ws/server/MessageDispatcherTest.java +++ b/core/src/test/java/org/springframework/ws/server/MessageDispatcherTest.java @@ -298,7 +298,54 @@ public class MessageDispatcherTest { verify(mappingMock, interceptorMock1, interceptorMock2, adapterMock, factoryMock); } - + + @Test + public void testResolveExceptionsWithInterceptors() throws Exception { + EndpointAdapter adapterMock = createMock(EndpointAdapter.class); + dispatcher.setEndpointAdapters(Collections.singletonList(adapterMock)); + + Object endpoint = new Object(); + expect(adapterMock.supports(endpoint)).andReturn(true); + + EndpointMapping mappingMock = createMock(EndpointMapping.class); + dispatcher.setEndpointMappings(Collections.singletonList(mappingMock)); + + EndpointExceptionResolver resolverMock = createMock(EndpointExceptionResolver.class); + dispatcher.setEndpointExceptionResolvers(Collections.singletonList(resolverMock)); + + EndpointInterceptor interceptorMock = createStrictMock("interceptor1", EndpointInterceptor.class); + + expect(interceptorMock.handleRequest(messageContext, endpoint)).andReturn(true); + + adapterMock.invoke(messageContext, endpoint); + RuntimeException exception = new RuntimeException(); + expectLastCall().andThrow(exception); + + expect(resolverMock.resolveException(messageContext, endpoint, exception)).andReturn(true); + + expect(interceptorMock.handleResponse(messageContext, endpoint)).andReturn(true); + + interceptorMock.afterCompletion(messageContext, endpoint, null); + + EndpointInvocationChain chain = + new EndpointInvocationChain(endpoint, new EndpointInterceptor[]{interceptorMock}); + + expect(mappingMock.getEndpoint(messageContext)).andReturn(chain); + expect(factoryMock.createWebServiceMessage()).andReturn(new MockWebServiceMessage()); + + replay(mappingMock, interceptorMock, adapterMock, factoryMock, resolverMock); + + // response required for interceptor invocation + messageContext.getResponse(); + try { + dispatcher.dispatch(messageContext); + } catch (RuntimeException ex) { + + } + + verify(mappingMock, interceptorMock, adapterMock, factoryMock, resolverMock); + } + @Test public void testFaultFlow() throws Exception { EndpointAdapter adapterMock = createMock(EndpointAdapter.class);