Yes, I agree with this approach. The most ideal thing is to always
write as directly to the writer as possible, and this even allows the
servlet container to progressively stream results to the client. Of
course, that means instead of using creating a StringWriter to use
temporarily the original writer from the response object (or wrapping
the stream from the response object) should just be passed down and
used.
What to do with error messages is a good question. In many cases an
exception will make continuing the rendering of the screen impossible
or lead to unpredictable results due to bad state. Whatever we do the
HTML produced is likely to be invalid, which is why we haven't tried
to eliminate exception and rendering error messages from the output,
either way the HTML is likely to be horked and you'll have to view
source to be sure to see the error message (stack trace, etc).
It might still be nice to separate this out and pass in an error
message list for everything to add errors to instead of going to the
writer, though that means the error messages while consolidated and
not interfering with the rest would be at the bottom of the page
instead of the top.
As for using a StringWriter instead of the HttpResponse Writer (or
output stream wrapped in a Writer), I'd vote strongly against that for
efficiency reasons. There are some memory usage issues with the
StringWriter in general, and of course performance and memory issues
in general when building the full string on the server before sending
it to the client. If we are going to build the full string before
sending anything to the client, we should at least use something more
efficient and performant like the the javolution.text.TextBuilder
object.
To do this more generically, and allow for easy changing between a
bunch of different things, we should change all Writer and
StringBuffer parameters to just use the java.lang.Appendable
interface, which both Writer and StringBuffer (and the javolution
TextBuilder) classes implement.
So, whatever we do in the ScreenWidgetViewHandler, in the screen
widget code itself the best flexibility will come from using the
Appendable interface for everything, plus adding an errorMessageList
parameter as a sister parameter to the appendable one so error
messages can be isolated and treated more independently.
-David
On May 30, 2008, at 9:27 AM, Adrian Crum wrote:
Jacopo,
Thank you very much for your comments!
I spent some time researching the StringBuffer versus StringBuilder
issue, and the general agreement in the Java community is that there
isn't a significant performance difference. So, I'll drop the idea
of using StringBuilder.
I would still like to have the screen widgets render to a string
before writing to the browser, so I'm considering using a
StringWriter for the initial rendering - which will be output to the
browser if there are no errors. This approach would have less of an
impact on the widget library API.
If rendering large XML files via the form widget is an issue, it
would have surfaced already - since the form widget currently uses a
StringBuffer for rendering. I'll perform some tests on large
datasets to check for out-of-memory errors.
To summarize: I'd like to make the screen widget library API more
consistent by converting StringBuffer arguments to Writer (which
would be a StringWriter). Plus, have the screens rendered to a
string before being output to the client - to facilitate better
error handling.
-Adrian
Jacopo Cappellato wrote:
Maybe there are some tools available in this area that could help.
For example, I remember that in the Apache Commons there is an API
to facilitate file uploads: the file is uploaded into memory but
if, during the upload, it exceeds a configurable size, it is
temporarly stored in the file system.
Maybe there are similar tools for what we need... maybe not.
Jacopo
On May 30, 2008, at 3:24 PM, Adrian Crum wrote:
That is a very good point. I will look into it.
-Adrian
Jacopo Cappellato <[EMAIL PROTECTED]> wrote: Adrian,
I think that we should also take into account the possibility to use
the form widget to render big lists (such as an xml export)... could
the StringBuilder approach cause OutOfMemory errors?
Jacopo
On May 30, 2008, at 1:21 AM, Adrian Crum wrote:
The current screen widget view handler creates a Writer instance
and
passes it to the screen renderer. That in turn passes the Writer
instance to the screen's sub-widgets.
Some of the sub-widgets render to a StringBuffer first, then output
the StringBuffer contents to the Writer instance. This has led to
an
inconsistent API in the screen widget library - some methods take a
Writer argument, others take a StringBuffer argument. (Take a look
at the HtmlWidgetRenderer class - two versions of each method are
needed.)
One of the problems with screen widget renderers outputting to a
Writer instance is when an error or exception occurs. The error
message is mangled or unreadable - depending upon where in the
Writer stream the error occurred. I'm sure most of the developers
have seen this - where an exception is rendered inside a table
element, or inside a drop-down list box, or inside a menu item,
etc.
Here's my idea: Have the screen widget view handler create a
StringBuilder instance and pass that to the screen renderer. All
screen sub-widgets render to the StringBuilder instance. If the
entire process completes without errors, then the view handler
outputs the StringBuilder contents to the Writer. If an error
occurs, the view handler discards the StringBuilder contents and
constructs a simple page to render the error message.
The StringBuilder class should provide faster rendering, because
it's not synchronized like the StringBuffer class. Synchronization
is not an issue in this case.
The screen widget library API would be simplified.
What do you think?
-Adrian