Getting started with ADF Faces in JDeveloper 10.1.3 – Using the Tree Component, comparison with MyFaces Tomahawk Tree2

14

After having tried the tree2 component from the MyFaces Tomahawk library – see: Apache MyFaces (open source JSF implementation) – Using the Tree2 Component with JDeveloper 10.1.3
-, I wanted to do something similar with MyFaces Cherokee aka ADF
Faces. Unfortunately, the Apache MyFaces Cherokee project has not yet
been released, so I go for the ADF Faces set in JDeveloper 10.1.3 EA1.
Supposedly this is interchangeable with Cherokee once released.

The
af:tree element seems somewhat sober at first glance. It also seems
less smart than the tree2 component from the Tomahawk library that I
discussed in the previous post. Well, I am getting ahead of myself.
Let’s first get things going.....

Steps

The first steps are
more or less generic for anyone starting out with ADF Faces in
JDeveloper 10.1.3 EA. Oracle has many tutorials and howto’s on OTN that
describe these basic steps. 

  • Download JDeveloper 10.1.3 EA1 and install it.
  • Run JDeveloper 10.1.3
  • Create
    a new Application Workspace – I call it AdfFacesTrials – and a new
    project – I call it AdfFacesTreeTrials. I did not select any special
    Technology scope.
  • From the New Gallery, pick Web Tier, JSF and
    choose JSF JSP. The wizard for creating a JSF page – or rather a JSP
    that contains JSF components – starts. I call my new JSP
    MyFirstAdfFacesPage.jsp.  From a tutorial on OTN:Build a Master-Detail Web Page with JDeveloper and ADF Business Components I learned that I should include the following tag libraries on page 4 of the wizard (Tag Libraries):

JSF Core 1.0
JSF HTML 1.0

ADF Faces Components
ADF Faces HTML

  • I
    close the wizard and my new JSP page is created; it contains the proper
    Tag Library directives as well as the basic outline of the JSF
    structure: <f:view> and <h:form>.
  • Run the page to
    verify the set up is correct. The JSP should display in the browser,
    showing only its title – MyFirstAdfFacesPage.

Now it will get more interesting, as we are actually going to use the tree component from the ADF Faces Core Component Palette.

I
drag the Tree component to my JSP, positioning it right after the
<h:form> tag. From the documentation – see the resources below -
I have more or less gathered what the properties are that must be set.

&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;<br />&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br />&lt;%@ page contentType=&quot;text/html;charset=windows-1252&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://java.sun.com/jsf/html&quot; prefix=&quot;h&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://java.sun.com/jsf/core&quot; prefix=&quot;f&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://xmlns.oracle.com/adf/faces&quot; prefix=&quot;af&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://xmlns.oracle.com/adf/faces/html&quot; prefix=&quot;afh&quot;%&gt;<br />&lt;f:view&gt;<br />  &lt;html&gt;<br />    &lt;head&gt;<br />      &lt;meta http-equiv=&quot;Content-Type&quot;<br />            content=&quot;text/html; charset=windows-1252&quot;/&gt;<br />      &lt;title&gt;MyFirstAdfFacesPage&lt;/title&gt;<br />    &lt;/head&gt;<br />    &lt;body&gt;&lt;h:form&gt;<br />        &lt;af:tree var=&quot;node&quot; value=&quot;#{libaryTreeHandler.libraryTreeModel}&quot;&gt;<br />          &lt;f:facet name=&quot;nodeStamp&quot;&gt;<br />            &lt;h:panelGroup&gt;<br />              &lt;af:outputText value=&quot;#{node.description}&quot;/&gt;<br />              &lt;af:outputText value=&quot; (#{node.childCount})&quot;/&gt;<br />              &lt;af:outputText value=&quot; (#{node.nodeType})&quot; <br />                             rendered=&quot;#{node.nodeType == 'author'}&quot;<br />              /&gt;<br />            &lt;/h:panelGroup&gt;<br />          &lt;/f:facet&gt;<br />        &lt;/af:tree&gt;<br />      &lt;/h:form&gt;&lt;/body&gt;<br />  &lt;/html&gt;<br />&lt;/f:view&gt; <br />

The
<af:tree> element has a <f:facet> child element named
nodeStamp. This facet is rendered for each node in the tree. Unlike the
MyFaces tree2 component that had named facets for every nodeType -
where the name of the facet matches the nodeType – ADF Faces’ af:tree
has a single facet for every node. However, using multiple panelGroups
- one per nodeType – and tying the rendered property of these
panelGroups to the nodeType they represent, we can achieve that same
effect in ADF Faces.

In this case I have just a single
panelGroup with three elements: the description of the node, the number
of childnodes (between parentheses) and the node type – but the latter
only for nodes of type author.

Now I need to create the
backing bean to provide the TreeModel expected by the <af:tree>
component. I dug a little round the JavaDocs for TreeModel and came up
the class ChildPropertyTreeModel, that can be instantiated with a
Collection of node objects:

libraryTreeModel = new ChildPropertyTreeModel(library, &quot;children&quot;); 

where
library is a Collection (an ArrayList in this case) of objects. There
are two requirements: the objects in the Collection must all be of the
same type and there must be a property referring to the Collection of
child-nodes of each node object. We are free to design our own Node
object, as long as we adhere to these two requirements. So here is my
GenericTreeNode class:

package nl.amis.adffaces.library;<br /><br />import java.util.ArrayList;<br />import java.util.Collection;<br /><br />public class GenericTreeNode {<br /><br />    private String description ;<br />    private String longDescription ;<br />    private Collection children;<br />    private String nodeType;<br />    private boolean nodeSelected;<br />    <br />    public GenericTreeNode() {<br />    }<br /><br />    public GenericTreeNode(String description, String nodeType) {<br />      this.description = description;<br />      this.nodeType = nodeType;<br />      this.children = new ArrayList();<br />    }<br />    public GenericTreeNode(String description, String longDescription, Collection children) {<br />      this.description = description;<br />      this.longDescription = longDescription;<br />      this.children = children;<br />    }<br /><br />    public void setDescription(String description) {<br />        this.description = description;<br />    }<br /><br />    public String getDescription() {<br />        return description;<br />    }<br /><br />    public void setLongDescription(String longDescription) {<br />        this.longDescription = longDescription;<br />    }<br /><br />    public String getLongDescription() {<br />        return longDescription;<br />    }<br /><br />    public void setChildren(Collection children) {<br />        this.children = children;<br />    }<br /><br />    public Collection getChildren() {<br />        return children;<br />    }<br />    <br />    public int getChildCount() {<br />      if (children == null)<br />        return 0;<br />      else<br />        return children.size();<br />    }<br /><br />    public void setNodeType(String nodeType) {<br />        this.nodeType = nodeType;<br />    }<br /><br />    public String getNodeType() {<br />        return nodeType;<br />    }<br /><br />    public void setNodeSelected(boolean nodeSelected) {<br />        this.nodeSelected = nodeSelected;<br />    }<br /><br />    public boolean isNodeSelected() {<br />        return nodeSelected;<br />    }<br />}<br />&nbsp;

In the class LibraryTreeHandler – a class that I have instructed JSF to manage for me under the name libraryTreeHandler:

&lt;faces-config xmlns=&quot;http://java.sun.com/JSF/Configuration&quot;&gt;<br />  &lt;managed-bean&gt;<br />    &lt;managed-bean-name&gt;LibraryTreeHandler&lt;/managed-bean-name&gt;<br />    &lt;managed-bean-class&gt;nl.amis.myfaces.tree.LibraryHandler&lt;/managed-bean-class&gt;<br />    &lt;managed-bean-scope&gt;session&lt;/managed-bean-scope&gt;<br />  &lt;/managed-bean&gt;<br />&lt;/faces-config&gt; <br />

I
set up the nodes collection and tree model expected by <af:tree>
under the libraryTreeModel property of the libraryTreeHandler managed
bean.

package nl.amis.adffaces.library;<br /><br />import java.util.ArrayList;<br />import java.util.List;<br /><br />import oracle.adf.view.faces.model.ChildPropertyTreeModel;<br />import oracle.adf.view.faces.model.TreeModel;<br /><br />public class LibraryTreeHandler {<br /><br />    private TreeModel libraryTreeModel;<br /><br />    public LibraryTreeHandler() {<br /><br />        GenericTreeNode library = new GenericTreeNode(&quot;Library&quot;, &quot;folder&quot;);<br /><br />        GenericTreeNode ben = new GenericTreeNode(&quot;Ben Elton&quot;, &quot;author&quot;);<br />        GenericTreeNode book = new GenericTreeNode(&quot;Post Mortem&quot;, &quot;book&quot;);<br />        ben.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Blast from the Past&quot;, &quot;book&quot;);<br />        ben.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Stark&quot;, &quot;book&quot;);<br />        ben.getChildren().add(book);<br /><br />        GenericTreeNode rod = new GenericTreeNode(&quot;Rod Johnson&quot;, &quot;author&quot;);<br />        book = new GenericTreeNode(&quot;J2EE Design and Development&quot;, &quot;book&quot;);<br />        rod.getChildren().add(book);<br />        book =<br />            new GenericTreeNode(&quot;J2EE without Enterprise Java Bean&quot;, &quot;book&quot;);<br />        rod.getChildren().add(book);<br />        book =<br />            new GenericTreeNode(&quot;Professional Java Development With The Spring Framework&quot;,<br />                                   &quot;book&quot;);<br />        rod.getChildren().add(book);<br /><br />        GenericTreeNode orson =<br />            new GenericTreeNode(&quot;Orson Scott Card&quot;, &quot;author&quot;);<br />        book = new GenericTreeNode(&quot;Ender's Game&quot;, &quot;book&quot;);<br />        orson.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Xenocide&quot;, &quot;book&quot;);<br />        orson.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Shadow Puppets&quot;, &quot;book&quot;);<br />        orson.getChildren().add(book);<br /><br />        library.getChildren().add(ben);<br />        library.getChildren().add(rod);<br />        library.getChildren().add(orson);<br /><br />        // create the list of root nodes:<br />        List nodes = new ArrayList();<br />        nodes.add(library);<br /><br />        libraryTreeModel = new ChildPropertyTreeModel(library, &quot;children&quot;);<br />    }<br /><br />    public TreeModel getLibraryTreeModel() {<br />        return libraryTreeModel;<br />    }<br />}<br />&nbsp;

Now
I can run the JSP: JSF will instantiate the libraryTreeHandler that in
its constructor sets up the TreeModel and makes it available under its
the treeModel property where the <af:tree> element can get it. It
looks like this in the browser:

 

Of course it is similar to what I did with the MyFaces Tomahawk Tree2 component:

There
are some differences: the ADF Faces Tree does not let us specify the
icons for Node, Expanded and Collapsed like Tree2 does. Furthermore,
ADF Faces Tree does not look ahead to check whether a node has child
nodes: the Expand icon is always displayed, regardless of whether there
are in fact child nodes or not. I am not certain about the
configuration options for af:tree as the documentation is not
completely available and I have not been able to find any sample code
of the tree component. Perhaps it is much richer than I currently
suspect.

Make the tree application a little more interesting

Just like I did with MyFaces Tree2, I will bring a little more spark to the tree application. We
will allow Author nodes to be selected and we will display the
Biography of the currently selected author – marked in the tree with an
asterisk – next to the tree.

I
am sure that the ADF Faces Tree Component has its own events and built
in ways of handling those events. However, I have not been able to work
this out from the documentation, so I create my own CommandLink for the
nodes that can be selected. I also keep track of the currently selected
node myself – again, there very well be a mechanism in ADF Faces that
keeps track of the selected node, but it was not obvious to me. I make
small modifcations in the JSP to display an asterisk for the selected
node, as well as the biography for the currently selected node – if any.

&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;<br />&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br />&lt;%@ page contentType=&quot;text/html;charset=windows-1252&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://java.sun.com/jsf/html&quot; prefix=&quot;h&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://java.sun.com/jsf/core&quot; prefix=&quot;f&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://xmlns.oracle.com/adf/faces&quot; prefix=&quot;af&quot;%&gt;<br />&lt;%@ taglib uri=&quot;http://xmlns.oracle.com/adf/faces/html&quot; prefix=&quot;afh&quot;%&gt;<br />&lt;f:view&gt;<br />  &lt;html&gt;<br />    &lt;head&gt;<br />      &lt;meta http-equiv=&quot;Content-Type&quot;<br />            content=&quot;text/html; charset=windows-1252&quot;/&gt;<br />      &lt;title&gt;MyFirstAdfFacesPage&lt;/title&gt;<br />    &lt;/head&gt;<br />    &lt;body&gt;&lt;h:form&gt;<br />        &lt;h:panelGrid columns=&quot;2&quot; border=&quot;1&quot;&gt;<br />          &lt;af:tree var=&quot;node&quot; value=&quot;#{libaryTreeHandler.libraryTreeModel}&quot;<br />                   binding=&quot;#{libaryTreeHandler.tree}&quot; varStatus=&quot;status&quot;&gt;<br />            &lt;f:facet name=&quot;nodeStamp&quot;&gt;<br />              &lt;h:panelGroup&gt;<br />                &lt;h:outputText value=&quot;*&quot;<br />                              rendered=&quot;#{libaryTreeHandler.selectedNode == node}&quot;/&gt;<br />                &lt;h:commandLink id=&quot;my&quot; title=&quot;#{node.description}&quot;<br />                               actionListener=&quot;#{libaryTreeHandler.process}&quot;<br />                               rendered=&quot;#{node.nodeType == 'author'}&quot;&gt;<br />                  &lt;h:outputText value=&quot;#{node.description}&quot;/&gt;<br />                  &lt;f:param value=&quot;#{node.description}&quot; name=&quot;authorName&quot;/&gt;<br />                &lt;/h:commandLink&gt;<br />                &lt;af:outputText value=&quot;#{node.description}&quot;<br />                               rendered=&quot;#{node.nodeType != 'author'}&quot;/&gt;<br />                &lt;af:outputText value=&quot; (#{node.childCount})&quot;/&gt;<br />                &lt;af:outputText value=&quot; (#{node.nodeType})&quot;<br />                               rendered=&quot;#{node.nodeType == 'author'}&quot;/&gt;<br />              &lt;/h:panelGroup&gt;<br />            &lt;/f:facet&gt;<br />          &lt;/af:tree&gt;<br />          &lt;h:panelGroup rendered=&quot;#{libaryTreeHandler.selectedNode!= null }&quot;&gt;<br />            &lt;f:verbatim&gt;<br />              &lt;h3&gt;Results of the currently selected author&lt;/h3&gt;<br />            &lt;/f:verbatim&gt;<br />            &lt;h:outputText style=&quot;font-size:70%; font-family:arial&quot;<br />                          value=&quot;#{libaryTreeHandler.selectedNode.longDescription}&quot;/&gt;<br />          &lt;/h:panelGroup&gt;<br />        &lt;/h:panelGrid&gt;<br />      &lt;/h:form&gt;&lt;/body&gt;<br />  &lt;/html&gt;<br />&lt;/f:view&gt; <br />

For
some hugely annoying reason, when the command link is invoked, the
ActionEvent process in my bean is called three times, once for every
Author node that has such a CommandLink component. What’s worse, the
UIParam authorName has a different value for each of these three
invocations, namely the description of the Author node. So at this
point, I cannot make use of the normal UIParam processing. Instead, I
retrieve the value of the authorName Parameter from the
HttpServletRequest that I retrieve from ExternalContext that is
available on the current instance of the FacesContext. I cannot help
but feel that this is a bug in the tree component – but again, perhaps
I do not understand it all correctly. The code handling the ‘select
node’ event now becomes:

package nl.amis.adffaces.library;<br /><br />import java.util.ArrayList;<br />import java.util.Collection;<br />import java.util.List;<br /><br />import javax.faces.component.UIComponent;<br />import javax.faces.context.FacesContext;<br />import javax.faces.event.AbortProcessingException;<br />import javax.faces.event.ActionEvent;<br /><br />import oracle.adf.view.faces.component.core.data.CoreTree;<br />import oracle.adf.view.faces.model.ChildPropertyTreeModel;<br />import oracle.adf.view.faces.model.TreeModel;<br /><br /><br />public class LibraryTreeHandler {<br /><br />    private CoreTree tree;<br />    private TreeModel libraryTreeModel;<br />    private GenericTreeNode selectedNode = null;<br /><br />    public LibraryTreeHandler() {<br />        GenericTreeNode library = new GenericTreeNode(&quot;Library&quot;, &quot;folder&quot;);<br /><br />        GenericTreeNode ben = new GenericTreeNode(&quot;Ben Elton&quot;, &quot;author&quot;);<br />        String bio = &quot; Already a successful comedian, Ben Elton turned to writing situation comedies during the 1980s and penned BBC classics such as \&quot;The Young Ones\&quot;, \&quot;Blackadder\&quot;, and during the 1990s \&quot;The Thin Blue Line\&quot;.\n&quot; + <br />            &quot;    He provided lyrics for Andrew Lloyd Webber Musical, The Beautiful Game, which was nominated for Best Musical at the Laurence Olivier Theatre Awards in 2001 (2000 season).\n&quot; + <br />            &quot;    His comedy, Popcorn performed at the Apollo Theatre, was awarded the 1998 Laurence Olivier Theatre Award for Best New Comedy of the 1997 season.\n&quot; + <br />            &quot;    Has three children : Bert, Lottie and Fred. Is co-writer of the Queen Musical 'We Will Rock You' with the band itself.\n&quot; + <br />            &quot;Birth name: Benjamin Charles Elton. Height: 5' 8\&quot; (1.73 m) \n&quot;; <br />        ben.setLongDescription(bio);<br />        GenericTreeNode book = new GenericTreeNode(&quot;Post Mortem&quot;, &quot;book&quot;);<br />        ben.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Blast from the Past&quot;, &quot;book&quot;);<br />        ben.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Stark&quot;, &quot;book&quot;);<br />        ben.getChildren().add(book);<br /><br />        GenericTreeNode rod = new GenericTreeNode(&quot;Rod Johnson&quot;, &quot;author&quot;);<br />            bio = &quot;Rod Johnson is an enterprise Java architect with extensive experience in the insurance, dot-com, and financial industries. He was the J2EE architect of one of Europe's largest web portals, and he has worked as a consultant on\n&quot; + <br />            &quot;a wide range of projects.\n Rod has an arts degree majoring in music and computer science from the University of Sydney. He obtained a Ph.D. in musicology before returning to software development. He has been working with both Java and J2EE since\n&quot; + <br />            &quot;their release and is actively involved in the Java Community Process as a member of the JSR-154 (Servlet 2.4) and JDO 2.0 Expert Groups. He is the author of several best-selling books, like \&quot;Expert One-on-One J2EE Design and Development\&quot; (Wrox, 2002) and has contributed to several other books on J2EE since 2000. As founder of the Spring Framework (www.springframework.org), he speaks frequently at leading industry conferences.\n&quot;;<br />        rod.setLongDescription(bio);<br />        book = new GenericTreeNode(&quot;J2EE Design and Development&quot;, &quot;book&quot;);<br />        rod.getChildren().add(book);<br />        book =<br />            new GenericTreeNode(&quot;J2EE without Enterprise Java Bean&quot;, &quot;book&quot;);<br />        rod.getChildren().add(book);<br />        book =<br />            new GenericTreeNode(&quot;Professional Java Development With The Spring Framework&quot;,<br />                                   &quot;book&quot;);<br />        rod.getChildren().add(book);<br />        <br />        bio = &quot;Nobody had ever won the Hugo and Nebula awards for best novel two years in a row, until Orson Scott Card received them for Ender's Game and its sequel, Speaker for the Dead, in 1986 and 1987. The third novel in the series, Xenocide, was published in 1991, and the fourth and seemingly final volume, Children of the Mind, was published in August 1996. However, the Ender cycle now includes the new parallel series that began with Ender's Shadow in 1999, followed by Shadow of the Hegemon in 2001, and continued with Shadow Puppets in 2002. Warner Brothers also recently announced that it has made a deal for director Wolfgang Petersen to bring Ender's Game to the big screen. Born in Richland, Washington, Card grew up in California, Arizona, and Utah. He lived in Brazil for two years as an unpaid missionary for the Mormon Church. He received degrees from Brigham Young University (1975) and the University of Utah (1981). He currently lives in Greensboro, North Carolina. He and his wife, Kristine, are the parents of five children: Geoffrey, Emily, Charles, Zina Margaret, and Erin Louisa (named for Chaucer, Bronte and Dickinson, Dickens, Mitchell, and Alcott, respectively).&quot;;<br />        GenericTreeNode orson =<br />            new GenericTreeNode(&quot;Orson Scott Card&quot;, &quot;author&quot;);<br />        orson.setLongDescription(bio);<br />        book = new GenericTreeNode(&quot;Ender's Game&quot;, &quot;book&quot;);<br />        orson.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Xenocide&quot;, &quot;book&quot;);<br />        orson.getChildren().add(book);<br />        book = new GenericTreeNode(&quot;Shadow Puppets&quot;, &quot;book&quot;);<br />        orson.getChildren().add(book);<br /><br />        library.getChildren().add(ben);<br />        library.getChildren().add(rod);<br />        library.getChildren().add(orson);<br /><br />        // create the list of root nodes:<br />        List nodes = new ArrayList();<br />        nodes.add(library);<br /><br />        libraryTreeModel = new ChildPropertyTreeModel(nodes, &quot;children&quot;);<br />        }<br /><br />        public TreeModel getLibraryTreeModel() {<br />        return libraryTreeModel;<br />        }<br />    <br />    public void setTree(CoreTree tree) {<br />        this.tree=tree;<br />    }<br />    <br />    public CoreTree getTree() {<br />        return tree;<br />    }<br />    <br />    private GenericTreeNode findNode(String description, Collection&lt;GenericTreeNode&gt; nodes) {<br />        // iterate through the collection, verify each node and then - if it does not match - verify its child collection<br />        for (GenericTreeNode node: nodes) {<br />            if (node.getDescription().equalsIgnoreCase(description)) { return node;}<br />            GenericTreeNode childNode = findNode(description, node.getChildren());<br />            if (childNode != null) return childNode;            <br />        }<br />        return null;<br />    }<br />    <br />    public void process(ActionEvent event) throws AbortProcessingException {<br />    FacesContext context = FacesContext.getCurrentInstance();<br />    javax.servlet.http.HttpServletRequest req = (javax.servlet.http.HttpServletRequest)context.getExternalContext().getRequest();<br />    String authorName = req.getParameter(&quot;authorName&quot;);<br />    // find the selected node in the tree model:    <br />    Collection roots = (Collection)libraryTreeModel.getWrappedData();<br />    GenericTreeNode selectedNode = findNode( authorName, roots);<br />    this.selectedNode = selectedNode;<br /><br />    // This would seem the more logical code for handling the event and its <br />    // associated parameter. Unfortunately, it turns out that this method is<br />    // invoked for each of the Author nodes in the tree, regardless of the<br />    // node whose commandlink was actually clicked on; what's more: for each<br />    // of these invocations, the value of the UIParameter authorName is equal<br />    // to the node being dealt with. So for three authors, even if we select<br />    // the second one, this method is called three times with three different<br />    // values for the UIParameter. However, reading the parameter authorName<br />    // directly from the HttpServletRequest does get us a single value.<br />    // I probably make somehow inappropriate use of the ADF Faces tree component...<br />    /*<br />    UIComponent component = (UIComponent)event.getSource();<br />    List children = component.getChildren();<br />    for (int i=0;i&lt;children.size();i++) {<br />      if (children.get(i) instanceof UIParameter) {<br />        UIParameter currentParam = (UIParameter)children.get(i);<br />        if (currentParam.getName().equals(&quot;authorName&quot;)) {<br />            String nodeAuthorName = (String)currentParam.getValue();            <br />        }            <br />      }<br />    }<br />    }<br />    // deal with selected Author node<br />    */<br />    }<br /><br />    public void setSelectedNode(GenericTreeNode selectedNode) {<br />        this.selectedNode = selectedNode;<br />    }<br /><br />    public GenericTreeNode getSelectedNode() {<br />        return selectedNode;<br />    }<br />    }<br />&nbsp;

I have the feeling that I am missing out on some of the features
available to me in ADF Faces’s tree component, but at least I have my
application working. The result looks like this:

 

Next steps

Link the Tree up with a proper Database backed Model, for example
using Spring or EJB 3.0. Also: look at other ADF Faces components and
how they compare to MyFaces Tomahawk components. And of course delve
deeper into what the af:tree can do – since obviously I have only
scratched the surface. If anyone reading this has pointers on how to
dig deeper: please share them!

Resources

Working with ADF Faces Components – On Line documentation for JDeveloper 10.1.3 

Download the JDeveloper 10.1.3EA Application Workspace for the AdfFacesTreeTrials application as discussed in this article, including all sources: AdfFacesTrials.zip

More specifically: Documentation for the <af:tree> element on OTN

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

14 Comments

  1. Hi,

    Thanks a bunch for this application.It proved to be very useful.Do u have any idea about how to highlight the selected node

  2. HI Lucas Jellema,

    This Article on Tree Component is very useful. Thank you very much for the same.

    Can I have a similar approach on using JDeveloper 11G as some of the Classes used in jDev10.1.3 is depricated in 11G.

    Thank you … Dev

  3. Thank you so much for the tree example. I was able to use it successfully. In using GenericTreeNode, I was unable to use Michal’s or Chintan’s suggestion. The error was in the jsp file in still needing to output the longdescription. Thanks you again.

  4. Nuruthin Ahammed on

    Your article was very help ful to create tree components using ADF Faces. But my aim is to create treeTable component by fetching records from DEPARTMENT & EMP tables. But I am not using JDeveloper. Using eclipse for file creation and tomcat to run the application. How can I add all details of employee as columns in tree table. Actually the treeTable should show the DEPARTMENTS. When click on Departments it should expand to show the Employees along with all the details in the same row, but in separate columns.

  5. Nuruthin Ahammed on

    I want to make treeTable demo application which will give the drilldown facility. What changes should I give to implement this facility.

  6. This is a fantastic post! I would just like to add that if you override the isContainer method on your TreeModel that you can display leave nodes. Thanks for your time and consideration. Hope that is helpful.

    Regards,
    Ric

  7. Ok, it didn’t processed ok the jspx file and faces-config.xml but that certainly is not anything complicated to produce one of your own.

  8. The original example has a slight problem that it displays as a parent node even nodes without children – Chintan’s suggestion solves the problem, code looks like this:
    ———————————————-
    .jspx file:

    ———————————————-
    faces-config.xml:

    oracle.adf.core

    tree2
    sk.skulm.gen.tree2.Tree
    session

    ———————————————-
    Tree.java:

    package sk.skulm.gen.tree2;
    import oracle.adf.view.faces.model.ChildPropertyTreeModel;
    import java.util.ArrayList;
    import sk.skulm.gen.tree2.TreeNode;
    import javax.faces.context.FacesContext;
    import javax.faces.event.AbortProcessingException;
    import javax.faces.event.ActionEvent;
    import javax.servlet.http.HttpServletRequest;
    import java.util.Collection;
    import oracle.adf.view.faces.component.core.data.CoreTree;

    public class Tree{
    private ChildPropertyTreeModel model;
    private String selectedNodeLabel = null;
    private CoreTree tree;

    public Tree() {
    TreeNode node_0 = new TreeNode(“node_0″);
    TreeNode node_0_0 = new TreeNode(“node_0_0″);
    TreeNode node_0_0_0 = new TreeNode(“node_0_0_0″);
    TreeNode node_0_0_0_0 = new TreeNode(“node_0_0_0_0″);
    TreeNode node_0_0_1 = new TreeNode(“node_0_0_1″);
    TreeNode node_0_1 = new TreeNode(“node_0_1″);
    TreeNode node_0_1_0 = new TreeNode(“node_0_1_0″);
    TreeNode node_0_1_1 = new TreeNode(“node_0_1_1″);
    TreeNode node_0_2 = new TreeNode(“node_0_2″);
    TreeNode node_0_3 = new TreeNode(“node_0_3″);
    TreeNode node_0_4 = new TreeNode(“node_0_4″);
    TreeNode node_0_5 = new TreeNode(“node_0_5″);

    ArrayList list_0 = new ArrayList();
    list_0.add(node_0_0);
    list_0.add(node_0_1);
    list_0.add(node_0_2);
    list_0.add(node_0_3);
    list_0.add(node_0_4);
    list_0.add(node_0_5);
    node_0.setChildren(list_0);

    ArrayList list_0_0 = new ArrayList();
    list_0_0.add(node_0_0_0);
    list_0_0.add(node_0_0_1);
    node_0_0.setChildren(list_0_0);

    ArrayList list_0_0_0 = new ArrayList();
    list_0_0_0.add(node_0_0_0_0);
    node_0_0_0.setChildren(list_0_0_0);

    ArrayList list_0_1 = new ArrayList();
    list_0_1.add(node_0_1_0);
    list_0_1.add(node_0_1_1);
    node_0_1.setChildren(list_0_1);
    this.model = new ChildPropertyTreeModel(list_0, “children”);
    }

    public ChildPropertyTreeModel getModel()
    { return this.model;
    }

    public void setModel(ChildPropertyTreeModel model)
    { this.model = model;
    }

    public void process(ActionEvent event) throws AbortProcessingException {
    this.selectedNodeLabel = ((TreeNode)model.getRowData()).getLabel();
    }

    public void setSelectedNodeLabel(String selectedNodeLabel) {
    this.selectedNodeLabel = selectedNodeLabel;
    }

    public String getSelectedNodeLabel() {
    return this.selectedNodeLabel;
    }

    public void setTree(CoreTree tree) {
    this.tree = tree;
    }

    public CoreTree getTree() {
    return this.tree;
    }
    }

    ———————————————-
    TreeNode.java:

    package sk.skulm.gen.tree2;
    import java.util.ArrayList;

    public class TreeNode {
    private ArrayList children;
    private String label;

    public TreeNode(String label) {
    this.label = label;
    }

    public void setChildren(ArrayList children)
    { this.children = children;
    }

    public ArrayList getChildren()
    { return this.children;
    }

    public void setLabel(String label)
    { this.label = label;
    }

    public String getLabel()
    { return this.label;
    }
    }

  9. Thanks for the example, after searching days for a simple adf faces tree sample really appreciate yours here.
    There are also tree examples in adf-faces-demo.war packed in adf-faces-10_1_3_0_4.zip download but the one with selecting value functionality was rather too complex for a newbie like me…

    Michal

  10. Hi,
    Your example is quite useful. But in order to get selected node in ADF faces, you don’t need to have HTTP parameter. You can easily bind table with backing bean table using BINDING variable of table and then just use get method : here is the sample code:

    In backing bean:
    private CoreTree bookTree; with getter and setters.

    In actionEvent:
    this.selectedNode = ( (GenericTreeNode) bookTree.getRowData() );
    Here you don’t need find method either.

    and this concept is from JSF faces, isn’t it?
    let me know your comments.

    Thanks,
    Chintan

  11. Hey, this page was VERY HELPFUL for me.

    You shell also consider build the Library in the faces-config, as managed-beans,
    I didn’t find an example that will help me modify my app to use it (I try to use menuTabs, as in an example of Oracle, but it required menuModel and menuTree, so I bypassed it using your example. But they used the managed-beans for the content, and I want to do so too)

    If you have link or instructions how to do it you are most welcome to write me,

    Regards,
    Sagi