• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Fastest way to read inputstream and recreate it?

 
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've got a class that gets passed an InputStream which it needs to read from and then pass on to another class. The problem: once that stream's been read, the data's no longer in it (it's not a pushback or buffered).

What's the best way "recreate it" and pass it down the line?

My idea was to copy the data into a ByteArrayOutputStream at the same time that I'm reading the data, and then take that output and put it into a ByteArrayInputStream and pass that on. Is this the fastest, most efficient way to do this? Is there a better way? I'm looking for a solution that hopefully is:

1. Efficient, i.e. quick processing speed
2. Takes as little extra memory as possible (since I believe there's no way not to take approx. double the amount of memory, right? - i.e. there's no way to "leave" the data in the same memory space by reading it and "putting it back"?)
3. Looks the same to other classes reading the stream
 
Bartender
Posts: 6663
5
MyEclipse IDE Firefox Browser Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Since every class needs to read the same data using this input stream wouldnt it be better if you made a static reference to the byte [] data so that all classes can use it once it is read ?
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by John Meyers:
Since every class needs to read the same data using this input stream wouldnt it be better if you made a static reference to the byte [] data so that all classes can use it once it is read ?



I can't do that. My class is a Servlet Filter and the other classes are simply the filters (and servlets and JSPs) called by doFilter(..). So they expect an HttpServletRequest and that it have a ServletInputStream for POSTed data. So I HAVE to pass that (i.e. an InputStream) on down the line.
 
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If the implementation of InputStream that you are using supports mark and reset you could use those methods to relocate the pointer at the begining of the stream after you have read it.

Simply invoke mark() at the begining of the read method and reset at the end of the reading process and then pass the stream as parameter.

I have not tested this, but it should work.

Does this help?
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Edwin Dalorzo:
If the implementation of InputStream that you are using supports mark and reset you could use those methods to relocate the pointer at the begining of the stream after you have read it.

Simply invoke mark() at the begining of the read method and reset at the end of the reading process and then pass the stream as parameter.

I have not tested this, but it should work.

Does this help?



Hmmm, maybe. It would depend on if the implementation of ServletinputStream (for that particular java web server) supports mark. If it doesn't then I'm back to the original problem. So I'll check if it supports mark and if it does than I'll use that, otherwise use the ByteArrayIn/Out streams to copy it?
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yikes. I've looked online and asked here (and a few other boards) and there don't seem to be any good answers out there. I'm sure tons of people must have come across this issue, but there's almost no discussion about it online. Weird.
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In the context of a Filter, it seems that you should be able to create your own ServletInputStream implementation that simply wraps the original ServletInputStream in a BufferedInputStream, and reads from that BIS as necessary. That allows you to also use the mark() and reset() methods as suggested above, which will work for a BIS. To pass this new ServletInputStream on to the FilterChain you'll need to create a HttpRequestWrapper implementation which returns an instance of the ServletInputStream, and pass this HttpRequestWrapper to the FilterChain with doFilter(). Does that help?
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jim Yingst:
In the context of a Filter, it seems that you should be able to create your own ServletInputStream implementation that simply wraps the original ServletInputStream in a BufferedInputStream, and reads from that BIS as necessary. That allows you to also use the mark() and reset() methods as suggested above, which will work for a BIS. To pass this new ServletInputStream on to the FilterChain you'll need to create a HttpRequestWrapper implementation which returns an instance of the ServletInputStream, and pass this HttpRequestWrapper to the FilterChain with doFilter(). Does that help?



Yes, that definitely helps! That does seem to be a cleaner, more efficient solution than the one I was going to do (and the only one I've found online): use BAOS/BAIS.

Thanks!
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Would FilterInputStream do the job for you? I only used it once to make an input stream that wrote everything to the log as it read. It has a few overloaded read() methods like:
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Stan James:
Would FilterInputStream do the job for you



My main concern is not transforming the data but simply of allowing multiple reads of the stream (which is not allowed normally). So from that standpoint I think a BufferedInputStream wrapping it or a BAOS-BAOIS option might work better. Using FilterInputStream I'd just have to implement what BufferedInputStream would be doing for me anyways (right? or am i missing something?).
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It really depends what sort of processing you need to do on the stream. For many applications, the FilterInputStream could well be faster, and require less memory. BAIS/BAOS and BufferedInputStream are both storing the data in byte array somewhere so it can be replayed. With FilteredInputStream you don't need to save the data However you're more limited on what you can do, and when you can do it.

For example, let's say you want to use a FilteredInputStream to count the number of bytes that pass through the filter. That's easy to do. However, let's say that the reason you want that info is that you want to insert it into the request header, for any request that does not supply the content length. That's more of a problem, because the FilteredInputStream is not going to know the length of the content until after all the content has been read, either by another filter or by a servlet at the end of the filter chain. At that point, it may well be too late to populate the content length header, since subsequent filters or the servlet may have already tried to read that before reading the content. So in this case, you'd probably need your filter to read the entire content, and set up the new ServletInputStream with BAIS or BufferednputStream before calling doFilter(). FilterInputStream won't help here.

In general I would suggest that if the processing you require can be done with a FilterInputStream, and you're OK that it won't be completed until the other filters or servlet have started reading the content - then use FilteredInputStream, because it's probably faster and uses less memory. But if you can't, then use BufferedInputStream. Or BAOS/BAIS, but I think that may be a little slower as there's more need for recopying of data from one array to another.
 
Don't get me started about those stupid light bulbs.
reply
    Bookmark Topic Watch Topic
  • New Topic