# Class CoverageAggregator

Object
CoverageAggregator

public final class CoverageAggregator extends Object
Creates a grid coverage resource from an aggregation of an arbitrary number of other resources. This class accepts heterogeneous resources (a data lake), organizes them in a tree of resources as described in the next section, then performs different kinds of aggregation:

- Creation of a data cube from a collection of slices: If a collection of `GridCoverageResource` instances represent the same phenomenon (for example Sea Surface Temperature) over the same geographic area but at different dates and times. `CoverageAggregator` can be used for building a single data cube with a time axis.
- Aggregation of bands: Resources having different sample dimensions can be combined in a single resource.

## Generated resource tree

All source coverages should share the same CRS and have the same ranges (sample dimensions). If this is not the case, then the source coverages will be grouped in different aggregates with an uniform CRS and set of ranges in each sub-aggregates. More specifically, `CoverageAggregator` organizes resources as below, except that parent nodes having only one child are omitted:

        Root aggregate
        ├─ All coverages with same sample dimensions #1
        │  └─ ...
        └─ All coverages with same sample dimensions #2
           ├─ Coverages with equivalent reference systems #1
           │  └─ ...
           └─ Coverages with equivalent reference systems #2
              ├─ Slices with compatible "grid to CRS" #1
              ├─ Slices with compatible "grid to CRS" #2
              └─ ...

Where:

- Equivalent reference systems means two `CoordinateReferenceSystem` instances for which `CRS​.equivalent(…)` returns `true`.
- Compatible grid to CRS means two grid to CRS transforms which are identical (with small tolerance for rounding errors) except for the translation terms, with the additional condition that the translations, when expressed in units of grid cell indices, can differ only by integer amounts of cells.
- Slices means source coverages declared to this aggregator by calls to `add(…)` methods, after they have been incorporated in a data cube by this aggregator. Above tree does not contain the individual slices, but data cubes containing all slices that can fit.

## Multi-threading and concurrency

All `add(…)` methods can be invoked concurrently from arbitrary threads. It is okay to load `GridCoverageResource` instances in parallel threads and add those resources to `CoverageAggregator` without synchronization. However, the final
invalid reference

    #build()

method is not thread-safe; that method shall be invoked from a single thread after all sources have been added and no more addition are in progress.

Since:
  1.3

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `CoverageAggregator()`
  Creates an initially empty aggregator with no listeners.
  `CoverageAggregator(StoreListeners listeners)`
  Creates an initially empty aggregator with the given listeners.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `add(GridCoverage coverage)`
  Adds the given coverage.
  `void`
  `add(GridCoverage coverage, double lower, double span, SingleCRS crs)`
  Adds the given coverage augmented with a single grid dimension.
  `void`
  `add(GridCoverage coverage, Instant lower, Duration span)`
  Adds the given coverage augmented with a single temporal grid dimension.
  `void`
  `add(GridCoverage coverage, GridGeometry dimToAdd)`
  Adds the given coverage augmented with the specified grid dimensions.
  `void`
  `add(GridCoverageResource resource)`
  Adds the given resource.
  `void`
  `add(GridCoverageResource resource, double lower, double span, SingleCRS crs)`
  Adds the given resource augmented with a single grid dimension.
  `void`
  `add(GridCoverageResource resource, Instant lower, Duration span)`
  Adds the given resource augmented with a single temporal grid dimension.
  `void`
  `add(GridCoverageResource resource, GridGeometry dimToAdd)`
  Adds the given resource augmented with the specified grid dimensions.
  `void`
  `addAll(Stream<? extends GridCoverageResource> resources)`
  Adds all grid resources provided by the given stream.
  `void`
  `addComponents(Aggregate resource)`
  Adds all components of the given aggregate.
  `void`
  `addRangeAggregate(GridCoverageResource... sources)`
  Adds a resource whose range is the aggregation of the ranges of a sequence of resources.
  `void`
  `addRangeAggregate(GridCoverageResource[] sources, int[][] bandsPerSource)`
  Adds a resource whose range is the aggregation of the specified bands of a sequence of resources.
  `Resource`
  `build(GenericName identifier)`
  Builds a resource which is the aggregation or concatenation of all components added to this aggregator.
  `Colorizer`
  `getColorizer()`
  Returns the colorization algorithm to apply on computed images.
  `MergeStrategy`
  `getMergeStrategy()`
  Returns the algorithm to apply when more than one grid coverage can be found at the same grid index.
  `void`
  `setColorizer(Colorizer colorizer)`
  Sets the colorization algorithm to apply on computed images.
  `void`
  `setMergeStrategy(MergeStrategy strategy)`
  Sets the algorithm to apply when more than one grid coverage can be found at the same grid index.
  `String`
  `toString()`
  Returns a string representation for debugging purposes.

  ### Methods inherited from class Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

- ## Constructor Details

  - ### CoverageAggregator

    public CoverageAggregator()
    Creates an initially empty aggregator with no listeners.
    Since:
      1.4

  - ### CoverageAggregator

    public CoverageAggregator(StoreListeners listeners)
    Creates an initially empty aggregator with the given listeners.
    Parameters:
      `listeners` - listeners of the parent resource, or `null` if none. This is usually the listeners of the `DataStore`.

- ## Method Details

  - ### add

    public void add(GridCoverage coverage)
    Adds the given coverage. This method can be invoked from any thread.
    Parameters:
      `coverage` - coverage to add.
    Since:
      1.4

  - ### add

    public void add(GridCoverage coverage, GridGeometry dimToAdd)
    Adds the given coverage augmented with the specified grid dimensions. The `dimToAdd` argument contains typically vertical or temporal axes to add to a two-dimensional coverage. All additional dimensions in `dimToAdd` must have a grid extent size of one cell.
    Parameters:
      `coverage` - coverage to add.
      `dimToAdd` - the dimensions to append. The grid extent size must be 1 cell in all dimensions.
    Throws:
      `IllegalGridGeometryException` - if a dimension has more than one grid cell, or concatenation would result in duplicated grid axis types, or the compound CRS cannot be created.
    Since:
      1.5
    See Also:
      - `GridCoverageProcessor​.appendDimensions(GridCoverage, GridGeometry)`

  - ### add

    public void add(GridCoverage coverage, double lower, double span, SingleCRS crs)
    Adds the given coverage augmented with a single grid dimension. The additional dimension is typically a vertical axis to add to a two-dimensional coverage.
    Parameters:
      `coverage` - coverage to add.
      `lower` - lower coordinate value of the slice, in units of the CRS.
      `span` - size of the slice, in units of the CRS.
      `crs` - one-dimensional coordinate reference system of the slice, or `null` if unknown.
    Throws:
      `IllegalGridGeometryException` - if the compound CRS or compound extent cannot be created.
    Since:
      1.5
    See Also:
      - `GridCoverageProcessor​.appendDimension(GridCoverage, double, double, SingleCRS)`

  - ### add

    public void add(GridCoverage coverage, Instant lower, Duration span)
    Adds the given coverage augmented with a single temporal grid dimension. This method is provided for convenience, but should be used carefully. Slice coordinates computed from calendars tend to produce slices at irregular intervals or with heterogeneous spans, which result in coverages that cannot be aggregated by this `CoverageAggregator` class.
    Parameters:
      `lower` - start time of the slice.
      `span` - duration of the slice.
      `source` - the source on which to append a temporal dimension.
    Throws:
      `IllegalGridGeometryException` - if the compound CRS or compound extent cannot be created.
    Since:
      1.5
    See Also:
      - `GridCoverageProcessor​.appendDimension(GridCoverage, Instant, Duration)`

  - ### add

    public void add(GridCoverageResource resource) throws DataStoreException
    Adds the given resource. This method can be invoked from any thread. This method does not recursively decomposes an `Aggregate` into its component. If such decomposition is desired, see `addComponents(Aggregate)` instead.
    Parameters:
      `resource` - resource to add.
    Throws:
      `DataStoreException` - if the resource cannot be used.

  - ### add

    public void add(GridCoverageResource resource, GridGeometry dimToAdd) throws DataStoreException
    Adds the given resource augmented with the specified grid dimensions. The `dimToAdd` argument contains typically vertical or temporal axes to add to a two-dimensional resource. All additional dimensions in `dimToAdd` must have a grid extent size of one cell.
    Parameters:
      `resource` - resource to add.
      `dimToAdd` - the dimensions to append. The grid extent size must be 1 cell in all dimensions.
    Throws:
      `IllegalGridGeometryException` - if the compound CRS or compound extent cannot be created.
      `DataStoreException` - if the resource cannot be used.
    Since:
      1.5

  - ### add

    public void add(GridCoverageResource resource, double lower, double span, SingleCRS crs) throws DataStoreException
    Adds the given resource augmented with a single grid dimension. The additional dimension is typically a vertical axis to add to a two-dimensional resource.
    Parameters:
      `resource` - resource to add.
      `lower` - lower coordinate value of the slice, in units of the CRS.
      `span` - size of the slice, in units of the CRS.
      `crs` - one-dimensional coordinate reference system of the slice, or `null` if unknown.
    Throws:
      `IllegalGridGeometryException` - if the compound CRS or compound extent cannot be created.
      `DataStoreException` - if the resource cannot be used.
    Since:
      1.5

  - ### add

    public void add(GridCoverageResource resource, Instant lower, Duration span) throws DataStoreException
    Adds the given resource augmented with a single temporal grid dimension. This method is provided for convenience, but should be used carefully. Slice coordinates computed from calendars tend to produce slices at irregular intervals or with heterogeneous spans, which result in coverages that cannot be aggregated by this `CoverageAggregator` class.
    Parameters:
      `resource` - resource to add.
      `lower` - start time of the slice.
      `span` - duration of the slice.
    Throws:
      `IllegalGridGeometryException` - if the compound CRS or compound extent cannot be created.
      `DataStoreException` - if the resource cannot be used.
    Since:
      1.5

  - ### addComponents

    public void addComponents(Aggregate resource) throws DataStoreException
    Adds all components of the given aggregate. This method can be invoked from any thread. It delegates to `add(GridCoverageResource)` for each component in the aggregate which is an instance of `GridCoverageResource`. Components that are themselves instance of `Aggregate` are decomposed recursively.
    Parameters:
      `resource` - resource to add.
    Throws:
      `DataStoreException` - if a component of the resource cannot be used.
    "TODO:"
      Instead of ignoring non-coverage instances, we should put them in a separated aggregate.

  - ### addAll

    public void addAll(Stream<? extends GridCoverageResource> resources) throws DataStoreException
    Adds all grid resources provided by the given stream. This method can be invoked from any thread. It delegates to `add(GridCoverageResource)` for each element in the stream. `Aggregate` instances are added as-is (not decomposed in their components).
    Parameters:
      `resources` - resources to add.
    Throws:
      `DataStoreException` - if a resource cannot be used.
    See Also:
      - `add(GridCoverageResource)`

  - ### addRangeAggregate

    public void addRangeAggregate(GridCoverageResource... sources) throws DataStoreException
    Adds a resource whose range is the aggregation of the ranges of a sequence of resources. This method combines homogeneous grid coverage resources by "stacking" their sample dimensions (bands). The grid geometry is typically the same for all resources, but some variations described below are allowed. The number of sample dimensions in the aggregated coverage is the sum of the number of sample dimensions in each individual resource.

    This convenience method delegates to `addRangeAggregate(GridCoverageResource[], int[][])`. See that method for more information on restrictions.

    Parameters:
      `sources` - resources whose bands shall be aggregated, in order.
    Throws:
      `DataStoreException` - if an error occurred while fetching the grid geometry or sample dimensions from a resource.
      `IllegalGridGeometryException` - if a grid geometry is not compatible with the others.
    Since:
      1.4
    See Also:
      - `getColorizer()`
      - `GridCoverageProcessor​.aggregateRanges(GridCoverage...)`

  - ### addRangeAggregate

    public void addRangeAggregate(GridCoverageResource[] sources, int[][] bandsPerSource) throws DataStoreException
    Adds a resource whose range is the aggregation of the specified bands of a sequence of resources. This method performs the same work as `addRangeAggregate(GridCoverageResource...)`, but with the possibility to specify the sample dimensions to retain in each source coverage. The `bandsPerSource` argument specifies the sample dimensions to keep, in order. That array can be `null` for selecting all sample dimensions in all source coverages, or may contain `null` elements for selecting all sample dimensions of the corresponding coverage. An empty array element (i.e. zero sample dimension to select) discards the corresponding source coverage.

    #### Restrictions

    - All resources shall use the same coordinate reference system (CRS).
    - All resources shall have the same domain, except for the grid extent and the translation terms which can vary by integer numbers of grid cells.
    - All grid extents shall intersect and the intersection area shall be non-empty.
    - If coverage data are stored in `RenderedImage` instances, then all images shall use the same data type.
    Some of those restrictions may be relaxed in future Apache SIS versions.
    Parameters:
      `sources` - resources whose bands shall be aggregated, in order.
      `bandsPerSource` - sample dimensions for each source. May be `null` or may contain `null` elements.
    Throws:
      `DataStoreException` - if an error occurred while fetching the grid geometry or sample dimensions from a resource.
      `IllegalGridGeometryException` - if a grid geometry is not compatible with the others.
      `IllegalArgumentException` - if some band indices are duplicated or outside their range of validity.
    Since:
      1.4
    See Also:
      - `getColorizer()`
      - `GridCoverageProcessor​.aggregateRanges(GridCoverage[], int[][])`

  - ### getColorizer

    public Colorizer getColorizer()
    Returns the colorization algorithm to apply on computed images. This algorithm is used for all resources added by `addRangeAggregate(GridCoverageResource[], int[][])`,
    Returns:
      colorization algorithm to apply on computed image, or `null` for default.
    Since:
      1.4

  - ### setColorizer

    public void setColorizer(Colorizer colorizer)
    Sets the colorization algorithm to apply on computed images. This algorithm applies to all resources added by `addRangeAggregate(GridCoverageResource[], int[][])`, including resources already added before this method is invoked. If this method is never invoked, the default value is `null`.
    Parameters:
      `colorizer` - colorization algorithm to apply on computed image, or `null` for default.
    Since:
      1.4

  - ### getMergeStrategy

    public MergeStrategy getMergeStrategy()
    Returns the algorithm to apply when more than one grid coverage can be found at the same grid index. This is the most recent value set by a call to `setMergeStrategy(MergeStrategy)`, or `null` if no strategy has been specified. In the latter case, `SubspaceNotSpecifiedException` will be thrown in situations of ambiguity. An ambiguity happens at `GridCoverage​.render(GridExtent)` invocation time if more than one source coverage (slice) is found for a specified grid index.
    Returns:
      algorithm to apply for merging source coverages at the same grid index, or `null` if none.

  - ### setMergeStrategy

    public void setMergeStrategy(MergeStrategy strategy)
    Sets the algorithm to apply when more than one grid coverage can be found at the same grid index. The new strategy applies to the next coverages to be added; previously added coverage may or may not be impacted by this change (see below). For avoiding hard-to-predict behavior, this method should be invoked before to add the first coverage.

    #### Effect on previously added coverages

    The merge strategy of previously added coverages is not modified by this method call, except for coverages (slices) that become part of the same aggregated `GridCoverageResource` (data cube) than a coverage added after this method call. In such case, the strategy set by this call to `setMergeStrategy(…)` prevails. Said otherwise, the merge strategy of a data cube is the strategy which was active at the time of the most recently added slice for that data cube.
    Parameters:
      `strategy` - new algorithm to apply for merging source coverages at the same grid index, or `null` if none.

  - ### build

    public Resource build(GenericName identifier)
    Builds a resource which is the aggregation or concatenation of all components added to this aggregator. The returned resource will be an instance of `GridCoverageResource` if possible, or an instance of `Aggregate` if some heterogeneity in grid geometries or sample dimensions prevents the concatenation of all coverages in a single resource.

    An identifier can optionally be specified for the resource. This identifier will be used if this method creates an aggregated or concatenated resource, but it will be ignored if this method returns directly one of the resource specified to the `add(…)` methods.

    #### Multi-threading

    If the `add(…)` and `addAll(…)` methods were invoked in background threads, then all additions must be finished before this method is invoked.
    Parameters:
      `identifier` - identifier to assign to the aggregated resource, or `null` if none.
    Returns:
      the aggregation or concatenation of all components added to this aggregator.
    Since:
      1.4

  - ### toString

    public String toString()
    Returns a string representation for debugging purposes.
    Overrides:
      `toString` in class `Object`