On Mon, 14 May 2001, James Strachan wrote:

> Agreed. How about we put the definitive 'tag lifecycle' guidelines in
> a document on the Jakarta Taglibs web site?

I'd be in favor of that.  It could also be incorporated into the general
tutorial on the site, but since the material is arguably more advanced,
maybe separating it out is useful.  I'm +1 for either.

I'm including below a revised version that takes people's comments into
account --

==============

Guidelines for tag lifecycle management:

1) Properties are expected to remain consistent.  This means that:

   - user code should avoid calling a a setter method of a tag handler
     for properties that correspond to tag attributes.  That is, if
     a tag has a "value" attribute, user code should avoid calling
     setValue() for that tag's handler.
   - the tag handler's code itself should not modify properties that are
     set by a setXXX() method
   - tag handlers should not perform invocation-specific logic in a
     setXXX() method.  That is, the setting of a property should
     have no side effects.

2) Private, invocation-specific state must be managed manually.  
   Implications include that:

   - release() is not necessarily called between invocations, which
     means that tag logic should not count on private invocation-
     specific state being reset by release()
   - doEndTag() is not necessarily called at the end of every invocation
     (in cases of abnormal termination -- e.g., an exception thrown inside
     a tag's body or by one of its methods)
   - private invocation-specific state is thus best initialized in
     doStartTag()

   - doFinally() *is* always called for tag handlers that implement
     TryCatchFinally, so this method should be used if any invocation-
     specific resources need to be released
   - release() *is* always called at least once for a tag handler before
     it is garbage-collected, so this method can and should be used to
     release any long-term resources

3) Since tags may be re-used, user code should not refer to a tag handler
   beyond its natural scope.  This implies:

   - a tag handler must not expose itself as a scripting variable if
     that variable has AT_BEGIN or AT_END scope (although NESTED scope
     would not be problematic in this case).
   - a tag handler should not set a reference to itself in the
     PageContext associated with the page for which it is invoked,
     unless expected use of such a reference would occur only during
     the invocation of the tag handler.


Examples:

a) Suppose you have a tag that accepts some sort of expression that you
   need to resolve, e.g.:

        <show value="$my-expression$"/>

   "$my-expression$" should be stored by setValue() and evaluated (i.e.,
   resolved) in doStartTag().  For the behavior that's almost always
   desired, it should NOT be evaluated in setValue().  (Validation, such
   as syntax checking, is acceptable in the setter method.)

   Similarly, Iterators and Enumerations should not be extracted in a
   setXXX() method.  setXXX() methods are meant to be "idempotent";
   write them so that they can be called multiple times with no
   side effects (and, conversely, only once instead of multiple times
   if the argument passed is the same).

b) Private state that's kept for each invocation should typically be
   reset in doStartTag(), not in release().  If you have an iteration
   index controlling the behavior of a loop, doStartTag() is the
   appropriate method from which to initialize it.

c) If a tag needs to open a new database connection (or file, or other
   external resource) for every invocation, the tag handler should
   implement TryCatchFinally and close the database connection (or
   other resource) in doFinally().  doEndTag() might not be called,
   and release() might not be called until long after you expect it to be.

Reply via email to