dev@javaserverfaces.java.net

Re: JSF Component Question

From: Ken Paulsen <Ken.Paulsen_at_Sun.COM>
Date: Fri, 15 Dec 2006 18:00:15 -0800

Comments below.

Jason Lee wrote:
I'll lhave to look into facets
Not difficult to learn, but they can be very powerful for a component developer.
(I'll admit that I'm not too familiar with them), but, right now, I can't use them, which I'd like to change.  To get the basic tree working, the tag looks like this:
 
<risb:tree id="foo" model="#{testBean.tree}" />
 
With TestBean.getTree() looking like this:
 
    public TreeNode getTree() {
        TreeNode top = new TextNode ("Top Node!");
        TreeNode category = null;
        TreeNode book = null;
       
        category = new TextNode("Books for Java Programmers");
        top.add(category);
        category.add(new TextNode("The Java Tutorial: A Short Course on the Basics"));
        category.add(new TextNode("The Java Tutorial Continued: The Rest of the JDK"));
        category.add(new TextNode("The JFC Swing Tutorial: A Guide to Constructing GUIs"));
        category.add(new MenuNode("Menu Test", "http://blogs.steeplesoft.com"));
 
        category = new TextNode("Books for Java Implementers");
        top.add(category);
        category.add(new TextNode("The Java Virtual Machine Specification"));
        category.add(new HtmlNode("The Java Language Specification", "<b>Gilad Brach!</b>"));
       
        return top;
    }
That's an OK implementation, I guess, but not as useful as I'd like.  I thought about this some (and I'm not kidding:  every time I got up to change my new-born son's diapers this kept running through my head.  Sad. :), and I'd like to see a more flexible solution.  Maybe something like this:
 
<risb:tree id="testTree">
    <risb:treeNode>
        <h:outputText value="A giant table!"/>
        <risb:treeNode>
            <h:dataTable value="#{testBean.data}" var="data">
                <!-- snip! -->
            </h:dataTable>
        <risb:treeNode>
    </risb:treeNode>
    <risb:treeNode>
        <h:outputText value="Another node"/>
        <risb:treeNode>
            <h:outputText value="And another"/>
            <risb:treeNode>
                <h:outputText value="And yet another!"/>
            </risb:treeNode>
        </risb:treeNode>
    <risb:treeNode>
The difficulty here with allowing this particular markup is that it becomes a challenging to do the layout of the children when you mix the structure w/ the children themselves.  It may work out, but it's more challenging than using facets to define the areas.

Consider this instead:

<risb:tree id="testTree">
    <risb:treeNode>
          <f:facet name="content">
            <h:outputText value="A giant table!"/>
          </f:facet>
        <risb:treeNode>
             <f:facet name="content">
            <h:dataTable value="#{testBean.data}" var="data">
                <!-- snip! -->
            </h:dataTable>
             </f:facet>
        <risb:treeNode>
    </risb:treeNode>
    <risb:treeNode>
          <f:facet name="content">
            <h:outputText value="Another node"/>
          </f:facet>
        <risb:treeNode>
              <f:facet name="content">
            <h:outputText value="And another"/>
              </f:facet>
            <risb:treeNode>
                  <f:facet name="content">
                  <h:outputText value="And yet another!"/>
                  </f:facet>
            </risb:treeNode>
        </risb:treeNode>
    </risb:treeNode>
</risb:tree>

The difference is subtle, but significant and more noticeable when your tree component gets more complex.  If you consider *where* in the HTML the "content" vs. the children are rendered, you'll see the difference.  In most cases, the "content" of a TreeNode will be in the middle of the HTML for the TreeNode, whereas the "children" (child TreeNodes) will be at (or near) the end of the TreeNode.  You "might" be able to get them to render at the same place, but probably not.  And forcing yourself to do so may limit your design.  As your tree component gets more complex, you might provide facets for icons to appear next to your tree.  You can also provide properties which replace the need for facets when the tree nodes are text.  For example consider:

<risb:treeNode text="Text Node">
    <risb:treeNode>
       <f:facet name="content">
          <h:outputText value="Old of of doing a Text Node" />
       </f:facet>
    </risb:treeNode>
</risb:treeNode>


You may add "url", "imageURL" or other properties for common tree features.  This eliminates the need to subclass your TreeNodes for simple tree nodes, and eliminates the need to subclass whenever you can simply provide a UIComponent via a facet to be the "content".  You'll only need to subclass to change layout or behavior.

I hope this gives you some ideas to explore.

Good luck!

Ken Paulsen
ken.paulsen@sun.com
https://jsftemplating.dev.java.net
which would produce
 
- A giant table!
    (table data)
- Another node
    - And another
        And yet another!
 
I think that would be a more practical use, but I haven't had the time to think through it (clearly) yet, and, if I implement something like, how would that look from the user's perspective building the tree.  I don't know.  These are questions I hope to get hammered out in the sandbox. 
 
I think, though, that for all practical purpose, the different JS classes (TextNode, HTMLNode, and MenuNode) can all be rendered using only HTMLNode, as a TextNode's HTML content can simply be text (or a styled <span>, etc) and a MenuNode could have a <h:outputLink/> tag nested in the JSF markup.
 
All of that is something I'll be pondering today and over the Christmas break. 
 
Any input (ideas or code) will be greatly appreciated. :)
-----
Jason Lee, SCJP
Programmer/Analyst
http://www.iec-okc.com
 


From: Ken.Paulsen@Sun.COM [mailto:Ken.Paulsen@Sun.COM]
Sent: Thursday, December 14, 2006 6:59 PM
To: dev@javaserverfaces.dev.java.net
Subject: Re: JSF Component Question


Hi Jason,

Sounds reasonable.  You may also consider leveraging JSF's "facet" capability so that your tree renderer does not have to be so "smart" when displaying the contents.  In my case, I relied on this to define any TreeNode that was more complicated than plain text or an href.

Another piece of advice (which may be obvious and you may be doing already), when rendering the child tree nodes, don't cast or check for instanceof on any of the child UIComponents... just render all of them.  Some components I've seen written cast to an specific instance (i.e. TreeNode) and call their getters... this prevents things like Ed's AjaxZone from being inserted in the UIComponent tree to re-render portions of the tree dynamically.

Good luck!

Ken Paulsen
ken.paulsen@sun.com
https://jsftemplating.dev.java.net


Jason Lee wrote:
Hmm.  For now, it's using the Swing class, but I think I may create some Java classes that mimic, in terms of nomenclature, the classes supported by the JS component:
 
TreeNode
    TextNode
    HTMLNode
    MenuNode
 
A TreeNode would be able to hold 0 or more TreeNode elements for nested levels.  This hierarchy would help me identify at render time what type of node in the JS i need to create for the given TreeNode on the Java side.
 
Anyone see any problems with that?
 
-----
Jason Lee, SCJP
Programmer/Analyst
http://www.iec-okc.com
 


From: Ken.Paulsen@Sun.COM [mailto:Ken.Paulsen@Sun.COM]
Sent: Wednesday, December 13, 2006 6:03 PM
To: dev@javaserverfaces.dev.java.net
Subject: Re: JSF Component Question


Hi Jason,

I have had the privilege of writing a JSF tree component and faced the same issue.  There's more than one right approach (or is that more than one wrong approach?).  But I can share what I did.

On the component side, I composed the Tree of multiple UIComponents.  I defined 2 types of components:

    Tree
    TreeNode

From an implementation point-of-view, I ended up having Tree extend TreeNode b/c the root node (represented by Tree) was just a specialized TreeNode.  You could then easily build a tree staticly in a JSP, Facelets xhtml, or JSFTemplating .jsf file.  However, this doesn't (didn't) address the root of your question.

So... on the "data" side, here's what I did.  I defined a factory class for instantiating part of a Tree structure as described above (or the entire structure if you want).  The factory class required a "TreeAdaptor" implementation.  TreeAdaptor" was an interface that exposed methods for walking a tree structure that that factory would call.  The interface also exposed methods for getting meta data needed for the UIComponent (image urls, hyperlink, facets, etc.).  The TreeAdaptor implementations could be written to accept any type of data structure (i.e. swing TreeNode).  This allowed me to walk existing tree structures and "adapt" them to the UIComponent tree structure required to represent them in JSF.

You can see the code here:

https://jsftemplating.dev.java.net/source/browse/jsftemplating/src/java/com/sun/jsftemplating/component/factory/tree/

And for impl. of the TreeAdaptor inteface:

https://glassfish.dev.java.net/source/browse/glassfish/admin-gui/admin-jsf/src/java/com/sun/enterprise/tools/admingui/tree/

I don't know if this type of approach is what you're looking for or not... but I thought I'd share how I dealt with it.

Good luck!

Ken Paulsen
ken.paulsen@sun.com
https://jsftemplating.dev.java.net

Jason Lee wrote:
I'm trying to write a JSF component wrapper for the YUI tree component.  My first thought on how to represent the tree's data to the component, based on discussions I've overheard around the office is TreeNode, with which I have no experience.  I quickly discovered that that interface's package is javax.swing.tree.  My gut reaction is that it seems a little odd to have a JSF component using a Swing interface for its data model, but I see no better, existing interface/class with which to model my tree's data.  Another option is to design a custom class for just this purpose.  Anyone have any thoughts?  For now, I'll probably keep plodding along with TreeNode and see what happens in the interim. :)
 
Thanks!
 
-----
Jason Lee, SCJP
Programmer/Analyst
 
--------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@javaserverfaces.dev.java.net For additional commands, e-mail: dev-help@javaserverfaces.dev.java.net
--------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@javaserverfaces.dev.java.net For additional commands, e-mail: dev-help@javaserverfaces.dev.java.net