user2840283
user2840283

Reputation: 41

"stream is closed" error when enabling LoggingInInterceptor on JaxWSClient

I'm having a weird issue and cannot seem to get the bottom of it. Basically need to log the soap XML being sent to a webservice and received (consumer). I believe the correct approach to this is to use the out of the box interceptors provided by Apache. These work fine however we have a particular case where a method accepts a large amount of parameters/objects and returns a large amount of parameters/objects which would obviously create a large soap request/response xml. The soap request/response are always being printed correctly however the below error is being thrown:

Application configuration

Spring config:

<jaxws:client id="serviceClient"
              serviceClass="com.services.stubs.ServiceAPI"
              address="${service.url}">
    <jaxws:inInterceptors>
        <ref bean="incomingInterceptor"/>
    </jaxws:inInterceptors>
    <jaxws:outInterceptors>
        <ref bean="outgoingInterceptor"/>
    </jaxws:outInterceptors>
</jaxws:client>

My Interceptor classes:

public class OutLoggingInterceptor extends LoggingOutInterceptor
{
    public OutLoggingInterceptor()
    {
        super(Phase.PRE_STREAM);
    }
}


public class InLoggingInterceptor extends LoggingInInterceptor
{
    public InLoggingInterceptor()
    {
        super(Phase.RECEIVE);
    }
}

Error being thrown:

org.apache.cxf.interceptor.Fault: stream is closed
    at org.apache.cxf.interceptor.LoggingInInterceptor.logging(LoggingInInterceptor.java:167) ~[cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.interceptor.LoggingInInterceptor.handleMessage(LoggingInInterceptor.java:78) ~[cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:811) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1590) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1486) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1305) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:50) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:223) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:623) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:541) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96) [cxf-rt-frontend-simple-2.7.6.jar:2.7.6]
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134) [cxf-rt-frontend-jaxws-2.7.6.jar:2.7.6]

Upvotes: 4

Views: 3038

Answers (1)

yaromir
yaromir

Reputation: 385

I can propose several solutions. Please let know if any of them worked for you.

1) Why are you subclassing from LoggingOutInterceptor at all? If only thing that you need is to specify phase to which it is added, just use appropriate constructor in Spring context config.

2) I've encountered similar error when i was implementing SOAP service using Apache CXF. A had 2 custom interceptors in interceptor chain. One of them was reading message's input stream to parse it to perform some custom actions. The problem was that Xerces was closing input stream after parse so other interceptors were getting input stream that was already closed.

The only solution that worked for me was to duplicate input streams using this solution.

Something like:

// Exception handling ommitted

InputStream originalStream = soapMessage.getContent(InputStream.class);

// Reading contents of original stream into memory
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = originalStream.read(buffer)) > -1) {
    baos.write(buffer, 0, len);
}
baos.flush();
baos.close();

// Open new InputStreams using the recorded bytes
InputStream streamForThisInterceptor = new ByteArrayInputStream(baos.toByteArray());
InputStream streamForOtherInterceptors = new ByteArrayInputStream(baos.toByteArray());

// Replacing stream for other interceptors
soapMessage.setContent(InputStream.class, streamForOtherInterceptors);

Awful solution, but it's the only one that worked.

3) You can also try using CloseShieldInputStream from Apache commons-io, maybe you'll have better luck.

Upvotes: 1

Related Questions