In this chapter, we will learn about tree processing in RichFaces. RichFaces provide all the required components to create and manipulate a tree.
This tag is used to create a hierarchical tree. Each node provided inside the <treeNode> will be a child node of the tree. This tag will be used with another tag called <rich:tree>. All the instance variables we are using to create a tree must implement any of these three interfaces - org.richfaces.model.TreeNode, org.richfaces.model.TreeDataModel, and javax.swing.tree.TreeNode.
In the following example, we will populate a tree using <rich:treeNode> tag from the backend.
<?xml version = "1.0" encoding = "UTF-8"?> <!DOCTYPE html> <html xmlns = "http://www.w3.org/1999/xhtml" xmlns:h = "http://java.sun.com/jsf/html" xmlns:f = "http://java.sun.com/jsf/core" xmlns:ui = "http://java.sun.com/jsf/facelets" xmlns:a4j = "http://richfaces.org/a4j" xmlns:rich = "http://richfaces.org/rich"> <h:head> <title>TreeNode Example</title> <meta name = "viewport" content = "width = device-width, initial-scale = 1.0"/> </h:head> <h:body> <h:form> <rich:tree value = "#{tree.populateNode}" var = "tree"> <rich:treeNode> <rich:treeModelRecursiveAdaptor> </rich:treeModelRecursiveAdaptor> <h:outputText value = "#{tree.data}" /> </rich:treeNode> </rich:tree> </h:form> </h:body> </html>
Following is the related java class that implements “TreeNodeImpl” interface.
import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import org.richfaces.model.TreeNodeImpl; @ManagedBean @RequestScoped public class Tree extends TreeNodeImpl { private Tree stationRoot; private Tree populateNode; private Object data; public Tree() { super(); } public Tree(boolean leaf, Object data) { super(leaf); this.data = data; } public Object getData() { return data; } public Tree getPopulateNode() { if (populateNode == null) { String[] List_OF_Node = { "Frist Node", "Second Node", "Third Node", "Fourth Node", "Fifth Node"}; stationRoot = new Tree(false, "Example Of Tree"); for (int i = 0; i < List_OF_Node.length; i++) { Tree child = new Tree(true, List_OF_Node[i]); stationRoot.addChild(i, child); } populateNode = new Tree(); populateNode.addChild(0, stationRoot); } return populateNode; } }
The above piece of code will produce the following output in the browser.
This component takes a Map as an input, iterates through it, and produces the required output in the browser. Whenever we need to populate a recursive map, we can use another tag called <rich:recursiveTreeModelAdaptor>.
The following example shows how to render the project structure in the browser. In RichFaces 3, these two tags are used <rich:treeNodeAdaptor> and <rich:recursiveTreeNodeAdaptor>.
<?xml version = "1.0" encoding = "UTF-8"?> <!DOCTYPE html> <html xmlns = "http://www.w3.org/1999/xhtml" xmlns:h = "http://java.sun.com/jsf/html" xmlns:f = "http://java.sun.com/jsf/core" xmlns:ui = "http://java.sun.com/jsf/facelets" xmlns:a4j = "http://richfaces.org/a4j" xmlns:rich = "http://richfaces.org/rich"> <h:head> <title>Tree Model and Recursive Model Example</title> </h:head> <h:body> <h:form id = "form"> <rich:tree toggleType = "AJAX" var = "item" style = "max-width: 400px"> <rich:treeModelRecursiveAdaptor roots = "#{fileSystemBean.sourceRoots}" nodes = "#{item.directories}"> <rich:treeNode> #{item.shortPath} </rich:treeNode> <rich:treeModelAdaptor nodes = "#{item.files}"> <rich:treeNode>#{item}</rich:treeNode> </rich:treeModelAdaptor> </rich:treeModelRecursiveAdaptor> </rich:tree> </h:form> </h:body> </html>
We need to create two new java beans for this example. Following is the code snippet for bean class ”FileSystemBean.java”, which holds the required folder name.
import java.util.List; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; @ManagedBean @RequestScoped public class FileSystemBean { private static final String SRC_PATH = "/WEB-INF"; private List<FileSystemNode> srcRoots; public synchronized List<FileSystemNode> getSourceRoots() { if (srcRoots == null) { srcRoots = new FileSystemNode(SRC_PATH).getDirectories(); } return srcRoots; } }
Following is the code snippet for bean class “FileSystemNode.java”, which holds the required the leaf node of the project.
import static com.google.common.base.Predicates.containsPattern; import static com.google.common.base.Predicates.not; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import com.google.common.base.Function; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; public class FileSystemNode { private static final Function<String, FileSystemNode> FACTORY = new Function<String, FileSystemNode>() { public FileSystemNode apply(String from) { return new FileSystemNode(from.substring(0, from.length() - 1)); }; }; private static final Function<String, String> TO_SHORT_PATH = new Function<String, String>() { public String apply(String from) { int idx = from.lastIndexOf('/'); if (idx < 0) { return from; } return from.substring(idx + 1); }; }; private String path; private List<FileSystemNode> directories; private List<String> files; private String shortPath; public FileSystemNode(String path) { this.path = path; int idx = path.lastIndexOf('/'); if (idx != -1) { shortPath = path.substring(idx + 1); } else { shortPath = path; } } public synchronized List<FileSystemNode> getDirectories() { if (directories == null) { directories = Lists.newArrayList(); Iterables.addAll(directories, transform(filter( getResourcePaths(), containsPattern("/$")), FACTORY)); } return directories; } public synchronized List<String> getFiles() { if (files == null) { files = new ArrayList<String>(); Iterables.addAll(files, transform(filter( getResourcePaths(), not(containsPattern("/$"))), TO_SHORT_PATH)); } return files; } private Iterable<String> getResourcePaths() { FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); Set<String> resourcePaths = externalContext.getResourcePaths(this.path); if (resourcePaths == null) { resourcePaths = Collections.emptySet(); } return resourcePaths; } public String getShortPath() { return shortPath; } }
The above example will produce the following output in the browser.