Catching the SOAP Fault error in custom interceptor (Soap12FaultOutInterceptor)

前端 未结 3 1267
醉梦人生
醉梦人生 2021-02-10 09:52

I wrote a custom CXF interceptor to log all the SOAP request and responses into the database and it seems to be working fine with positive test cases and server errors.

相关标签:
3条回答
  • 2021-02-10 10:09

    The Best way is to implement the Fault listener and use org.slf4j.Logger to log the error message instead of using java logging.

    It would be wise to override the LoggingInInterceptor and write ur custome interceptor to get the request payload.

    public class CxfInputFaultInterceptor extends AbstractLoggingInterceptor {
    private static final Logger LOG = LogUtils.getLogger(CxfInputFaultInterceptor.class);
    
    public CxfInputFaultInterceptor() {
        super(Phase.RECEIVE);
    }
    

    Step 1: cxf-beans.xml

        <cxf:bus>
        <cxf:inInterceptors>
            <ref bean="cxfInputFaultInterceptor"/>
        </cxf:inInterceptors>
        <cxf:inFaultInterceptors>
            <ref bean="cxfInputFaultInterceptor"/>
        </cxf:inFaultInterceptors>
        <cxf:properties>
            <entry key="org.apache.cxf.logging.FaultListener">
                <bean id="cxfFaultListener" class="pkg.common.ws.interceptor.CxfFaultListenerImpl" >
                    <property name="loggedUser" ref="loggedUser"/>
                </bean> 
            </entry>
        </cxf:properties>
    </cxf:bus>
    

    Step 2 : your listener which should implements org.apache.cxf.logging.FaultListener

    import java.io.InputStream;
    
    import org.apache.cxf.interceptor.LoggingMessage;
    import org.apache.cxf.logging.FaultListener;
    import org.apache.cxf.message.Message;
    import org.apache.cxf.service.model.EndpointInfo;
    import org.apache.cxf.service.model.InterfaceInfo;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /*
     * Listener to faults on the processing of messages by CXF intercepter chain. Here we      override 
     * java.util.logging.Logger and use  org.slf4j.Logger to print error to console.
     */
    
    public class CxfFaultListenerImpl implements FaultListener{
    
    private static final Logger logger = LoggerFactory.getLogger(CxfFaultListenerImpl.class);
    private static final String NEWLINE="\n";
    
    public boolean faultOccurred(final Exception exception,final String description,final Message message) {
    
        createErrorLog(message);
        logger.error(" --------------------------------------------------------------------------------------------------");
        logger.error(" Stack Trace  :         ");
        logger.error(" --------------------------------------------------------------------------------------------------");
        logger.error(NEWLINE,exception);
        logger.error(" --------------------------------------------------------------------------------------------------");
    
        return true;
    }
    
    private void createErrorLog(final Message message){
    
         final Message inMessage = message.getExchange().getInMessage();
    
         final InputStream is = inMessage.getContent(InputStream.class);
    
         final EndpointInfo endpoint = message.getExchange().getEndpoint().getEndpointInfo();
         String logName=null;
    
         if(endpoint!=null && endpoint.getService()!=null){
             final String serviceName = endpoint.getService().getName().getLocalPart();
             final InterfaceInfo iface = endpoint.getService().getInterface();
             final String portName = endpoint.getName().getLocalPart();
             final String portTypeName = iface.getName().getLocalPart();
             logName =  serviceName + "."  + portName + "." + portTypeName;
         }
        final LoggingMessage buffer
        = new LoggingMessage("Error occured on Service Call  : "+NEWLINE +"----------------------------", logName);
    
        final Integer responseCode = (Integer)message.get(Message.RESPONSE_CODE);
        if (responseCode != null) {
            buffer.getResponseCode().append(responseCode);
        }
    
        final String encoding = (String)message.get(Message.ENCODING);
    
        if (encoding != null) {
            buffer.getEncoding().append(encoding);
        }
        final String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD);
        if (httpMethod != null) {
            buffer.getHttpMethod().append(httpMethod);
        }
        final String ct = (String)message.get(Message.CONTENT_TYPE);
        if (ct != null) {
            buffer.getContentType().append(ct);
        }
        final Object headers = message.get(Message.PROTOCOL_HEADERS);
    
        if (headers != null) {
            buffer.getHeader().append(headers);
        }
        final String uri = (String)message.get(Message.REQUEST_URL);
        if (uri != null) {
            buffer.getAddress().append(uri);
            final String query = (String)message.get(Message.QUERY_STRING);
            if (query != null) {
                buffer.getAddress().append("?").append(query);
            }
        }
    
        final String requestXml= is.toString();
        if(requestXml !=null){
            buffer.getMessage().append("LoggedIn User:  ");
            buffer.getMessage().append(getCurrentUsername()+NEWLINE);
            buffer.getMessage().append("Request payload  : "+NEWLINE);
            buffer.getMessage().append(requestXml);
        }else{
            buffer.getMessage().append("LoggedIn User:  ");
            buffer.getMessage().append(getCurrentUsername()+NEWLINE);
            buffer.getMessage().append("No inbound request message to append.");
        }
    
        logger.error(buffer.toString());
    }
    

    }

    Hope that helps someone who just wants the stack trace and payload only when an error occurs on the service call and thus avoid huge log files.

    0 讨论(0)
  • 2021-02-10 10:14

    To capture faults, you need to register the interceptor as a fault interceptor. For example

    <cxf:outFaultInterceptors>
       <bean class="DbLogOutInterceptor" />
    </cxf:outFaultInterceptors>
    

    See the CXF Configuration page under "Enabling message logging using custom CXF bean elements" for an example using the CXF logging interceptors to capture in/out messages and in/out faults.

    0 讨论(0)
  • 2021-02-10 10:25

    So in my custom interceptor I write the following code:

    Fault fault = new Fault(message.getContent(Exception.class));
    

    Now this is in some legacy code that was throwing exceptions from Java and letting the framework convert it to a fault. I won't get into my feelings on that, but this will get you the fault that is generated.

    Now if you are throwing a fault from your service method, do

    Fault fault = message.getContect(Fault.class);
    

    Hopefully this will help you get the answer to what you want. Make sure you register the interceptor like below

    <jaxws:endpoint
      id="fooService" implementor="com.bar.FooService" address="/FooServices">
      <jaxws:outFaultInterceptors>
            <ref class="com.bar.interceptor.DbLogOutInterceptor"/>
      </jaxws:outFaultInterceptors>
    </jaxws:endpoint>
    <jaxws:endpoint
    
    0 讨论(0)
提交回复
热议问题