closing ServletOutputStream

What is the best practice handling the ServletOutputStream after the response has been written and the stream is flushed with flush() and you are about to return from the doGet or service method of the Servlet?

Should we close the ServletOutputStream or not? Closing ought to assure that any future write to this stream will throw. But this does not imply that the container will close the HTTP connection to the browser or discard any other underlying IO streams. The behavior is container dependent but there should be some guidance.

In my view, after return from Servlet.doGet or equivalent the ServletOutputStream instance should be guaranteed not to be used again. Calling close() should have no effect. How is it in practice?

-Thomas

[764 byte] By [tgila] at [2007-10-3 0:07:25]
# 1

> In my view, after return from Servlet.doGet or

> equivalent the ServletOutputStream instance should be

> guaranteed not to be used again. Calling close()

> should have no effect. How is it in practice?

>

> -Thomas

Do you mean that you think the servlet engine should close the ServletOutputStream at the end of the service() method call?

I would disagree. What to do if you need to include one Servlet into another (RequestDispatcher.include()). At the end of the included servlet's service method the output stream would be closed and the including servlet couldn't write to it. You would force the servlet specs to have special case servlets for includes.

Instead, close the output stream yourself when you are done with it. If you want one that automatically closes the stream for you, then you could extend the GenericServlet (or HTTPServlet) and close the output stream at the end of the service method. Then you would subclass this one for all your work.

stevejlukea at 2007-7-14 16:56:01 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2

I was really not thinking about the case of servlet includes but did not suggest that the engine should automatically call ServletOutputStream.close()

The ServletOutputStream is a facility provided by the engine to interface to the HTTP client. After return from the service() method the engine is back in control of the OutputStream. My question is: What is communicated to the engine by a call to close() that occurs in the servlet code? In my view nothing more than what is already communicated by a call to flush()

There is more guidance in this matter in JDBC where a call to close() on a database connection object will just tell the factory that I am returning the connection to the pool, but not close the actual connection. I hope the servlet container does not automatically close the HTTP connection on ServletOutputStream.close()

tgila at 2007-7-14 16:56:01 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3

> I was really not thinking about the case of servlet

> includes but did not suggest that the engine should

> automatically call ServletOutputStream.close()

>

> The ServletOutputStream is a facility provided by the

> engine to interface to the HTTP client. After return

> from the service() method the engine is back in

> control of the OutputStream. My question is: What is

> communicated to the engine by a call to close() that

> occurs in the servlet code? In my view nothing more

> than what is already communicated by a call to

> flush()

A lot of things are communicated in a close() that aren't in a flush():

According to contract, a flush() gauruntees the bytes in this stream are passed to the target of the stream. That is all. You can still write to a flush()ed stream, you just accumulate more bytes (which you flush later on...)

According to contract, a close() releases all system resources associated with the stream. A close()ed stream can't be written to anymore, and a close()ed stream can't be re-opened.

So a close() and a flush() mean entirely different things: a flush() simply says that 'I want the target to get these bytes now' and a close() says 'I am done with this stream, throw it away'.

>

> There is more guidance in this matter in JDBC where a

> call to close() on a database connection object will

> just tell the factory that I am returning the

> connection to the pool, but not close the actual

> connection. I hope the servlet container does not

> automatically close the HTTP connection on

> ServletOutputStream.close()

A Connection object to a DB is not the same thing as an OutputStream. The contract that close() holds in a Connection object is to 'release this object's and the JDBC's resources', not the system resources, so the contract does not hinder the close()ed connection from holding onto memory (as it does when in a pool).

I think the main reason for the difference is this: a JDBC Connection can be pooled because the destination of the data is know and will always be the same, no matter who grabs from the pool next. OutputStreams, and ServletOutputStreams in particular, have unknown destinations.

Each time one is created it is likely to be pointing to a different spot - for servlets, you would have to have a pool for every user to visit your site - and a different pool for each location you would be downloading content to. So one for every image, every temporary file the user's browser makes to hold onto cached results, every file that was downloaded... etc.. And that would be just one user. Each user would have to have their own sets of these pools.You would quickly run out of memory.

Since the target is always changing, you can't reliably maintain anything about it in memory anyway, so it is better to re-create than to hold onto old info that isn't going to be accurate.

> I hope the servlet container does not

> automatically close the HTTP connection on

> ServletOutputStream.close()

There are other objects I think that can benefit from pooling in servlets (mainly the threads used to process a request, maybe the request objects themselves), and I know that most servlet engines will pool certain things. I am would wage a hefty penny that a ServletOutputStream is not one of those things (because the contract of close() inherited from OutputStream pretty much forbids it).

On the other hand, I know that the close() method will not be automatically called 'at some point'. The stream won't get garbage collected until after the stream is closed (which it may be by the client, if the client decides it has been long enough), unlike the JDBC Connection object which can be garbage collected and have close() thusly called. One of the up-sides of this is the ability to constantly have comunication lines open to the client through which to 'Push' content to the browser (usually through javascript commands). See 'Pushlets' for more details.

stevejlukea at 2007-7-14 16:56:01 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4

Thanks for this excellent discussion.

However you seem to attribute more to the contract of close() than what there actually is. You write correctly

>

> According to contract, a close() releases all system

> resources associated with the stream. A close()ed

> stream can't be written to anymore, and a close()ed

> stream can't be re-opened.

>

"Releases all system resources" does not imply anything about changing the state of the underlying system resources. That is implementation dependent. The state of this stream should change and make exceptions being thrown on IO method invocations. The underlying resource of a ServletOutputStream is somewhere the HTTPConnection to the client and I dont expect it to be arbitrarily closed by the engine's implementation.

An obvious difference between servlets and JDBC is also that one is server-side and the other client-side technology - which affects the applicability of pooling.

tgila at 2007-7-14 16:56:01 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 5

> Thanks for this excellent discussion.

>

> However you seem to attribute more to the contract of

> close() than what there actually is. You write

> correctly

> >

> > According to contract, a close() releases all

> system

> > resources associated with the stream. A close()ed

> > stream can't be written to anymore, and a

> close()ed

> > stream can't be re-opened.

> >

>

> "Releases all system resources" does not imply

> anything about changing the state of the underlying

> system resources. That is implementation dependent.

> The state of this stream should change and

> make exceptions being thrown on IO method

> invocations. The underlying resource of a

> ServletOutputStream is somewhere the HTTPConnection

> to the client and I dont expect it to be arbitrarily

> closed by the engine's implementation.

No, your right, I was confused by which Stream you are talking about. The underlying java.io.OutputStream that the ServletOutputStream wraps around would have to be closed and released. The system resource does not need to be. Actually, it appears (from section 8 of the HTTP1.1 specs) that the underlying system stream suggests that the stream should be left open (unlike HTTP1.0 which required the stream to be closed for each request). It might be good to note that Tomcat 4.x introduced HTTP1.1 compatability, whereas version 3.x did not.

stevejlukea at 2007-7-14 16:56:01 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...