commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rodney Waldhoff <rwaldh...@apache.org>
Subject Re: [jelly] do we need the InvokeTag?
Date Tue, 31 Dec 2002 17:53:19 GMT
Here's what InvokeTag does for me.  I don't think all of this is otherwise
available, but it wouldn't be the first time I missed something obvious.

* It provides a logical way to invoke methods that return void.

Before invoke, I found myself writing jexl expressions directly within my
scripts.  E.g.,:

<j:jelly>
 <j:new var="list" className="java.util.ArrayList"/>
 ${list.add(bar))}
</j:jelly>

The <invoke> tag provides the only XML way to do this that I can see,
though I might be missing something. More generally it provides an XML
syntax for invoking methods.

* It can nest in ways that would seen to otherwise require a lot of
temporary variables.  (This may simply be working around jexl issues.)

I.e.,

<j:set var="result" value="${myBean.foo(x, 123)}"/>

works if ${x} has been set, but does:

<j:set var="result" value="${myBean.foo(map.get(x), 123)}"/>

or

<j:set var="result" value="${myBean.foo(map.get(otherBean.bar(x)), 123)}"/>

etc.?

I'm sure I can't currently use "new" inside a jexl expression, so
something like

<j:set var="result" value="${myBean.foo(map.get(new OtherBean(123)), 123)}"/>

would have to be expressed with a temporary variable or with nested
new/invoke/arg calls.

* Between <invoke> and <new>, we have a xml syntax for arbitrary
reflection.  Significantly, the method to invoke can be determined by an
expression, and this would be otherwise unsupported.


But honestly I rarely find myself using <invoke> for very long, I
generally use it to feel my way around a new jelly taglib design.

For example (and hopefully an interesting little case study), I recently
jellified the configuration of a small library, first with new/invoke, and
later with custom tags.

I had a small interface like this:

 interface Factory {
   Element getElement(Identifier);
 }

with various implementations of Factory for generating Elements from disk,
from database calls, from transforms, from calls to web services etc. (It
doesn't really matter what Element and Identifier are here, but if you're
curious they are things like XML/HTML documents, images and multimedia
content).

I also had a "chain" that maintained a list of factories and would return
the Element returned by the first matching one:

 interface Filter {
   boolean accepts(Identifier);
 }

 class FactoryChain implements Factory {
   void addFactory(Filter,Factory);
   void addFactory(Factory); // in this case, the Factory instance also implements Filter
 }

So that the client code could just interact with a single Factory, no
matter what Identifier it encountered.

Different instances of my app had different Factories in the chain (and
sometimes which specific factories is determined at runtime) and I wanted
to externalize that configuration into a jelly script.  Specifically, I
wanted a jelly script that set the context variable "result" to some
Factory instance.

Creating a taglib that exposed all of the possible permutations here
seemed to be a daunting task, but using <invoke> and <new>, I could start
without any custom tags at all. My first pass (and I knew this wouldn't
last for long) looked something like this:

 <j:jelly>
  <j:new var="result" className="FactoryChain"/>
  <j:invoke method="addFactory" on="${result}">
    <j:new className="SomeFactory"/>
  </j:invoke>
  <j:invoke method="addFactory" on="${result}">
    <j:useBean class="SomeFactoryWithBeanishProperties" propertyName="value"/>
  </j:invoke>
  <j:invoke method="addFactory" on="${result}">
    <j:new class="SomeFactoryWithConstructorArgs">
      <j:arg><!-- ...etc... --></j:arg>
    </j:new>
  </j:invoke>
 </j:jelly>

After working with this for a while (i.e., converting some apps to this
configuration), I was able to figure out what methods and attributes I
really needed to expose and what a reasonable syntax for that might be. I
ended up with something like:

 <j:jelly>
  <my:chain var="result">
   <my:factory class="SomeFactory"/>
   <my:factory class="SomeFactoryWithBeanishProperties" propertyName="value"/>
   <my:factory class="SomeFactoryWithConstructorArgs" argName="value"/>
  </my:chain>
 </j:jelly>

I found that I didn't need to expose many of the methods via the taglib
(e.g., FactoryChain.addFactory(Filter,Factory)), and that with some simple
additions to the underlying library (like adding bean-ish setters for
constructor args) I could get a long way with a tag derived from useBean.

I haven't exposed all the methods of the underlying library yet in my
custom taglib, and probably I never will.  But having <invoke> available
gave me the confidence that there was at least some reasonable way to
access all that functionality, and it comforts me to know that I can
always fall back to <invoke> if there's some method I've omitted that I
suddenly need.

 - R.

On Tue, 31 Dec 2002, James Strachan wrote:

> I just spotted the invoke tag (I must have missed its arrival before). I
> might have misunderstood its intention but using it as follows
>
> <j:invoke var="result" on="${myBean}" method="foo">
>     <arg value="${x}"/>
>     <arg value="123"/>
> </j:invoke>
>
> Could just be replaced with
>
> <j:set var="result" value="${myBean.foo(x, 123)}"/>
>
> Do you think we still need the invoke tag? I can imagine the invoke tag
> having some benefits for argument type conversion, but am just wondering if
> that could be done via a seperate convert tag or helper bean..
>
> James
> -------
> http://radio.weblogs.com/0112098/
>


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


Mime
View raw message