You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Thomas Gschwind <TH...@zurich.ibm.com> on 2010/07/08 10:46:07 UTC

Log/Replace attachments within interceptor

Hi all!

I am trying to extract attachments passed to a RESTful service within a
subclass of AbstractPhaseInterceptor<Message>.  The questions I have is how
to do this properly and whether it is possible to replace/manipulate the
attachments.

What I have so far is the following:
class RequestLoggingInterceptor extends AbstractPhaseInterceptor<Message> {
      RequestLoggingInterceptor() {
            super(Phase.PRE_INVOKE);
      }

      public void handleMessage(Message message) throws Fault {
            List<?> contentList = message.getContent(List.class);
            MultipartBody body=(MultipartBody) contentList.get(0);
            List<Attachment> attachments = body.getAllAttachments();
            for (Attachment a : attachments) {
                  File file = new File(...);
                  ServicesUtils.writeToFile(a.getDataHandler
().getInputStream(), file);
                  ...

For retrieving the attachments I also tried to invoke getAttachments on the
message but this returns null.  I am wondering whether the above code
(getContent(List.class).get(0) is the proper way of doing this.  At least
this is the way the invoker eventually retrieves the body to pass to my
RESTful service.  The other thing I experience is when writing the file, I
have to invoke reset on the InputStream to reset the the file read position
back to the initial mark of 0.  Would this be the proper way to get hold of
the attachments?

And the final question I have, would it be possible to replace the
attachment with a different one after it has been extracted?  The
collection I get from body.getAllAttachments is unmodifiable, so
body.getAllAttachments().set(...) does not work.  When looking at the API
provided by Attachment, I don't see any method that would allow me to
replace the data handler.  On the data handler, I can only change the
DataContentHandlerFactory - could I do anything with that?  And the
getInputStream gives me back a DelegatingInputStream which has package
visibility, so cannot change the stream it is delegating to.

Does anybody have any other ideas of how to accomplish this?

Thanks in advance,
Thomas


Re: Log/Replace attachments within interceptor (solved)

Posted by Daniel Kulp <dk...@apache.org>.
On Wednesday 14 July 2010 5:11:10 am Thomas Gschwind wrote:
> 
> Only downside DelegatingInputStream has package visibility.  So, I
> currently have added a class to that package (yes, an ugly hack) that
> exposes the function to me.  That seems to work.  Does anybody know whether
> cxf could make the visibility of the DelegatingInputStream public?

Done on trunk.   Will merge to 2.2 shortly.  :-)

Thanks!
Dan



> 
> > At the moment you may want to replace the existing MultipartBody instance
> > with a new one by initializing it with a new collection of Attachments,
> > getting some from the immutable collection and adding some new
> 
> attachcment
> 
> > to the new collection
> 
> Replacing the entire MultipartBody is quite a bit of work.  Generating new
> attachments, copying all the other meta-data, etc.  In this case, I rather
> live with the above hack.
> 
> Thanks,
> Thomas

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

Re: Log/Replace attachments within interceptor (solved)

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Thomas

> > At the moment you may want to replace the existing MultipartBody instance
> > with a new one by initializing it with a new collection of Attachments,
> > getting some from the immutable collection and adding some new
> attachcment
> > to the new collection
>
> Replacing the entire MultipartBody is quite a bit of work.  Generating new
> attachments, copying all the other meta-data, etc.  In this case, I rather
> live with the above hack.
>
> I was thinking you could just do

List<Attachment> atts = body.getAllAttachments();
List<Attachment> newAtts = new ArrayList<Attachment>();
newAtts.add(atts.get(0));
// replace the 2nd one
newAtts.add(new Attachment(...));
newAtts.add(atts.get(2));
MultipartBody newBody = new MultipartBody(newAtts);
and then replace the original one with newBody on the message...

Not sure if it is what you're after, especially given the Dan's fix

cheers, Sergey


> Thanks,
> Thomas
>
>

Re: Log/Replace attachments within interceptor (solved)

Posted by Thomas Gschwind <TH...@zurich.ibm.com>.
Hi Sergey!

Sergey Beryozkin <sb...@gmail.com> wrote on 07/09/2010 10:18:43 PM:
> > [...]
> >            List<?> contentList = message.getContent(List.class);
> > [...]
> > For retrieving the attachments I also tried to invoke getAttachments on
the
> > message but this returns null.
>
> I think JAXRS MessageContextImpl is just not setting attachments on the
> message (as in message.setAttachments()), this is because Attachments
that
> MultipartBody deals with and those which are set in
message.setAttachments
> are of different types

I guess so too.  Did not have any troubles witjh that part so far.

> > The other thing I experience is when writing the file, I
> > have to invoke reset on the InputStream to reset the the file read
position
> > back to the initial mark of 0.  Would this be the proper way to get
hold of
> > the attachments?
>
> I'm presuming the CXF input stream representing an attachment is
supporting
> reset() - so yes, it's fine if it works :-)

I had some troubles with this solution.  It seems that some attachments use
a different type of InputStream that does not support reset().  Maybe this
is, if an attachment is over a certain size.  But I realized that the
InputStream returned is in fact of type DelegatingInputStream that passes
on all the operations to another InputStream.  This class provides a
setInputStream method where I can replace the InputStream. :)

Only downside DelegatingInputStream has package visibility.  So, I
currently have added a class to that package (yes, an ugly hack) that
exposes the function to me.  That seems to work.  Does anybody know whether
cxf could make the visibility of the DelegatingInputStream public?

> At the moment you may want to replace the existing MultipartBody instance
> with a new one by initializing it with a new collection of Attachments,
> getting some from the immutable collection and adding some new
attachcment
> to the new collection

Replacing the entire MultipartBody is quite a bit of work.  Generating new
attachments, copying all the other meta-data, etc.  In this case, I rather
live with the above hack.

Thanks,
Thomas


Re: Log/Replace attachments within interceptor

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Thomas

Hi all!
>
> I am trying to extract attachments passed to a RESTful service within a
> subclass of AbstractPhaseInterceptor<Message>.  The questions I have is how
> to do this properly and whether it is possible to replace/manipulate the
> attachments.
>
> What I have so far is the following:
> class RequestLoggingInterceptor extends AbstractPhaseInterceptor<Message> {
>      RequestLoggingInterceptor() {
>            super(Phase.PRE_INVOKE);
>      }
>
>      public void handleMessage(Message message) throws Fault {
>            List<?> contentList = message.getContent(List.class);
>            MultipartBody body=(MultipartBody) contentList.get(0);
>            List<Attachment> attachments = body.getAllAttachments();
>            for (Attachment a : attachments) {
>                  File file = new File(...);
>                  ServicesUtils.writeToFile(a.getDataHandler
> ().getInputStream(), file);
>                  ...
>
> For retrieving the attachments I also tried to invoke getAttachments on the
> message but this returns null.


I think JAXRS MessageContextImpl is just not setting attachments on the
message (as in message.setAttachments()), this is because Attachments that
MultipartBody deals with and those which are set in message.setAttachments
are of different types


>  I am wondering whether the above code
> (getContent(List.class).get(0) is the proper way of doing this.  At least
> this is the way the invoker eventually retrieves the body to pass to my
> RESTful service.


Yes, this is the way to get to the request/response object


> The other thing I experience is when writing the file, I
> have to invoke reset on the InputStream to reset the the file read position
> back to the initial mark of 0.  Would this be the proper way to get hold of
> the attachments?
>
>
I'm presuming the CXF input stream representing an attachment is supporting
reset() - so yes, it's fine if it works :-)


> And the final question I have, would it be possible to replace the
> attachment with a different one after it has been extracted?  The
> collection I get from body.getAllAttachments is unmodifiable, so
> body.getAllAttachments().set(...) does not work.  When looking at the API
> provided by Attachment, I don't see any method that would allow me to
> replace the data handler.  On the data handler, I can only change the
> DataContentHandlerFactory - could I do anything with that?  And the
> getInputStream gives me back a DelegatingInputStream which has package
> visibility, so cannot change the stream it is delegating to.
>
> Does anybody have any other ideas of how to accomplish this?
>
>
At the moment you may want to replace the existing MultipartBody instance
with a new one by initializing it with a new collection of Attachments,
getting some from the immutable collection and adding some new attachcment
to the new collection

cheers, Sergey


> Thanks in advance,
> Thomas
>
>