This tree assumes that there is a view named "Managers" that contains all applicable Person documents, categorized by their "Manager" field and with their "ShortName" field in the second column. Moreover, it's assumed that the "Manager" field contains the "ShortName" value of their manager, and that the top of the tree has an empty field.



test/Names.java

package test;

import com.ibm.xsp.extlib.tree.impl.*;
import lotus.domino.*;
import javax.faces.context.FacesContext;
import java.util.*;

public class Names extends BasicNodeList {
	private static final long serialVersionUID = -6873644238872938295L;

	private transient View managerView = null;
	private final Set<String> processedNames = new HashSet<String>();

	public Names() throws NotesException {
		Database database = (Database)this.getVariableValue("database");
		this.managerView = database.getView("Managers");
		this.managerView.setAutoUpdate(false);

		ViewEntryCollection bosses = this.managerView.getAllEntriesByKey("", true);
		ViewEntry boss = bosses.getFirstEntry();
		while(boss != null) {
			this.processNode(String.valueOf(boss.getColumnValues().get(1)), null);

			ViewEntry tempEntry = boss;
			boss = bosses.getNextEntry(boss);
			tempEntry.recycle();
		}
		bosses.recycle();
	}

	private void processNode(String name, BasicTreeNode parent) throws NotesException {
		// Fetch the reports collection immediately so we can determine if this node is a leaf
		ViewEntryCollection reports = this.managerView.getAllEntriesByKey(name, true);

		// Create the node as appropriate - BasicTreeNode is the immediate common abstract parent of both node types
		BasicTreeNode node = reports.getCount() > 0 ? new BasicContainerTreeNode() : new BasicLeafTreeNode();
		node.setLabel(name);

		// Add the node to either the root of the tree (if it's a top-level person) or to the provided parent
		if(parent == null) {
			this.addChild(node);
		} else {
			// The parent should be a container node if we got here
			((BasicContainerTreeNode)parent).addChild(node);
		}

		// After a quick sanity check, it's time for recursion!
		if(!this.processedNames.contains(name)) {
			ViewEntry report = reports.getFirstEntry();
			while(report != null) {
				this.processNode(String.valueOf(report.getColumnValues().get(1)), node);

				ViewEntry tempReport = report;
				report = reports.getNextEntry(report);
				tempReport.recycle();
			}
			reports.recycle();
			this.processedNames.add(name);
		}
	}

	private Object getVariableValue(String varName) { 
		FacesContext context = FacesContext.getCurrentInstance(); 
		return context.getApplication().getVariableResolver().resolveVariable(context, varName); 
	} 
}

XSP

<xe:navigator expandable="true">
	<xe:this.treeNodes>
		<xe:beanTreeNode nodeBean="test.Names"/>
	</xe:this.treeNodes>
</xe:navigator>

CSS

.lotusMenuSubsection {
	margin-left: 2em !important;
}

Managers.view

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE view SYSTEM 'xmlschemas/domino_8_5_3.dtd'>
<view name='Managers' xmlns='http://www.lotus.com/dxl'>

	<code event='selection'><formula>SELECT Type = "Person"</formula></code>
	
	<column sort='ascending' itemname='$25' width='10' separatemultiplevalues='true' categorized='true'>
		<font style='bold'/>
		<columnheader title='Manager'><font size='9pt' style='bold underline'/></columnheader>
		<code event='value'><formula>@If(@LowerCase(Manager)=@LowerCase(ShortName); ""; Manager)</formula></code>
	</column>
	<column sort='ascending' itemname='ShortName' width='10'>
		<columnheader title='Short Name'><font size='9pt' style='bold underline'/></columnheader>
	</column>
</view>