ClientInterceptor's afterCompletion() is called twice. [SWS-983]
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
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.
Maxim Butov commented
Same thing (ClientInterceptor.afterCompletion() called twice) when FaultMessageResolver.resolveFault(...) throws a RuntimeException.
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
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.??