You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by Thomas Nichols <nx...@yahoo.co.uk> on 2003/03/03 16:58:11 UTC

Re: [jelly] Using BeanTagLibrary for "action" tags

Hi James,

At 22:54 25/02/2003 +0000, James Strachan wrote:
>From: "Thomas Nichols" <nx...@yahoo.co.uk>
> > Hello,
> >
> > Is it possible to use BeanTagLibrary and have the top-level tags - i.e.
> > those registered with registerBean() - actually DO something? The plumbing
> > used in
> > jelly-tags/bean/src/test/org/apache/commons/jelly/tags/bean/
> > works a treat, and requires a minimal amount of glue (most of which can be
> > abstracted into super classes - great.)
>
>Agreed.
>
> > However, though this is useful for "data assembly" I want the top-level
>tag
> > to perform an action - which I'm currently doing using a standard
> > TagLibrary impl and TagSupport-derived tag classes. With the existing
> > ("imperative") code, doTag() is invoked for the top-level, registered,
>tag,
> > so I can take appropriate actions. How do I do this using the plumbing of
> > BeanTagLibrary?
> >
> > I'm trying to get the following -
> > <sync>
> >    <input1><file name="reggae.xml"/></input1>
> >    <input2><url value="http://www.pinkflag.com/wire/punk.xml"/></input2>
> > </sync>
> >
> > The inputX, url and file classes are just data wrappers, BeanTagLibrary
> > handles this very elegantly if I have
> >      registerBean (sync, Sync.class) in  MyTagLibrary ctor. I want to
> > invoke the "sync" processing on the collected data once the input1 and
> > input2 elements have been parsed. Is this possible?
> >
> > The refactoring has made for a cleaner architecture IMHO - worth the pain,
> > for me at least.
>
>Good idea Thomas.
>
>I've just patched the Bean tag library so that you can register a Method (or
>method name) which can be passed into the BeanTagLibrary.registerBean()
>method or used by the <beandef/> tag to specify a zero argument 'doit'
>method. So this method could be run() for Runnable objects or execute() for
>Ant like tasks etc.
>
>James

This is excellent - thanks very much, I can successfully trigger processing 
on a beantag with an "execute" method, the child beantags get processed 
first and addFoo methods ensure they get registered with their parent.

I'm not sure I yet understand fully how BeanTagLibrary works. Within the 
root (level0) "j:jelly" tag I want to have a sequence of level1 
"action"  tags (e.g. "blah:sync") and beneath each of those a 
"data-assembly" hierarchy of beans. Astonishingly, this actually works:

<j:jelly xmlns:j.... xmlns:bean... xmlns:blah... >
   <bean:sync>
     <bean:customer ...>
       <bean:order>
         <bean:product .../>
       </bean:order>
     ...
     </bean:customer>
     ...
   </bean:sync>
</j:jelly>

However ... :-)

The current BeanTag.java impl assumes that a bean either has a name 
("var"), or can be added to its parent (which needs an addFoo() method), or 
that its parent is a collection. This is not true for my Sync.java "bean" 
-- which isn't really a bean at all, I just need to register it in the 
MyOwnBeanTagLibrary ctor.

Now, if I register Sync with
registerBean ("sync", Sync.class, "execute");
all is hunky dory - but I get a warning from BeanTag.processBean(), lines 
174-176:

                 else if(var == null) { //warn if the bean gets lost in space
                     log.warn( "Could not add bean to parent for bean: " + 
bean );
                 }

If I register the sync tag (bean:sync) with registerTag() instead of 
registerBean(), and give it a doTag(), then the data-assembly logic does 
not get invoked. The doTag() gets invoked fine, but the beans aren't processed.

So...

1. Can I have the "sync" tag registered with a vanilla TagSupport-derived 
class, but have the beans still processed? I'd like to keep a single taglib 
if possible.

2. Is my use case general enough to warrant taking out that "Could not add 
bean to parent" warning, or at least making the trigger different?

3. If #2 == false, how can I programmatically assign a (meaningless) 'var' 
name to the sync tag, to suppress that message?

Not particularly keen on ice cream, but I do like jelly.
Onwards and upwards,
Thomas.



Re: [jelly] Using BeanTagLibrary for "action" tags

Posted by James Strachan <ja...@yahoo.co.uk>.
 From: "Thomas Nichols" <nx...@yahoo.co.uk>
> I'm not sure I yet understand fully how BeanTagLibrary works. Within the
> root (level0) "j:jelly" tag I want to have a sequence of level1
> "action"  tags (e.g. "blah:sync") and beneath each of those a
> "data-assembly" hierarchy of beans. Astonishingly, this actually works:
>
> <j:jelly xmlns:j.... xmlns:bean... xmlns:blah... >
>    <bean:sync>
>      <bean:customer ...>
>        <bean:order>
>          <bean:product .../>
>        </bean:order>
>      ...
>      </bean:customer>
>      ...
>    </bean:sync>
> </j:jelly>


BTW you can always use the default namespace to avoid typing too many
prefixes...

<j:jelly xmlns:j="jelly:core" xmlns="jelly:com.acme.MyTagLibrary">
    <sync>
        <customer>
            ...

If you ever want to process beans in a generic way via the BeanTagLibrary
you can write a Tag which implements the CollectionTag interface which is a
little like Ant's TaskContainer (indeed calling it ContainerTag would have
been a good idea).

e.g. if your <sync> tag wanted to process any old bean then (rather than
having specific adder or setter methods for each type of bean) then you
could do something like this...

    public class SyncTag extends TagSupport implements CollectionTag {
        private List list = new ArrayList();

        // Tag interface
        public void doTag() throws JellyTagException {
            for (Iterator iter = list.iterator(); iter.hasNext(); ) {
                Objec bean = iter.next();
                ...
                // process a bean
            }
            list.clear();
        }

        // CollectionTag interface
        public void addItem(Object bean) {
            list.add(bean);
        }
    }

I've just added a new JellyUnit test case,  testCollectionTag, to the bean
tag library that tests this behaviour and doubles up as a little demo of how
to do this.

James
-------
http://radio.weblogs.com/0112098/


__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com

Re: [jelly] Using BeanTagLibrary for "action" tags

Posted by James Strachan <ja...@yahoo.co.uk>.
 From: "Thomas Nichols" <nx...@yahoo.co.uk>
> Hi James,
> At 22:54 25/02/2003 +0000, James Strachan wrote:
> >I've just patched the Bean tag library so that you can register a Method
(or
> >method name) which can be passed into the BeanTagLibrary.registerBean()
> >method or used by the <beandef/> tag to specify a zero argument 'doit'
> >method. So this method could be run() for Runnable objects or execute()
for
> >Ant like tasks etc.
> >
> >James
>
> This is excellent - thanks very much, I can successfully trigger
processing
> on a beantag with an "execute" method, the child beantags get processed
> first and addFoo methods ensure they get registered with their parent.
>
> I'm not sure I yet understand fully how BeanTagLibrary works.

:-)


> Within the
> root (level0) "j:jelly" tag I want to have a sequence of level1
> "action"  tags (e.g. "blah:sync") and beneath each of those a
> "data-assembly" hierarchy of beans. Astonishingly, this actually works:
>
> <j:jelly xmlns:j.... xmlns:bean... xmlns:blah... >
>    <bean:sync>
>      <bean:customer ...>
>        <bean:order>
>          <bean:product .../>
>        </bean:order>
>      ...
>      </bean:customer>
>      ...
>    </bean:sync>
> </j:jelly>
>
> However ... :-)
>
> The current BeanTag.java impl assumes that a bean either has a name
> ("var"), or can be added to its parent (which needs an addFoo() method),
or
> that its parent is a collection. This is not true for my Sync.java "bean"
> -- which isn't really a bean at all, I just need to register it in the
> MyOwnBeanTagLibrary ctor.


I've just patched the code so that this warning will no longer appear if a
BeanTag has either an 'execute' method or a variable name.


> Now, if I register Sync with
> registerBean ("sync", Sync.class, "execute");
> all is hunky dory - but I get a warning from BeanTag.processBean(), lines
> 174-176:
>
>                  else if(var == null) { //warn if the bean gets lost in
space
>                      log.warn( "Could not add bean to parent for bean: " +
> bean );
>                  }
>
> If I register the sync tag (bean:sync) with registerTag() instead of
> registerBean(), and give it a doTag(), then the data-assembly logic does
> not get invoked. The doTag() gets invoked fine, but the beans aren't
processed.
>
> So...
>
> 1. Can I have the "sync" tag registered with a vanilla TagSupport-derived
> class, but have the beans still processed? I'd like to keep a single
taglib
> if possible.
>
> 2. Is my use case general enough to warrant taking out that "Could not add
> bean to parent" warning, or at least making the trigger different?
>
> 3. If #2 == false, how can I programmatically assign a (meaningless) 'var'
> name to the sync tag, to suppress that message?
>
> Not particularly keen on ice cream, but I do like jelly.
> Onwards and upwards,

:)

So #2 has been done. You can now create your own TagLibrary implementation
(derived from BeanTagLibrary) to register your tags or beans etc.

James
-------
http://radio.weblogs.com/0112098/

__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com