Kirill Smirnov
Kirill Smirnov

Reputation: 1532

Saving outbound messages in CXF interceptor

I have an extremely hard problem for me with CXF, which I'm trying to solve (unsuccessfully) for more than a month. I'd read lots of similar questions, but nothing could help me.

First of all, let me introduce part of the code, which I use to save the outbound messages:

  public void handleMessage(SoapMessage message) throws Fault {
        OutputStream os = message.getContent(OutputStream.class);
        CacheAndWriteOutputStream cwos = new CacheAndWriteOutputStream(os);
        message.setContent(OutputStream.class, cwos);
        cwos.registerCallback(new LoggingOutCallBack());
    }

    class LoggingOutCallBack implements CachedOutputStreamCallback
    {
        public void onClose (CachedOutputStream cos)
        {
            try
            {
                String result = IOUtils.toString(cos.getInputStream());
            }
            catch (Exception e)
            {
                LogFactory.getLog(SwcFinalResponseInterceptor.class).error(ExceptionUtils.getStackTrace(e));
            }
        }

        public void onFlush (CachedOutputStream arg)
        {
        }
    }

I use the PRE_STREAM phase. This approach is mentioned in lots of places (for example, here), but it causes some rare errors. I have approximately 20000 requests a day, so, say, for 200 large requests this approach fails - for one of the further requests I get Stream closed error.

2013-12-19 15:37:47,902 [WARN ] org.apache.cxf.common.logging.LogUtils.doLog(LogUtils.java:400)
5880162-Interceptor for {http://service.ws.swc.comtech/}FrequentFlyerServiceWsService has thrown exception, unwinding now
5880163-org.apache.cxf.interceptor.Fault: Stream closed
5880164-        at org.apache.cxf.interceptor.LoggingInInterceptor.logging(LoggingInInterceptor.java:144)
5880165-        at org.apache.cxf.interceptor.LoggingInInterceptor.handleMessage(LoggingInInterceptor.java:73)

I'm absolutely sure that is because of this line in my code:

cos.getInputStream()

I've tested lots of times without this only line, and everything worked correct, but when I add this line, errors appear immediately. I suppose that's because CXF stores stream data for large streams not in memory but in some temporary file. It was described here.

An interesting point is that when I try to load the testing server by myself, sending thousands of heavy requests with curl, there are no errors, but when there are lots of clients, problems start to appear practically immediately.

I also found another solution and, at first glance, it seemed to work fine, I get no more
Stream closed errors, but server starts to skip some responses.

Please, help me, I really don't know what else can I read or do, I'm not good at streams and CXF, but I need a working solution and it would be great if you could explain what I'm doing wrong.

If you can't answer this question directly, please, at least, answer some of these questions:

  1. Why this line is required message.setContent(OutputStream.class, cwos);? I don't want to modify stream content, just get what's inside, so why should I read and then send contents again?

  2. May be there is more appropriate format (class to get) than this message.getContent(OutputStream.class);?

  3. May be I should use another interceptor phase?

  4. There is a method onClose, which is triggered BEFORE stream is closed or AFTER? And when does this happen? I don't want the strem to be closed before it's content is sent as a request to the client.

Thanks in advance!

Upvotes: 3

Views: 7477

Answers (1)

Ashish
Ashish

Reputation: 1121

The way I understand your question:

  1. If you just want to log SOAP request response envelops, you shouldnt even be using StreamInterceptor. its better to use LoggingInterceptor. To answer your first question message.setContent(OutputStream.class, cwos); intercepts the outgoing soap message and changes the content within it.

  2. If you want to continue with StreamInterceptor, you would end up using the same method to get the content of OutputStream. An alternative would be to use LoggingInterceptor. for more information on this How to log Apache CXF Soap Request and Soap Response using Log4j

  3. you can continue using pre-stream. but if the purpose is to just read the message content, you can go with pre_invoke. there is no advantage of using one over another. here is a link which will give you an idea about how could you extend a simple class to implement LoggingInterceptor. http://cxf.apache.org/docs/interceptors.html

    How to get incoming & outgoing soap xml in a simple way using Apache CXF?

Upvotes: 3

Related Questions