You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by "Wulff, Oliver" <Ol...@iona.com> on 2008/09/26 15:02:32 UTC

StreamInterceptor in configuration_interceptor

Hi there

I've to develop an interceptor where I want to do some transformations on the stream before the soap message is sent and some transformations on the stream before the soap message is parsed on the server side.

I had a look to the sample StreamInterceptor.java in the demo configuration_interceptor. I don't understand the implemention. Could you give some background information for it?

- What is the value of the class CachedOutputStream?
- What is the need to implement the class CachedStream?
- What is the need to run "message.getInterceptorChain().doIntercept(message);"?


Thanks a lot for clarification
Oliver

Re: StreamInterceptor in configuration_interceptor

Posted by Ian Roberts <i....@dcs.shef.ac.uk>.
Wulff, Oliver wrote:
> I'm a little bit confused.
> 
> I had a look to the gzip interceptor in cxf 2.1.2. I noticed that you don't use an "ending" interceptor anymore for the GzipOutInterceptor but for the GzipInInterceptor. Why?
> Why do you have to use an "ending" interceptor for the InInterceptor?

Dan changed the architecture of the out interceptor when he implemented
it on the trunk to use a streaming approach where the main interceptor
replaces the output stream with one that just has a small buffer, and
when that buffer is full it automatically starts streaming the
compressed data.  This means it no longer requires an ending interceptor
as it does the compression as it goes along rather than waiting until
the end.

For the in direction, the only purpose of the ending interceptor is to
put the original (non-gzip) input stream back into the message after
we've read the compressed data.  When I first wrote the interceptor it
didn't do this but then I found that it broke HTTP pipelining, i.e. the
connection closed after reading the first compressed message, and the
client had to establish a new connection for future requests.  By
putting the original stream back at the end the connection could remain
open to be re-used by the client.

Ian

-- 
Ian Roberts               | Department of Computer Science
i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK

AW: StreamInterceptor in configuration_interceptor

Posted by "Wulff, Oliver" <Ol...@iona.com>.
I'm a little bit confused.

I had a look to the gzip interceptor in cxf 2.1.2. I noticed that you don't use an "ending" interceptor anymore for the GzipOutInterceptor but for the GzipInInterceptor. Why?
Why do you have to use an "ending" interceptor for the InInterceptor?

Thanks
Oliver


-----Ursprüngliche Nachricht-----
Von: Wulff, Oliver [mailto:Oliver.Wulff@iona.com]
Gesendet: Di 30.09.2008 16:29
An: users@cxf.apache.org; users@cxf.apache.org
Betreff: AW: StreamInterceptor in configuration_interceptor
 
When I compare your proposal and Dan's current implementation both use the cached stream approach, isn't it?
A difference is that Dan's implementation makes use of the reentrance feature of CXF.

But why do you use the CachedOutputStream at all and store the original in the message context?

Thanks for clarification
Oliver


-----Ursprüngliche Nachricht-----
Von: Ian Roberts [mailto:i.roberts@dcs.shef.ac.uk]
Gesendet: Di 30.09.2008 13:40
An: users@cxf.apache.org
Betreff: Re: StreamInterceptor in configuration_interceptor
 
Wulff, Oliver wrote:
> Hi Dan
> 
> I need full access to the message but I want to transform and update the message before it is parsed by the corresponding soap parser.
> 
> I've done the following in which case the client blocks. If I uncomment the line where I close the steam os, the client doesn't block but an empty message is sent to the server:

Take a look at the patch attached to
https://issues.apache.org/jira/browse/CXF-1387.  This is my original
version of a GZIP interceptor which uses cached streams to do its work
(the version Dan committed to the trunk used a streaming technique
instead).  You can ignore the gzip-specific stuff, but the principle is
that rather than doing everything in one interceptor I have a main
interceptor in the PREPARE_SEND phase that replaces the OutputStream on
the message with a CachedOutputStream, but remembers the original output
stream.

The main interceptor adds another interceptor to the chain in the
PREPARE_SEND_ENDING phase that retrieves the two streams (cached and
original), transforms and writes the cached stream to the original one
and finally puts the original output stream back on the message.


Main interceptor:

private EndingInterceptor ending = new EndingInterceptor();

handleMessage(message) {
  OutputStream os = message.getContent(OutputStream.class);
  message.put(ORIGINAL_OUTPUT_STREAM_KEY, os);

  CachedOutputStream cs = new CachedOutputStream();
  message.setContent(OutputStream.class, cs);
  message.getInterceptorChain().add(ending);
}

Ending interceptor:

handleMessage(message) {
  CachedOutputStream cs =
    (CachedOutputStream)message.getContent(OutputStream.class);
  cs.flush();
  OutputStream originalOutput =
    (OutputStream)message.get(ORIGINAL_OUTPUT_STREAM_KEY);

  // write transformed message to originalOutput

  cs.close();
  originalOutput.flush();
  message.setContent(OutputStream.class, originalOutput);
}

>                 String processingMsg = new String(csnew.getBytes());
>                 String processedMsg = transform(processingMsg);
>                 
>                 ByteArrayOutputStream encOutput = new ByteArrayOutputStream();
>                 byte[] date = encryptedMessage.getBytes();

Be very, very careful about character encodings if you're doing this
kind of thing...

Ian

-- 
Ian Roberts               | Department of Computer Science
i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK



AW: StreamInterceptor in configuration_interceptor

Posted by "Wulff, Oliver" <Ol...@iona.com>.
When I compare your proposal and Dan's current implementation both use the cached stream approach, isn't it?
A difference is that Dan's implementation makes use of the reentrance feature of CXF.

But why do you use the CachedOutputStream at all and store the original in the message context?

Thanks for clarification
Oliver


-----Ursprüngliche Nachricht-----
Von: Ian Roberts [mailto:i.roberts@dcs.shef.ac.uk]
Gesendet: Di 30.09.2008 13:40
An: users@cxf.apache.org
Betreff: Re: StreamInterceptor in configuration_interceptor
 
Wulff, Oliver wrote:
> Hi Dan
> 
> I need full access to the message but I want to transform and update the message before it is parsed by the corresponding soap parser.
> 
> I've done the following in which case the client blocks. If I uncomment the line where I close the steam os, the client doesn't block but an empty message is sent to the server:

Take a look at the patch attached to
https://issues.apache.org/jira/browse/CXF-1387.  This is my original
version of a GZIP interceptor which uses cached streams to do its work
(the version Dan committed to the trunk used a streaming technique
instead).  You can ignore the gzip-specific stuff, but the principle is
that rather than doing everything in one interceptor I have a main
interceptor in the PREPARE_SEND phase that replaces the OutputStream on
the message with a CachedOutputStream, but remembers the original output
stream.

The main interceptor adds another interceptor to the chain in the
PREPARE_SEND_ENDING phase that retrieves the two streams (cached and
original), transforms and writes the cached stream to the original one
and finally puts the original output stream back on the message.


Main interceptor:

private EndingInterceptor ending = new EndingInterceptor();

handleMessage(message) {
  OutputStream os = message.getContent(OutputStream.class);
  message.put(ORIGINAL_OUTPUT_STREAM_KEY, os);

  CachedOutputStream cs = new CachedOutputStream();
  message.setContent(OutputStream.class, cs);
  message.getInterceptorChain().add(ending);
}

Ending interceptor:

handleMessage(message) {
  CachedOutputStream cs =
    (CachedOutputStream)message.getContent(OutputStream.class);
  cs.flush();
  OutputStream originalOutput =
    (OutputStream)message.get(ORIGINAL_OUTPUT_STREAM_KEY);

  // write transformed message to originalOutput

  cs.close();
  originalOutput.flush();
  message.setContent(OutputStream.class, originalOutput);
}

>                 String processingMsg = new String(csnew.getBytes());
>                 String processedMsg = transform(processingMsg);
>                 
>                 ByteArrayOutputStream encOutput = new ByteArrayOutputStream();
>                 byte[] date = encryptedMessage.getBytes();

Be very, very careful about character encodings if you're doing this
kind of thing...

Ian

-- 
Ian Roberts               | Department of Computer Science
i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK


Re: StreamInterceptor in configuration_interceptor

Posted by Ian Roberts <i....@dcs.shef.ac.uk>.
Wulff, Oliver wrote:
> Hi Dan
> 
> I need full access to the message but I want to transform and update the message before it is parsed by the corresponding soap parser.
> 
> I've done the following in which case the client blocks. If I uncomment the line where I close the steam os, the client doesn't block but an empty message is sent to the server:

Take a look at the patch attached to
https://issues.apache.org/jira/browse/CXF-1387.  This is my original
version of a GZIP interceptor which uses cached streams to do its work
(the version Dan committed to the trunk used a streaming technique
instead).  You can ignore the gzip-specific stuff, but the principle is
that rather than doing everything in one interceptor I have a main
interceptor in the PREPARE_SEND phase that replaces the OutputStream on
the message with a CachedOutputStream, but remembers the original output
stream.

The main interceptor adds another interceptor to the chain in the
PREPARE_SEND_ENDING phase that retrieves the two streams (cached and
original), transforms and writes the cached stream to the original one
and finally puts the original output stream back on the message.


Main interceptor:

private EndingInterceptor ending = new EndingInterceptor();

handleMessage(message) {
  OutputStream os = message.getContent(OutputStream.class);
  message.put(ORIGINAL_OUTPUT_STREAM_KEY, os);

  CachedOutputStream cs = new CachedOutputStream();
  message.setContent(OutputStream.class, cs);
  message.getInterceptorChain().add(ending);
}

Ending interceptor:

handleMessage(message) {
  CachedOutputStream cs =
    (CachedOutputStream)message.getContent(OutputStream.class);
  cs.flush();
  OutputStream originalOutput =
    (OutputStream)message.get(ORIGINAL_OUTPUT_STREAM_KEY);

  // write transformed message to originalOutput

  cs.close();
  originalOutput.flush();
  message.setContent(OutputStream.class, originalOutput);
}

>                 String processingMsg = new String(csnew.getBytes());
>                 String processedMsg = transform(processingMsg);
>                 
>                 ByteArrayOutputStream encOutput = new ByteArrayOutputStream();
>                 byte[] date = encryptedMessage.getBytes();

Be very, very careful about character encodings if you're doing this
kind of thing...

Ian

-- 
Ian Roberts               | Department of Computer Science
i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK

AW: StreamInterceptor in configuration_interceptor

Posted by "Wulff, Oliver" <Ol...@iona.com>.
Hi Dan

I need full access to the message but I want to transform and update the message before it is parsed by the corresponding soap parser.

I've done the following in which case the client blocks. If I uncomment the line where I close the steam os, the client doesn't block but an empty message is sent to the server:

    public PMPOutInterceptor() {
        super(Phase.PRE_STREAM);

...

        	  OutputStream os = message.getContent(OutputStream.class);        	
        	  CachedStream cs = new CachedStream();
            message.setContent(OutputStream.class, cs);
            
            message.getInterceptorChain().doIntercept(message);

            try {
                cs.flush();
                CachedOutputStream csnew = (CachedOutputStream) message
                    .getContent(OutputStream.class);
                
                String processingMsg = new String(csnew.getBytes());
                String processedMsg = transform(processingMsg);
                
                ByteArrayOutputStream encOutput = new ByteArrayOutputStream();
                byte[] date = encryptedMessage.getBytes();
                for (int i = 0; i < date.length; i++) {
                    encOutput.write(date[i]);
                }
                encOutput.flush();
                
                cs.close();
                message.setContent(OutputStream.class, encOutput);
                //os.close();  //If I close this stream an empty message is sent otherwise, the client blocks

...
    
    private class CachedStream extends CachedOutputStream {
        public CachedStream() {
            super();
        }
        
        protected void doFlush() throws IOException {
            currentStream.flush();
        }

        protected void doClose() throws IOException {
        }
        
        protected void onWrite() throws IOException {
        }
    }           

What am I missing?

Thanks a lot
Oliver


-----Ursprüngliche Nachricht-----
Von: Daniel Kulp [mailto:dkulp@apache.org]
Gesendet: Mo 29.09.2008 18:07
An: users@cxf.apache.org
Cc: Wulff, Oliver
Betreff: Re: StreamInterceptor in configuration_interceptor
 

Oliver,

It kind of depends on what you are trying to do with the stream.

If you can do your transformation in a streaming fasion, that's the ideal 
scenario.   An example is gzipping the stream.  You can just wrapper the 
original stream with a gzip stream and the "write" methods on the new stream 
handle everything.

If you need access to the entire message (like as a byte[] or similar) for 
your transform, you need a way to obtain the whole message.   That's where 
the caching streams come in.    The caching streams cache everything that is 
written to them, first in a  byte[] and then into a temp file once a 
threshold is crossed.    They then let you manipulate the temp file/byte[] as 
need before you then write it into the original stream.   

It really depends on your needs and how your transformation works.   If it can 
be implemented in a streaming manner, the performance it much better and 
memory usage is lower and such, but a lot of things cannot be implemented 
that way.

Dan




On Friday 26 September 2008 9:02:32 am Wulff, Oliver wrote:
> Hi there
>
> I've to develop an interceptor where I want to do some transformations on
> the stream before the soap message is sent and some transformations on the
> stream before the soap message is parsed on the server side.
>
> I had a look to the sample StreamInterceptor.java in the demo
> configuration_interceptor. I don't understand the implemention. Could you
> give some background information for it?
>
> - What is the value of the class CachedOutputStream?
> - What is the need to implement the class CachedStream?
> - What is the need to run
> "message.getInterceptorChain().doIntercept(message);"?
>
>
> Thanks a lot for clarification
> Oliver



-- 
Daniel Kulp
dkulp@apache.org
http://www.dankulp.com/blog


Re: StreamInterceptor in configuration_interceptor

Posted by Daniel Kulp <dk...@apache.org>.
Oliver,

It kind of depends on what you are trying to do with the stream.

If you can do your transformation in a streaming fasion, that's the ideal 
scenario.   An example is gzipping the stream.  You can just wrapper the 
original stream with a gzip stream and the "write" methods on the new stream 
handle everything.

If you need access to the entire message (like as a byte[] or similar) for 
your transform, you need a way to obtain the whole message.   That's where 
the caching streams come in.    The caching streams cache everything that is 
written to them, first in a  byte[] and then into a temp file once a 
threshold is crossed.    They then let you manipulate the temp file/byte[] as 
need before you then write it into the original stream.   

It really depends on your needs and how your transformation works.   If it can 
be implemented in a streaming manner, the performance it much better and 
memory usage is lower and such, but a lot of things cannot be implemented 
that way.

Dan




On Friday 26 September 2008 9:02:32 am Wulff, Oliver wrote:
> Hi there
>
> I've to develop an interceptor where I want to do some transformations on
> the stream before the soap message is sent and some transformations on the
> stream before the soap message is parsed on the server side.
>
> I had a look to the sample StreamInterceptor.java in the demo
> configuration_interceptor. I don't understand the implemention. Could you
> give some background information for it?
>
> - What is the value of the class CachedOutputStream?
> - What is the need to implement the class CachedStream?
> - What is the need to run
> "message.getInterceptorChain().doIntercept(message);"?
>
>
> Thanks a lot for clarification
> Oliver



-- 
Daniel Kulp
dkulp@apache.org
http://www.dankulp.com/blog