Helma Logo
main list history

Enhancements for response buffer handling

What I propose here started out while thinking about ways to de-uglify res.debug(). My goals were:

After trying some superficial plastic surgery, it became clear to me that this is a model case for what Tobi proposed here and was implemented as res.pushBuffer() and res.popBuffer() in Helma 1.6. (This wasn't immediately obvious because I didn't think "skin rendering" when thinking about res.debug().)

res.pushBuffer() and res.popBuffer() in Helma 1.6

These new response methods allow to slip an existing java.lang.StringBuffer on top of the resoponse buffer stack (as opposed to res.push(), which always creates a new one), and get the StringBuffer out of the response buffer stack without converting it to a String (versus res.pop(), which does just that). In other words, the new methods allow you to get a StringBuffer in and out of the response object multiple times without the penalty of StringBuffer to String conversion.

Unfortunately, res.pushBuffer() and res.popBuffer() is not quite as powerful as it should be. The problem is that the managing of StringBuffers is left to the application, which makes it quite difficult to implement a generic res.debug().

Proposed enhancement: manage buffers in res.buffers

In my eyes, we should enhance res.pushBuffer() to allow putting response buffers in a well-known, accessible location, and/or get them from there. Let's assume this location is called res.buffers. res.pushBuffer() would then optionally take a String argument:

   * Use buffer as new response buffer,
   *  without registering it in res.buffers.
  res.pushBuffer(java.lang.StringBuffer buffer)
   * Use the StringBuffer in res.buffers[name] as new response buffer,
   * creating it if it doesn't exist.
  res.pushBuffer(java.lang.String, name)

A third variant may or may not make sense:

   * Use buffer as new response buffer and register 
   * it as res.buffers[name], overwriting any previous buffer 
   * with that name.
  res.pushBuffer(java.lang.StringBuffer buffer, java.lang.String name)

Auto-Expanding res.buffers

For programmatic access to res.buffers, it might be useful to auto-expand by automatically creating buffers that do not yet exist:

  // res.buffers.debug is automatically created if it doesn't exist
  res.buffers.debug.append("Some debug output");

The nice thing here would be that for programmatic access we didn't even have to push/pop the buffer in question.

What it would mean for res.debug()

res.debug() could then be implemented as a method that writes to a buffer called "debug" (or "helma_debug"). Applications could simply provide their own version of res.debug(), and it would be easy to render skins to the response buffer, in addition to using res.write().

Other uses

Another area where this feature might prove useful is handling of javascript or style sheet resources included in a page. Sometimes individual modules of a web application need to add a script or style sheet to a page. Therefore, creating the <script> or <link> tags from a central function or macro may be inadequate. By rendering these tags to a separate buffer and including that buffer in the <head> element of the final page this problem could be solved in a simple and elegant way.

Links to this page: Core API Comments


#1 by midnightmonster at 2008/07/21 23:03
One of the benefits of using E4X for my "templating" is that I don't need any particular control over the buffers. Since my whole page lives as a tree in memory until I res.write it at the end of the request, I can modify any part at any time--e.g., add another script include to , add a message in
, or add a debug message to

(which it had never occurred to me to try since I always just debug to the console).

I know it's not usual to build the page as I do, but the only time I might use any more buffer power than exists would be if I were outputting to non-HTML.

The way the buffers currently are actually gives about the same functionality as PHP's output buffering--since I came from there, I'm pretty used to it.