Hi all,

> 
> An alternative that I could imagine, would be to create a class (that has
a
> boolean flag) which extends OutputStream, and decorates another
OutputStream
> that is given to the class in the constructor (that would be the
> OutputStream from the servlet's response). This class would pass all calls
> to it to the other OutputStream (as long as the flag is true), and as soon
> as close() or another special method is called, it sets the flag to false,
> which causes all other methods to do nothing (or throw an IOException).
That
> way, Tomcat's OutputStream would also be protected from future calls
> from the ImageIO.
> 

I now use a OutputStream decorator like this when calling ImageIO.write():

public class ImageIOBetterOutputStream extends OutputStream {
        private OutputStream out; // the actual stream
        private volatile boolean isActive = true;

        public ImageIOBetterOutputStream (OutputStream out) {
                this.out = out;
        }

        @Override
        public void close() throws IOException {
                if (isActive) {
                        isActive = false; // deactivate
                        try {
                                out.close();
                        } finally {
                                out = null;
                        }
                }
        }

        @Override
        public void flush() throws IOException {
                // do nothing
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
                if (isActive) {
                        out.write(b, off, len);
                }
        }

        [...] (overwrite the other methods the same way)
}

That way, I don't have to use a ByteArrayOutputStream to buffer the contents
in memory, and Tomcat's OutputStream is also protected from future calls to
flush() from the ImageIO (I just have to make sure that the call to close()
is inside a finally-block). (If flush() is the only method that the ImageIO
calls after an IOException, it probably would be enough to overwrite flush()
only). Since I'm using this class as OutputStream for the ImageIO, there
also haven't been any more errors.


> I agree that this behavior of the ImageIO is very strange (flushing the
> OutputStream when the ImageWriter gets garbage-collected, if an
IOException
> was thrown when the IIO previously tried to write to the stream).
> However, it seems also a bit strange to me that Tomcat is recycling
OutputStreams,
> because in my understanding, once an OutputStream is closed, it should
> be impossible to do any further write() calls to it.
> 
> May I ask, what is the particular reason for Tomcat to recycle
> OutputStreams?

Does anyone have a clue about this? I can understand recycling objects like
the Request/Response objects (e.g. if they contain lots of fields), but at
the moment I don't have an idea why it would be useful to recycle
OutputStream objects.


> Also, is there any hint to this on the Tomcat documentation/wiki? Because
I
> don't think it would be unusual to dynamically generate images and
> serve them to clients using the ImageIO, and I think it could be a bit
> frustrating to find the actual problem if one doesn't know this.

I couldn't find any hints about this in the Tomcat documentation/wiki, but I
think it should be mentioned somewhere. Of course, the behavior of the
ImageIO is strange, but Tomcat's recycling of OutputStreams enable the
errors when using the ImageIO.
If it is desired, maybe I could contribute something to this topic for
docs/wiki?


Regards,

Konstantin Preißer


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to