spring-ws icon indicating copy to clipboard operation
spring-ws copied to clipboard

ClientInterceptor's afterCompletion() is called twice. [SWS-983]

Open gregturn opened this issue 8 years ago • 4 comments

Sergey Trofimov opened SWS-983 and commented

Relevant code section in WebServiceTemplate.java

	protected Object handleError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
		if (logger.isDebugEnabled()) {
			logger.debug("Received error for request [" + request + "]");
		}
		throw new WebServiceTransportException(connection.getErrorMessage());
	}

	protected <T> T doSendAndReceive(/* ... */) throws IOException {
		try {
      // ...

			if (!messageContext.hasResponse() && !intercepted) {
				sendRequest(connection, messageContext.getRequest());
				if (hasError(connection, messageContext.getRequest())) {
					triggerAfterCompletion(interceptorIndex, messageContext, null);
					return (T) handleError(connection, messageContext.getRequest());
				}
				WebServiceMessage response = connection.receive(getMessageFactory());
				messageContext.setResponse(response);
			}

      // ...
		}
		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;
		}
	}

If after sendRequest(), hasError returns true then triggerAfterCompletion is fired and then handleError() is called which throws WebServiceTransportException. Latter exception is catched by catch (RuntimeException ex) block and then triggerAfterCompletion is called second time.

I got into this situation when target WebService was returning 404 error.

I have looked into the latest source code and seems that the bug remains.


Affects: 2.3.1

4 votes, 6 watchers

gregturn avatar Mar 23 '17 13:03 gregturn

Zbynek Vavros commented

Just found this myself so I just want to share my opinion.

This behavior still exists in 3.0.3.RELEASE but it's a question whether this is really a bug bacause handleError() is called when no FaultMessageResolver is registered. There is by default SoapFaultMessageResolver registered that throws SoapFaultClientException that is catched by the catch block you mention. If you register custom FaultMessageHandler that doesn't throw exception, then catch block doesn't get involved and interceptor is called only once. I solved this by doing check for SOAP fault in the interceptor's afterCompletion() method. In case there is fault method execution is stopped immediately as it will be invoked again (by the catch block) after FaultMessageResolver is run. This is the real completion for me as I consider the resolver as part of message processing cycle.

 

Therefore I suggest the javadoc of FaultMessageResolver is improved as this issue is closed.

gregturn avatar Nov 11 '18 16:11 gregturn

Maxim Butov commented

Same thing (ClientInterceptor.afterCompletion() called twice) when FaultMessageResolver.resolveFault(...) throws a RuntimeException.

gregturn avatar Sep 04 '19 10:09 gregturn

Dadaso Pawale commented

looks like issue because of below for loop in WebServiceTemplate.triggerAfterCompletion

 

if (interceptors != null) {if (interceptors != null) { for (int i = interceptorIndex; i >= 0; i--) { interceptors[i].afterCompletion(messageContext, ex); } }

 

i>=1 

gregturn avatar Oct 01 '19 13:10 gregturn

apechinsky commented

Everything becomes clear if we try to consider ClientInterceptor as some sort of try/catch/finally block. It seems that initial intent of afterCompletion() method was to play role of 'finally' block.

  • handleRequest - is called at the beginning of try block
  • handleResponse - at the en of try block
  • handleFault - catch block
  • afterCompletion - finally block

Javadoc says the same: ??...Will be called on any outcome, thus allows for proper resource cleanup.??

gregturn avatar Jan 03 '20 16:01 gregturn