Reading Structure Content
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.
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?
}
Now you have structureId
or an error situation where the name does not uniquely identify your structure.
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);
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.
Retrieve ForestSource
A ForestSource
is an interface that produces some specific forest and that provides versioning for it.
ForestSource forestSource = myStructureComponents.getForestService().getForestSource(forestSpec);
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.
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();
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
.
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);
...
}
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.
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!
...
}
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)) {
...
}
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.