We have developped a on our project a FaultEnhancerInterceptor that add the
following details when an exception occurs :
* Service : exchange.get(Message.WSDL_INTERFACE)
* Operation : exchange.get(OperationInfo.class).getName()
* Target URL : exchange.get(Message.ENDPOINT_ADDRESS)

If the exception is an unexpected exception (e.g. a SOAPFault), we wrap the
cause exception in a RuntimeException that holds all these details;
otherwise, we do not modify the exception.

Moreover, we log the exception : if debug level is enabled, we log the
stacktrace. Otherwise, we log the concatenation of the toString() of the
stack of exceptions.

Our interceptor is packaged as a CXF feature.

Code is available here : 
http://xebia-france.googlecode.com/svn/trunk/ws/cxf-demo/src/main/java/fr/xebia/cxf/feature/FaultEnhancerFeature.java
http://xebia-france.googlecode.com/svn/trunk/ws/cxf-demo/src/main/java/fr/xebia/cxf/interceptor/FaultEnhancerInterceptor.java

Hope this helps,

Cyrille
--
cyrille.lecl...@pobox.com


/**
 * We rely on {...@link Interceptor#handleFault(Message)} of a {...@link
Service#getOutInterceptors()} instead of
 * {...@link Interceptor#handleMessage(Message)} of {...@link
Service#getOutFaultInterceptors()} because {...@link ClientOutFaultObserver}
swallows
 * {...@link Interceptor#handleMessage(Message)} of the {...@link
Service#getOutFaultInterceptors()} for exceptions that occur on
 * {...@link Phase#SEND} ("do nothing for exception occurred during client
sending out request").
 * 
 * @author  mailto:cyrille.lecl...@pobox.com Cyrille Le Clerc 
 */
public class FaultEnhancerInterceptor extends
AbstractPhaseInterceptor<Message> {
    
    private final Logger logger =
Logger.getLogger(FaultEnhancerInterceptor.class);
    
    public FaultEnhancerInterceptor() {
        super(Phase.PRE_LOGICAL);
    }
    
    public void handleMessage(Message message) throws Fault {
        // do nothing. This class only handles Faults
    }
    
    @Override
    public void handleFault(Message message) {
        Exchange exchange = message.getExchange();
        if (exchange == null) {
            // do nothing
        } else {
            Fault fault = (Fault)message.getContent(Exception.class);
            FaultMode mode = message.get(FaultMode.class);
            
            String msg = "Exception invoking service " +
exchange.get(Message.WSDL_INTERFACE);
            if (exchange.get(OperationInfo.class) != null) {
                msg += ", operation=" +
exchange.get(OperationInfo.class).getName();
            }
            if (exchange.get(Message.ENDPOINT_ADDRESS) != null) {
                msg += ", url=" + exchange.get(Message.ENDPOINT_ADDRESS);
            }
            Throwable cause = fault.getCause() == null ? fault :
fault.getCause();
            
            Fault enhancedFault;
            Level level;
            if (FaultMode.UNCHECKED_APPLICATION_FAULT.equals(mode) ||
FaultMode.LOGICAL_RUNTIME_FAULT.equals(mode)
                || FaultMode.RUNTIME_FAULT.equals(mode)) {
                level = Level.ERROR;
                enhancedFault = new Fault(new RuntimeException(msg, cause));
            } else if (FaultMode.CHECKED_APPLICATION_FAULT.equals(mode)) {
                enhancedFault = fault;
                level = Level.INFO;
            } else /* mode == null */{
                enhancedFault = new Fault(new RuntimeException(msg, cause));
                level = Level.INFO;
            }
            if (logger.isDebugEnabled()) {
                logger.log(level, msg, cause);
            } else {
                List<Throwable> throwables =
ExceptionUtils.getThrowableList(cause);
                StringBuilder msgBuilder = new StringBuilder(msg);
                for (Throwable throwable : throwables) {
                    msgBuilder.append(" " + throwable);
                }
                logger.log(level,msgBuilder.toString());
            }
            
            message.setContent(Exception.class, enhancedFault);
            if (exchange.get(Exception.class) != null) {
                exchange.put(Exception.class, enhancedFault);
            }
        }
    }
}


dkulp wrote:
> 
> On Thursday 11 December 2008 3:57:24 am Kent Närling wrote:
>> We have several application that are configured to connect to a
>> webservice
>> interface for our server.
>> Naturally, it happens that this connection is sometimes configured
>> incorrectly or maybe the server is down etc
>> Unfortunately, this gives very bad and hard to read errors in the logs!
> .......
>> (furthermore this is logged inside the MessageSenderInterceptor, is there
>> any way to turn this off?)
> 
> Actually, it's not logged there.  There isn't any log statements in the 
> MessageSenderInterceptor.   It's PROBABLY logged in the 
> PhaseInterceptorChain.    In anycase, you can use the standard 
> java.util.logging configs to to reduce the logging level for the 
> PhaseInterceptorChain or similar which should solve that. 
> 
> 
>> How can we make this a bit more "user friendly"?
>>
>> I would like to catch at least the following situations and give an
>> application generated error message:
>> - Incorrect authorization
>> - Server unavailable/wrong address
>> etc
> 
> I THINK with CXF 2.0.9/2.1.3 (might be the latest SNAPSHOTS, don't
> remember 
> exactly when I fixed this), when you catch the WebServiceException from
> the 
> call, the "cause" will be the real cause (like the IOException) that could
> be 
> examined for more information.
> 
> 
> 
> -- 
> Daniel Kulp
> dk...@apache.org
> http://dankulp.com/blog
> 
> 

-- 
View this message in context: 
http://www.nabble.com/Improving-user-error-messages-for-failed-webservice-connection--tp20951772p21018900.html
Sent from the cxf-user mailing list archive at Nabble.com.

Reply via email to