Interface ScanningAttributeLoader<T>

Type Parameters:
T - type of the loaded value
All Superinterfaces:
AttributeLoader<T>, MultiRowAttributeLoader<T>, RowAttributeLoader<T>
All Known Implementing Classes:
AbstractScanningLoader, DelegatingScanningAttributeLoader, ScanningLongSumLoader, ScanningNumberSumLoader

@PublicSpi public interface ScanningAttributeLoader<T> extends MultiRowAttributeLoader<T>

Scanning attributes are used to process and aggregate values across all the forest, from top to bottom (depth-first traversal). Imagine fully expanding the forest and then processing each row, starting with the top and going down, aggregating a resulting value. For example, a rolling total can be implemented with a scanning attribute - it will show the total of some value of all the rows above the current one.

Scanning loader represents a scanning attribute. Scanning loading function for a row R can calculate value based on:

  • Already calculated value of the same attribute for the row, immediately preceding R;
  • Values of attribute dependencies for the row R;
  • StructureRow data for R and its immediate predecessor;
  • Forest depth of R and its immediate predecessor;
  • Context values, if declared with AttributeLoader.getContextDependencies().

The immediate predecessor is calculated without regarding the hierarchy. If R has index i in the forest, its immediate predecessor will have index i - 1. See Forest.getRow(int).

The loader must be a stable function. It must not depend on any other inputs, and should provide the same result for the same inputs every time: V(row) = SCANNING(V(predecessor(row)), dependencies(row)).

Similar to aggregates and propagates, this loader has a recursive definition and its properties can be derived by closing the recursion.

Using loader data

Note that sometimes a loader will need to store more data in AttributeValue than the resulting Java type allows. In that case, use loader data - see AttributeValue.withData(java.lang.Object).

Sensitive data control

A scanning attribute, as well as all multi-row loaders, is potentially capable of accessing data calculated for rows that the requesting user is not allowed to see. For example, an allocated budget may be inherited from a larger-scope budgeting parent issue, and a user may not have access to that issue.

If the attribute collected is considered sensitive (according to StructureConfiguration.getAttributeSensitivitySettings()), then the calls to AttributeLoaderContext.getDependencyValue(com.almworks.jira.structure.api.attribute.AttributeSpec<V>) will not disclose the hidden value. Instead, the loader function will receive AttributeValue.inaccessible().

In other words, you should not worry about implementing security checks in a scanning attribute, the system does it for you.

No super-root support

Scanning attribute loaders do not support super-root and will return undefined value for it all the time. When calculating 0th row's value, the preceding value will be AttributeValue.undefined(), and ScanningAttributeContext.getPrecedingRow() will return null.

See Also:
  • Method Details

    • loadValue

      @Nullable AttributeValue<T> loadValue(@NotNull AttributeValue<T> precedingValue, @NotNull ScanningAttributeContext context)

      Performs scanning loading. Must be a pure function - see ScanningAttributeLoader.

      If the value is missing or empty, the loader should return AttributeValue.undefined(). If for some reason this loader is not applicable for the given row, it should return null. (Note, however, that if multiple scanning loaders work on the same attribute, it could be tricky and lead to unexpected results.)

      Parameters:
      precedingValue - the value of this attribute for the immediately preceding row, or AttributeValue.undefined() for the very first row
      context - loading context
      Returns:
      the calculated value