Hierarchy

Overview

Refer to the javax.baja.hierarchy API.

Hierarchies provide a dynamic navigation layer to the Niagara Framework. By using neql to query tags and relations, they allow for the creation navigation trees that are not based on the station’s config.bog tree structure.

Creation

Hierarchies are defined under the BHierarchyService and the resulting hierarchy is shown in the BHierarchySpace.

The HierarchyService contains the definitions for each hierarchy in the system. These are the sets of rules for creating navigational hierarchies. Each hierarchy is defined by a BHierarchy and one or more BLevelDefs. The ordering of the BLevelDefs under a BHierarchy define the order in which they’re used to create the hierarchy. Each BLevelDef defines a level of a hierarchy where each node at that level uses the same rules for creation and determining its children.

LevelDefs

The Niagara Framework provides four BLevelDefs for creating hierarchies. These are divided into two basic types: grouping and entity. The two grouping definitions, BListLevelDef and BGroupLevelDef implement the BIGroupingLevelDef marker interface. These create virtual groups or folders of entities in the navigational hierarchy. They are not typically used for leafs in the tree so they will not typically be the last BLevelDef under a BHierarchy.

BGroupLevelDef uses Tag values to create groupings in a hierarchy. For each unique value of the given BGroupLevelDef.groupBy Tag in the system, a node will be created in the hierarchy. It is important to note that BGroupLevelDef.groupBy is a single Tag.id and not a neql query.

BListLevelDef also creates groupings in a hierarchy. Unlike BGroupLevelDef where the groupings are dynamic, BListLevelDef creates a static list of groups using BNamedGroupDefs. Each BNamedGroupDef creates a node in the resulting hierarchy and filters the entities under it based on the the defined query.

The two entity level definitions, BQueryLevelDef and BRelationLevelDef, populate the hierarchy with entity nodes. Typically these are BComponents. BQueryLevelDef uses a neql query to determine which entities to display in the hierarchy. By default, the results are filtered against any preceding BIGroupingLevelDefs in the hierarchy definition. If this is not desired, the includeGroupingQueries property can be set to false.

BRelationLevelDef uses Relation traversal to determine the displayed entities. Starting from the previous entity in the hierarchy, the relations specified by the relationId are traversed and the entities at the endpoints of those Relations are displayed in the hierarchy. Given this, a BRelationLevelDef will always be preceded by a BQueryLevelDef in the BHierarchy in order to define the Entity being traversed from. By default, inbound relations with the given relationId are followed. Outbound relations can be used instead by setting inbound to false. The set of returned entities can be further filtered by setting a neql expression in the filterExpression property. If repeatRelation is true, additional levels will be created in the hierarchy each time that defined relation is able to be traversed from the endpoint of the previous relation - a typical use of this is to traverse n:child relations to the end of the component tree.

Several properties are common to all BLevelDefs. The use of the queryContext property is discussed in the Doc Hierarchies Guide. sort, a BLevelSort, can be set to either BLevelSort.ascending or BLevelSort.descending. hierarchyTags are currently reserved for future use.

A useful tool when working with hierarchies is to turn on logging. Setting the hierarchy log to FINE under the DebugService will log the neql query that is run to produce each level of a hierarchy when that level is expanded under the HierarchySpace.

Scope

Hierarchies have a scope. What this means is that the queries used to produce a hierarchy can be run against one or more BSpaces. As of Niagara 4.0, the only supported space is the Station space. To add additional spaces in the future, one or more BHierarchyScopes can be added to the BHierarchyScopeContainer in the BHierarchy. The scopeOrd is simply the BOrdScheme for the desired space.

Roles

In order for users to be able to view a hierarchy, they need permissions to do so. When the BHierarchyService is added to a station, the BRoleHierarchies BIMixIn is added to each BRole as the viewableHierarchies property. BRoleHierarchies.hierarchyNames is a comma separated list of the BHierarchyDef names that the BRole has permissions to view.

Navigation

Hierarchies are displayed under the HierarchySpace. Each BHierarchyDef results in a child of the BHierarchySpace. These children of the Hierarchy Space, and the their children, are BLevelElems. BLevelElems implement BINavNode and are traversed using BINavNode.getNavChildren() and BINavNode.getNavParent().

Ords

The HierarchyOrdScheme defines hierarchy: as the BOrdScheme for resolving BLevelElems in a hierarchy. A HierarchyQuery is used for the body of the BOrd.

Note that since each part of a HierarchyQuery may result in a neql query being executed, hierarchy: Ord resolution may be very expensive. If hierarchy: Ords need to be resolved, developers should consider caching the results for improved performance.

Code Samples

The following code samples assume that you have hierarchies defined with given names and are provided as a getting started point.

Resolve a hierarchy: Ord in the Client

  BHierarchySpace hierarchySpace = (BHierarchySpace)BOrd.make("hierarchy:").get(rootComponent);  
  BLevelElem sampleHierarchy = (BLevelElem)BOrd.make("hierarchy:SampleHierarchy").get(rootComponent);  

Resolve a hierarchy: Ord in the Station

Even though hierarchy definitions exist in the station, the resulting hierarchies only exist in the client environment. Given this, Ord resolutions will only work in the client environment. To resolve hierarchy: Ord in the station, we need to use an alternative method. BHierarchyService.resolveHierarchyLevelElem() allows us to resolve HierarchiesQueries in the station VM.

  BHierarchyService hierarchyService = (BHierarchyService)BOrd.make("service:hierarchy:HierarchyService").get(rootComponent);  
  BLevelElem sampleHierarchy = hierarchyService.resolveHierarchyLevelElem(new HierarchyQuery("/sampleHierarchy"));  

Hierarchy Traversal

Hierarchy traversal is best accomplished by treating BLevelElems as BINavNodes.

  BLevelElem sampleHierarchy = (BLevelElem)BOrd.make("hierarchy:SampleHierarchy").get(rootComponent);  
  BINavNode[] firstLevelChildren = sampleHierarchy.getNavChildren();  
  for (int i=0; i<firstLevelChildren.length; i++)  
  {  
    System.out.println(firstLevelChildren[i].getNavDisplayName(null));  
  }