jakarta-taglibs-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Shawn Bayern <bay...@essentially.net>
Subject Re: XSL TagLib
Date Thu, 06 Dec 2001 18:47:37 GMT
On Wed, 5 Dec 2001, Bob Lee wrote:

 > IMHO, the JSPTL XSL library interface, albeit cool, leaves a lot to be
 > desired and does not really cater to developers' needs. I'm sure most
 > of you are familiar with it, so I'll skip the details.

Hi Bob -

Sorry I'm just joining this thread now; I was away at a conference for the 
last few days.

I looked over your messages and proposed syntax.  I'm curious if you could
highlight a particular use case where JSTL's tagset fails to cater to
developers' needs.  One difference is that the standard taglibs
XML-manipulation tags don't support retrieval directly from URLs, but this
is because URL-retrieval logic was abstracted to a core "import" action
instead of being replicated in numerous "process" tags.  (That is, XSL
"transform" tags aren't the only place where URL logic is useful.)  With
JSP 1.3's proposed support of tag creation via JSP fragment (instead of
Java logic), tightly focused tags become even more beneficial -- in
addition to current considerations about ease of documentation and
translation-time validation.

But if there are other areas where you feel the interface itself is 
lacking, I'm sure the EG would love to hear about it.  Thanks!

On to implementation notes:

 > Transformation performance.
 > 
 > My library literally performs hundreds of times faster than the JSPTL
 > implementation.

*Now* I'm paying attention... :-)

 > Unlike the JSPTL, my library hides the details of Transformer caching
 > and reuse. My XSLTransformerFactory maintains a global cache of
 > thread-safe Templates instances. Synchronized access to this cache has
 > been minimized as much as possible to prevent thread blocking. The
 > factory also maintains ThreadLocal Transformer caches. What this means
 > as that the number of Transformer caches is directly proportional to
 > the size of your request Thread pool.

Is such ThreadLocal caching ideal in a generalized JSP-container
environment?  There's no guarantee that JSP containers' threads will
persist.  James had the idea (I believe) initially for explicit
Transformer caching, and it made sense to me (at least) because it allows 
for proper, explicit scoping of the Transformer:  e.g., to a session, to 
the application, etc.

On the other hand, if there's a back-end implementation that's general
enough to let the page author avoid having to deal with this issue, that
would be ideal.  I'm not yet convinced that thread-based caching is it,
though.

 > The factory will automatically and correctly check the "lastModified" 
 > date on URL's and files.

This is a case where our implementation efficiency may be limited by our 
design requirements; since "URL retrieval" is considered, for JSTL's 
purposes, a separate function from "XML manipulation," we can't have the 
XML manipulation tags cache URL responses directly.

 > You can also set an environment variable to determine how often this
 > check is made (i.e. you can set it so that it looks for an updated
 > stylesheet once every ten minutes, every time a Transformer is
 > requested, or only when there isn't a cached version available). Set
 > it to 0 when developing so that XSLT changes are picked up right away
 > and the maximum in production so that they are permanently cached.

To adopt such a change, we'd need to bounce it up to the EG, since (I
believe that) an implementation-specific caching in this manner might
violate a spec that's not aware of it.  (E.g., the spec would have to
account for the possibility of XSLT changes not being picked up.)

An advantage of caching Transformers using a <transformer> tag instead of
using a back-end "environment variable" (or init param, attribute, etc.)  
is that it provides one less "timeout" for the user to worry about.  If
XSLT Transformer caching is indeed meant as an application-wide construct,
the page author can scope the Transformer to 'application'; otherwise, to
'session', and so on.  The Transformer would thus inherit the session
timeout, rather than requiring that the user create and understand a new
lifecycle.

 > Requesting a Transformer from the cache takes one third of the time
 > when you don't check the date on a local file. If the file is remote,
 > you'll will save a lot more time.
 > 
 > The fact is that the JSPTL implementation won't hold up in production
 > situations whereas mine will maintain consistent, predictable
 > performance, even under heavy concurrent loads. I'm not sure if this
 > was a goal, but hey, why not have it?

We'd certainly want to address the issue, if indeed the implementation 
won't hold up in production.  But do you really think that proper use of 
<transformer> will lead to inadequate performance?

 > Result caching.
 > 
 > I also implemented a result cache tag that works like this:
 > 
 >     <xsl:cache id="test" scope="application" duration="600"/>
 > 
 >         <xsl:transform xml="test.xml" xsl="test.xsl"/>
 > 
 >     </xsl:cache>
 > 
 > The results of this example transformation will be cache for the entire
 > application for 10 minutes. Other valid scopes are "session", 
 > "request", and "page".

Is this meaningfully different from simply saving the output of
<x:transform> into the session (where, as before, the page author gets to
rely on session lifecycle instead of managing a new concept)?

 > Buffer Flushing.
 > 
 > One of the problems is that when you use a StreamResult to output the
 > transform results to the JspWriter, it flushes the buffer, which is 
 > illegal inside of custom tags. Hence, you can't enclose transform tags 
 > inside other custom tags.
 > 
 > The JSPTL solves this by using a StringWriter and then outputting the 
 > result String to the JspWriter.
 > 
 > I solved this more directly by implementing what I call a
 > FlushIgnorantWriter. It is a Writer adapter that proxies all of the 
 > calls except for flush().
 > 
 > For example, instead of "new StreamResult(pageContext.getOut())", you 
 > just use "new StreamResult(new FlushIgnorantWriter(pageContext.getOut()))".
 > Problem solved, almost no performance hit.

Good thought.  The 'standard' RI currently does this:

    /*
     * We're going to output the text directly.  I'd love to
     * construct a StreamResult directly from pageContext.getOut(),
     * but I can't trust the transformer not to flush our writer.
     */
    StringWriter bufferedResult = new StringWriter();
    Result page = new StreamResult(bufferedResult);
    t.transform(xml, page);
    pageContext.getOut().print(bufferedResult);

I take it that you're suggesting, instead:

   Result page = new StreamResult(new FlushIgnored(pageContext.getOut()));
   t.transform(xml, page);

I'll make this change -- thanks!

 > Thank you, I hope this is enough to convince you,

Thank you, immensely, for such detailed comments.  This has a chance of 
meaningfully improving the implementation, and perhaps the spec too.  
Let's definitely keep up the discussion.

Shawn


--
To unsubscribe, e-mail:   <mailto:taglibs-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:taglibs-dev-help@jakarta.apache.org>


Mime
View raw message