[richfaces-issues] [JBoss JIRA] Created: (RF-3569) <rich:tree> possible performance issue

martin bischoff (JIRA) jira-events at lists.jboss.org
Wed May 28 06:23:49 EDT 2008


<rich:tree> possible performance issue 
---------------------------------------

                 Key: RF-3569
                 URL: http://jira.jboss.com/jira/browse/RF-3569
             Project: RichFaces
          Issue Type: Quality Risk
    Affects Versions: 3.2.0
            Reporter: martin bischoff
             Fix For: 3.2.0.SR1


i've got an quite simple tree with "just" 50 elements á 200 childs -> 10.000 nodes

every node gots:
- some little text
- image for a checkbox via h:graphicImage
- a4j:support for listenersupport at the image

expanding/collapsing nodes and checking the checkboxes takes a lot of time...

jprofiler tells me that most of the time is spend by domparsing. i dont know if i handle the tree as intended. here is some code:

JSP
[code]
<%@ taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
<%@ taglib uri="http://richfaces.org/rich" prefix="rich"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html>
<head>
<title>tree</title>
</head>
<body>
<f:view>
	<h:form>
			<a4j:loadStyle src="/res/button.css" />
			<a4j:loadStyle src="/res/tree/style.css" />
			<a4j:commandButton id="show_me" value="show childs" styleClass="normalButton">
			<a4j:ajaxListener type="controller.listener.ListenerBean" />
		</a4j:commandButton>
		<h:panelGrid columns="2">
         <h:outputLabel>
        <h:outputText value="infinite Tree extended"></h:outputText>
        <rich:tree componentState="#{treeBean.treeState}" id="infinite_Tree_expanded" style="width:300px" switchType="ajax"  stateAdvisor="#{treeDemoStateAdvisor}">
     
            <rich:recursiveTreeNodesAdaptor roots="#{treeBean.rootNodes}" var="item" nodes="#{item.children}">
            	<rich:treeNode nodeSelectListener="#{treeBean.processSelection}">
            	<h:graphicImage value="/res/tree/chkb_#{item.state}.png">
            		<a4j:support event="onclick" reRender="infinite_Tree_expanded" actionListener="#{item.actionListener}"/>
            	</h:graphicImage>
            	<h:outputText value="#{item.value} - #{item.state}"/> 
            	</rich:treeNode>
            </rich:recursiveTreeNodesAdaptor>
       
        </rich:tree>
        </h:outputLabel>
        </h:panelGrid>
	</h:form>
</f:view>
</body>
</html>[/code]

TreeBean:
[code]package my_tree;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;

import org.richfaces.component.state.TreeState;
import org.richfaces.event.NodeSelectedEvent;

public class TreeBean {

	private TreeNode rootNode = null;
	private TreeNode[] rootNodes = null;

	private TreeState treeState;

	private static final String DATA_PATH = "/res/tree/simple-tree-data.properties";

	public TreeNode getRootNode() {
		if (rootNode == null) {
			loadTree();
		}

		return rootNode;
	}

	public void setRootNode(TreeNode rootNode) {
		this.rootNode = rootNode;
	}

	public TreeNode[] getRootNodes() {
		if (rootNodes == null) {
			rootNodes = this.getRootNode().getChildren();
		}
		return rootNodes;
	}

	public void setRootNodes(TreeNode[] rootNodes) {
		this.rootNodes = rootNodes;
	}

	public TreeState getTreeState() {
		return treeState;
	}

	public void setTreeState(TreeState treeState) {
		this.treeState = treeState;
	}

	private void addNodes(String path, TreeNode node, Properties properties) {
		boolean end = false;
		int counter = 1;

		while (!end) {
			String key = path != null ? path + '.' + counter : String
					.valueOf(counter);

			String value = properties.getProperty(key);
			if (value != null) {
				TreeNode newNode = new TreeNode(value);
				newNode.setParent(node);
				node.addNode(newNode);
				addNodes(key, newNode, properties);
				counter++;
			} else {
				end = true;
			}
		}
	}

	private void loadTree() {
		System.out.println("TreeBean -> loadTree()");
		FacesContext facesContext = FacesContext.getCurrentInstance();
		ExternalContext externalContext = facesContext.getExternalContext();
		InputStream dataStream = externalContext.getResourceAsStream(DATA_PATH);
		try {
			Properties properties = new Properties();
			properties.load(dataStream);

			rootNode = new TreeNode("root");
			addNodes(null, rootNode, properties);
			// manual tree extension

			TreeNode dummy = new TreeNode("Sichtlinie");
			int count = 0;
			for (int i = 1; i <= 50; i++) {
				count++;
				TreeNode node = new TreeNode("i" + i);
				for (int j = 1; j <= 200; j++) {
					count++;
					if (count % 1000 == 0) {
						System.out.println(count);
					}
					TreeNode child = new TreeNode("j" + j);
					child.setParent(node);
					node.addNode(child);
				}
				node.setParent(dummy);
				dummy.addNode(node);
			}
			rootNode.addNode(dummy);

		} catch (IOException e) {
			e.printStackTrace();
			throw new FacesException(e.getMessage(), e);

		} finally {
			if (dataStream != null) {
				try {
					dataStream.close();
				} catch (IOException e) {
					e.printStackTrace();
					externalContext.log(e.getMessage(), e);
				}
			}
		}

	}

	public void processSelection(NodeSelectedEvent arg0)
			throws AbortProcessingException {
		System.out.println("SimpleTreeBean -> processSelection fired by "
				+ arg0.getComponent().getId());

	}[/code]

TreeNode:
[code]package my_tree;

import javax.faces.event.ActionEvent;

import org.richfaces.model.TreeNodeImpl;



public class TreeNode{


	private String value;
	private String state;

	private TreeNode parent;
	private TreeNode[] children;
	

	public TreeNode(String value) {
		this.value = value;
		this.state = "";
	}

	public synchronized void addNode(TreeNode newChild) {
		System.out.println("addNode("+newChild.getValue()+")");
		if (this.children == null) {
			TreeNode[] merged = new TreeNode[1];
			merged[0] = newChild;
			this.children = merged;
		} else {
			TreeNode[] merged = new TreeNode[this.children.length + 1];
			int i;
			for (i = 0; i < this.children.length; i++) {
				merged[i] = this.children[i];
			}
			merged[merged.length - 1] = newChild;
			this.children = merged;
		}
	}

	public synchronized void addNodes(TreeNode[] newChildren) {
		System.out.println("addNodeS("+newChildren.length+")");
		TreeNode[] merged = new TreeNode[newChildren.length
				+ this.children.length];
		int i;
		for (i = 0; i <= this.children.length; i++) {
			merged[i] = this.children[i];
		}
		for (int i2 = i; i2 <= newChildren.length + i; i2++) {
			merged[i2] = newChildren[i2];
		}
		this.children = merged;
	}

	public synchronized void removeNodes(TreeNode[] removeChildren) {
		TreeNode[] splitted = new TreeNode[this.children.length
				- removeChildren.length];
		int pos = 0;
		for (int i = 0; i <= this.children.length; i++) {
			boolean contains = false;
			for (int j = 0; j <= removeChildren.length; j++) {
				if (this.children[i] == removeChildren[j]) {
					contains = true;
				}
			}
			if (contains == false) {
				splitted[pos] = this.children[i];
				pos++;
			}
		}
	}

	public String checkSibling(){
		//System.out.println("checkSibling() of "+this.value);
		if(this.children!=null){
			String state = null;
			int checked = 0;
			int sub = 0;
			int i;	
			TreeNode[] siblings = this.children;
			for (i = 0; i < siblings.length; i++) {
				
				TreeNode treeNode = siblings[i];
				//System.out.println("\t"+treeNode.getValue()+" - "+treeNode.getState());
					if(!treeNode.getState().equals("")){
						if(treeNode.getState().equals("checked")){
							checked++;
						} else	if(treeNode.getState().equals("sub")){
							sub++;
						}
					}
				
			}
			
			if(checked == i){
				state = "checked";
			} else if(sub > 0 || checked > 0) {
				state = "sub";
			} else {
				state = "";
			}
			//System.out.println("siblings: "+i+" (checked: "+checked+" sub: "+sub+") -> "+state);
			return state;
		} else {
			return "";
		}

	}
	
	public void setChildsChecked(TreeNode node){
		//System.out.println("TreeNode -> setChildsChecked of "+node.getValue());
		if(node.getChildren()!=null){
			TreeNode[] children = node.getChildren();
			for (int i = 0; i < children.length; i++) {
				TreeNode treeNode = children[i];
				treeNode.setState("checked");
				setChildsChecked(treeNode);
			}
		}
	}
	
	public void setChildsUnchecked(TreeNode node){
		//System.out.println("TreeNode -> setChildsUnchecked of "+node.getValue());
		if(node.getChildren()!=null){
			TreeNode[] children = node.getChildren();
			for (int i = 0; i < children.length; i++) {
				TreeNode treeNode = children[i];
				treeNode.setState("");
				setChildsUnchecked(treeNode);
			}
		}
	}

	public void setParentsState(TreeNode node){
		System.out.println("TreeNode -> setParentsState of "+node.getValue());
		node.setState(node.checkSibling());
		if(node.getParent()!=null){
			setParentsState(node.getParent());
		}
	}	
	
	public void actionListener(ActionEvent ae){
		//System.out.println("TreeNode -> nodeListener fired by "+ae.getComponent().getId());
		if(this.state == "checked"){
			this.state = "";
			setChildsUnchecked(this);
		} else {
			this.state = "checked";
			setChildsChecked(this);
		}
		if(this.parent!=null){
			setParentsState(this.parent);
		}
		
	}	
	
		public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

    public TreeNode[] getChildren() {
		return children;
	}

	public void setChildren(TreeNode[] children) {
		this.children = children;
	}

	
	
	public TreeNode getParent() {
		if(parent==null){
			return null;
		} else {
		return parent;
		}
	}

	public void setParent(TreeNode parent) {
		this.parent = parent;
	}

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}


}
[/code]

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.jboss.com/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

       




More information about the richfaces-issues mailing list