Let's say you need to access a structure's content and export the hierarchy into your custom format or use for displaying the hierarchy in your way. This scenario walks you through from having just a structure name to iterating through the forest and learning which items are there.

We assume that your code has StructureComponents instance injected into myStructureComponents field.

1. Figure out Structure ID

To address a structure, you need to know its ID. If you just have a name you can do the following:

List<Structure> structures = myStructureComponents.getStructureManager().getStructuresByName("My Structure", PermissionLevel.VIEW);
long structureId;
if (structures.size() == 1) {
  structureId = structures.get(0).getId();
} else {
  // no structures or too many structures -- error?
}
CODE

Now you have structureId or an error situation where the name does not uniquely identify your structure.

2. Create a ForestSpec

You need a forest specification to get a ForestSource. You can read more about this in the section about Building Forest Specification.

ForestSpec forestSpec = ForestSpec.structure(structureId);
CODE

Note that this forest spec is going to be "secured" for the current user, which means that the resulting forest will exclude the sub-trees that only contain items not visible to the user.

3. Retrieve ForestSource

A ForestSource is an interface that produces some specific forest and that provides versioning for it.

ForestSource forestSource = myStructureComponents.getForestService().getForestSource(forestSpec);
CODE

Note that this call may produce StructureException in case a structure cannot be found and in some other cases. A robust code would have some exception handling.

Do not store a ForestSource in memory for a long time, longer than a single user request. Structure has internal caching engine that efficiently manages forest sources and their dependencies. Request forest source from ForestService in every new request.

4. Retrieve Forest and its version

Forest source can provide you with the latest version of the forest, or with an incremental update, based on the version you already have.

To get the latest forest:

VersionedForest versionedForest = forestSource.getLatest();
DataVersion latestVersion = versionedForest.getVersion();
Forest forest = versionedForest.getForest();
CODE

Note that latestVersion variable contains the version of the forest that you got. You can later use it to call forestSource.getUpdate(latestVersion) and receive only information about how did the forest change since the last time you've seen it.

You cannot really use latestVersion for anything else besides getting updates later. The numbers in that version bear no meaning regarding structure's history. For history queries, you'll need to use HistoryService.

5. Iterate through Forest and get StructureRow instances

A Forest is just two parallel arrays, one containing row IDs, the other containing depths. (Or, one can say that it is a list of pairs (rowId, depth).) You can iterate through it via simple cycle.

For each row, you'll need more information than just row ID. We use RowManager to retrieve other properties of a row.

RowManager rowManager = myStructureComponents.getRowManager();
for (int i = 0; i < forest.size(); i++) {
  long rowId = forest.getRow(i);
  int depth = forest.getDepth(i);
  StructureRow row = rowManager.getRow(rowId);
  ...
}
CODE

Note that row is never null, because Row Manager would through an unchecked exception if a row is not found – this situation is considered a developer's error.

6. Analyze the row and process data

Finally, you get ItemIdentity from the row to understand which item does the row show. The items could be anything – issues, folders, users. So even if your structure only contains issues, it is advised to do an extra check.

  ItemIdentity itemId = row.getItemId();
  if (CoreIdentities.isIssue(itemId)) {
    long issueId = itemId.getLongId();
    // process the row!
    ...
  }
CODE

A structure with dynamic content will also contain generators. If you take all the rows, regardless of the item type and use them somewhere, you might stumble upon a generator. To eliminate them from the analyzed forest, add a condition. The same is usually done for "loop markers", which are special items added by extenders to indicate that there's a loop (like cyclic issue links).

  ItemIdentity itemId = row.getItemId();
  if (!CoreIdentities.isGenerator(itemId) && !CoreIdentities.isLoopMarker(itemId)) {
    ...
  }
CODE

Congratulations! You've successfully implemented forest read-out.

You can adjust this walkthrough for your needs – for example, read a query result, or read only a portion of a forest.