You are viewing a plain text version of this content. The canonical link for it is here.
Posted to taglibs-dev@jakarta.apache.org by James Strachan <ja...@metastuff.com> on 2001/02/12 11:04:16 UTC

Using JSP in functions or using RunnableTags?

<summary>

Re: Using JSP in functions or using RunnableTags?

Posted by Stephen Abramson <st...@atg.com>.
James,
I agree, it would be nice to define blocks of jsp code that could be
executed on demand. ATG's Dynamo page programming language has a
feature called "oparams" that allow one to do just that. 

And although it seems that one can't easily do this in jsp1.1, I think the
workaround isn't quite as bad as your example shows. ATG has already
submitted a proposal containing several tags to jsr052, some of which may
be used to accomplish the task shown in your example, with (a little
bit) less of a performance hit.

I'll give a quick overview of some of the tags submitted by ATG to jsr052:

<foo:Switch>, <foo:Case> and <foo:DefaultCase>

they work as follows:

The foo:Switch tag has a single attribute "value", foo:Case also has a
single attribute called "value" and foo:DefaultCase has no attributes. The
foo:Case and foo:DefaultCase tags may only reside within the body of a
foo:Switch tag. The foo:Switch tag always executes its body and has a
single member variable called "doneTesting." As the body of the foo:Switch
tag is rendered, it runs into various foo:Case and foo:DefaultCase tags,
similar to a switch statement in Java. 

The setParent method of the foo:Case and foo:DefaultCase tags first check
to see if the parent tag is of type foo:Switch. If so, then foo:Case and
foo:DefaultCase set their switchTag property to their parent tag, cast up
from a Tag to a SwitchTag. The setParent method in these tags then set a
boolean property childOfSwitchTag to true. Then, when the doStartTag of
the foo:Case tag executes, it first checks to see if childOfSwitchTag is
true. If it is, it then checks the to see if the value of its switchTag
property's doneTesting property is set to false. If it is false, then the
"value" attribute of the parent foo:Switch tag is compared with the
"value" attribute of the foo:Case tag. If they are equal, then the
doStartTag sets the doneTesting property of the parent foo:Switch tag to
true, returns EVAL_BODY_INCLUDE and renders the body of the foo:Case
tag. If the doneTesting property is true, or the foo:Case tag's "value"
property does not equal the "value" property of the parent foo:Switch,
then the doStartTag returns SKIP_BODY, and the doneTesting property of the 
parent foo:Switch tag is not modified.

The foo:DefaultCase tag works in the same way, but its doStartTag method
always returns EVAL_BODY_INCLUDE as long as the doneTesting property of
the parent foo:Switch tag is set to false.

Here is an example of these three tags in action:


<foo:Switch value="<%= customer.getSpenderType() %>">

  <foo:Case value="<%= Spender.BIG_SPENDER %>">
    Our business loves you! You spend lots of money!
  </foo:Case>

  <foo:Case value="<%= Spender.STINGY_SPENDER %>">
    Hmm, you need to spend more money. Here are some money saving offers
    that will motivate you to buy more of our stuff:
  </foo:Case>

  <foo:DefaultCase>
    Well, we're not sure if you're gonna spend a lot or a little, but
    either way, we're going to offer you a free widget with every purchase
    of a sprocket.
  </foo:DefaultCase>

</foo:Switch>


The proposal by ATG to jsr052 also contains variations on this tag set to
accommodate comparisons beyond simple equality tests. There is an
ExclusiveIf that that can have any combination of If, IfNot, IfEqual,
IfNotEqual, IfGreaterThan, IfGreaterThanOrEqual, IfLessThan,
IfLessThanOrEqual, IfContains or IfNotContains tags as child tags. The
ExclusiveIf tag behaves in a similar manner to the Switch tag.

I know this doesn't solve the problem of rendering jsp blocks on
demand, but it does try to minimize the performance loss of the
"conventional" approach.


Stephen Abramson
Art Technology Group


On Mon, 12 Feb 2001, James Strachan wrote:

> <summary>
> >From inside a JSP or inside a JSP custom tag  I'd like to be able to
> programmatcially call a 'block' of the JSP file using a standard Java
> function call for efficiency rather than using
> pageContext.include( "something.jsp" ), using BodyTags or hacking together
> an
> anonymous inner class. Does anyone have any ideas?
> </summary>
> 
> <background>
> You can mix and match scriptlets (<% ... %>) and JSP code but not functions
> which seems an unnecessary limitation.
> The only way of 'calling' a block of JSP code from within a JSP file (or JSP
> custom tag) appears to be via the pageContext include mechanism. e.g.
> 
>     // in a Tag...
>     // do something
>     if ( someValue.equals( "'foo" ) {
>         pageContext.include( "foo.jsp" );
>     }
>     else
> 
>         pageContext.include( "bar.jsp" );
>     }
> 
> This is a heavyweight mechanism and shouldn't be used inside large loops for
> efficiency reasons. Rather than just having a simple function in your
> servlet you need to move what would be in the function into a seperate JSP
> page and use a heavyweight way of calling the function
> (pageContext.include("uri")) which each time its called, must map the URI to
> some servlet class name using a name matching mechanism, then find an
> instance in the pool etc.
> 
> Is there any way of putting a piece of JSP inside a function in the *same*
> servlet object instance, that is callable from within a JSP tag or the same
> JSP file? I'm aware of the inner class hack though I'm concerned as to how
> portable that would be across containers - making all of the implicit
> variables available in the new inner class should be something the JSP
> compiler does for you rather than a JSP / Tag author as its fiddly and a JSP
> compiler may generate extra variables which it requires.
> 
> I'm aware of BodyTags and what they can do - a body tag is capable of
> repeatedly evaluating its body, though that can be much more inefficient
> than just calling the right bit of JSP directly. Being able to have JSP
> blocks as callable functions would be much nicer and much more efficent.
> </background>
> 
> <example>
> Lets assume that we've got a custom tag, <foo:loop> that is some kind of
> loop that navigates some data structure and we wish to do a kind of switch
> statement on each object it finds...
> 
> <foo:loop>
>     <foo:case value="1">
>         this is value 1
>     </foo:case>
>     <foo:case value="2">
>         this is value 2
>     </foo:case>
>     ...
>     <foo:case value="N">
>         this is value N
>     </foo:case>
> </foo:loop>
> 
> You could say why not just do this in Java code? Well it would be nice to do
> it in JSP as the body of the case tags can then be JSP code and get to
> resuse the whole of JSP,  using JSP custom tags etc.
> 
> Now the <foo:loop> body tag could keep looping its body executing all of the
> <foo:case> tags until one of them evaluates the right body. However this
> seems an inefficient way of doing things. For example, each iteration
> through the loop we get the following happening:-
> 
> * <foo:loop> creates a new BodyContext object (ok the new IterationTag can
> avoid this)
> * all the whitespace inside the <foo:loop> gets written to the output
> (doesn't it?)
> * creates a new Java object for *each* case tag in *each* loop iteration
> * initialise each case tag object, calling setParent, setPageContext and
> other properties etc.
> * call the necessary doStartTag() / doEndTag() methods of each tag
> 
> Thats a lot of work. For 1000 iterations with 10 cases in the switch
> statement, the small simple loop would construct 10,000 case tag objects -
> each of which is initalised 1000 times - per request!.
> 
> It would be nice if the <foo:loop> tag could evaluate its body once putting
> the values to compare against and the case tags into some data structure and
> then just call the correct case tag whenever the loop tag wishes.
> 
> Then each case tag just gets created and initialised once and the loop can
> iterate to its hearts content, calling case tags whenever it wishes using a
> nice, simple, efficient Java funciton call. No multiple JSP files, multiple
> servlets or unnecessary tag object constructions.
> </example>
> 
> 
> Before I go into any more detail (sorry, this is already quite a long email)
> has anyone else come across this limitation and figured out a nice way
> around it?
> 
> I guess what I'm getting around to is proposing a new kind of JSP tag, a
> RunnableTag whose body not executed by default but is runnable on demand by
> other tags as many times as they wish (via a regular Java function call)
> and the JSP compiler generates all the magic Java glue to make it happen for
> us.
> 
> Any comments?
> 
> <James/>
> 
> 
> 
> James Strachan
> =============
> email: james@metastuff.com
> web: http://www.metastuff.com
> __________________________________________________________________
> 
> If you are not the addressee of this confidential e-mail and any 
> attachments, please delete it and inform the sender; unauthorised 
> redistribution or publication is prohibited. 
> Views expressed are those of the author and do not necessarily 
> represent those of Citria Limited.
> __________________________________________________________________
>