Class TileOpExecutor

java.lang.Object
org.apache.sis.internal.coverage.j2d.TileOpExecutor
Direct Known Subclasses:
PrefetchedImage.Worker

public class TileOpExecutor extends Object
A read or write action to execute on each tile of an image. The operation may be executed in a single thread or can be multi-threaded (each tile processed fully in a single thread). If the operation is to be executed in a single thread, or if the subclass is concurrent (it usually means that it does not hold any mutable state), then subclasses can override and invoke the methods in one of the following rows:
Methods to use in single-thread or with concurrent implementations
Override Then invoke (single thread) Or invoke (multi-thread)
readFrom(Raster) readFrom(RenderedImage) parallelReadFrom(RenderedImage)
writeTo(WritableRaster) writeTo(WritableRenderedImage) parallelWriteTo(WritableRenderedImage)

If the operation should be multi-threaded and produce a result, then invoke executeOnReadable(…) or executeOnWritable(…) method. Those methods are inspired from Stream.collect(Collector) API.

Since:
1.1
Version:
1.2
  • Field Details

    • minTileX

      private final int minTileX
      Minimum/maximum index of tiles to process, inclusive.
      See Also:
    • minTileY

      private final int minTileY
      Minimum/maximum index of tiles to process, inclusive.
      See Also:
    • maxTileX

      private final int maxTileX
      Minimum/maximum index of tiles to process, inclusive.
      See Also:
    • maxTileY

      private final int maxTileY
      Minimum/maximum index of tiles to process, inclusive.
      See Also:
    • areaOfInterest

      private Shape areaOfInterest
      If the processing should be restricted to a non-rectangular shape, the region in pixel coordinates. Otherwise null. This shape should not be a rectangle because otherwise it would be redundant with minimum/maximum tile X/Y fields.
    • errorHandler

      private TileErrorHandler errorHandler
      Where to report exceptions, or TileErrorHandler.THROW for throwing them. If at least one error occurred, then this handler will receive the TileOpExecutor.Cursor.errors report after all computation finished.
      See Also:
  • Constructor Details

    • TileOpExecutor

      public TileOpExecutor(RenderedImage image, Rectangle aoi)
      Creates a new operation for tiles in the specified region of the specified image. It is caller responsibility to ensure that aoi is contained inside image bounds (caller can invoke ImageUtilities.clipBounds(RenderedImage, Rectangle) if needed).
      Parameters:
      image - the image from which tiles will be fetched.
      aoi - region of interest, or null for the whole image.
      Throws:
      ArithmeticException - if some tile indices are too large.
  • Method Details

    • setAreaOfInterest

      public final void setAreaOfInterest(RenderedImage image, Shape aoi)
      Sets the area of interest as an irregular shape. This executor will skip calculations in all tiles that do not intersect the given AOI. There is no benefit if this AOI is the same than the rectangle given to the constructor. But if the AOI is non-rectangular, then specifying it may help to skip a few more tiles. Skipping tiles saves not only TileOpExecutor computation time, but can save also computation time of source image if the source is itself the result of another computation.
      Parameters:
      image - the image for which to set an AOI, or null if unknown.
      aoi - the non-rectangular AOI, or null if none.
      Since:
      1.2
    • setErrorHandler

      public final void setErrorHandler(ErrorHandler handler, Class<?> sourceClass, String sourceMethod)
      Sets the handler where to report exceptions. The exception can be obtained by LogRecord.getThrown() on the value returned by ErrorHandler.Report.getDescription().

      Limitation

      In current implementation this is used only during parallel computation. A future version may need to use it for sequential computations as well for consistency.
      Parameters:
      handler - where to report exceptions, or ErrorHandler.THROW for throwing them.
      sourceClass - class to declare in LogRecord, or null if none.
      sourceMethod - method to declare in LogRecord, or null if none.
    • isMultiTiled

      public final boolean isMultiTiled()
      Returns true if the region of interest covers at least two tiles. Returns false if the region of interest covers a single tile or no tile at all.
      Returns:
      whether the operation will be executed on two tiles or more.
    • getTileIndices

      public final Rectangle getTileIndices()
      Returns the range of indices of tiles to be processed by this TileOpExecutor.
      Returns:
      range of tile indices to be processed.
    • readFrom

      protected void readFrom(Raster source) throws Exception
      Executes the read operation on the given tile. The default implementation does nothing. This method should be overridden if the user intends to call readFrom(RenderedImage) for execution in a single thread, or parallelReadFrom(RenderedImage) for multi-threaded execution. In the single thread case, it is okay for this method to modify some mutable states in the subclass. In the multi-thread case, the subclass implementation shall be immutable or concurrent.
      Parameters:
      source - the tile to read.
      Throws:
      Exception - if an error occurred while processing the tile.
    • writeTo

      protected void writeTo(WritableRaster target) throws Exception
      Executes the write operation on the given tile. The default implementation does nothing. This method should be overridden if the user intends to call writeTo(WritableRenderedImage) for execution in a single thread, or parallelWriteTo(WritableRenderedImage) for multi-threaded execution. In the single thread case, it is okay for this method to modify some mutable states in the subclass. In the multi-thread case, the subclass implementation shall be immutable or concurrent.
      Parameters:
      target - the tile where to write.
      Throws:
      Exception - if an error occurred while computing the values to write.
    • readFrom

      public final void readFrom(RenderedImage source)
      Executes the read action sequentially on tiles of the specified source image. The given source should be the same than the image specified at construction time. Only tiles intersecting the area of interest will be processed. For each tile, the readFrom(Raster) method will be invoked in current thread.

      If a tile processing throws an exception and the errorHandler is TileErrorHandler.THROW, then this method stops immediately; remaining tiles are not processed. This policy is suited to the cases where the caller will not return any result in case of error.

      This method does not parallelize tile operations, because it is invoked in contexts where it should apply on exactly one tile most of the times.

      Parameters:
      source - the image to read. This is usually the image specified at construction time, but other images are okay if they share the same pixel and tile coordinate systems.
      Throws:
      ImagingOpException - if an exception occurred during RenderedImage.getTile(int, int) or readFrom(Raster) execution. This exception wraps the original exception as its cause.
    • writeTo

      public final void writeTo(WritableRenderedImage target)
      Executes the write action sequentially on tiles of the specified target image. The given target should be the same than the image specified at construction time. Only tiles intersecting the area of interest will be processed. For each tile, the writeTo(WritableRaster) method will be invoked in current thread.

      If a tile processing throws an exception, then this method continues processing other tiles and will log or throw the exception only after all tiles have been processed. This policy is suited to the cases where the target image will continue to exist after this method call and we want to have as much valid values as possible.

      This method does not parallelize tile operations, because it is invoked in contexts where it should apply on exactly one tile most of the times.

      Parameters:
      target - the image where to write. This is usually the image specified at construction time, but other images are okay if they share the same pixel and tile coordinate systems.
      Throws:
      ImagingOpException - if an exception occurred during WritableRenderedImage.getWritableTile(int, int), writeTo(WritableRaster) or WritableRenderedImage.releaseWritableTile(int, int) execution. This exception wraps the original exception as its cause.
    • parallelReadFrom

      public final void parallelReadFrom(RenderedImage source)
      Executes the read action in parallel on tiles of the specified source image. The given source should be the same than the image specified at construction time. Only tiles intersecting the area of interest will be processed. For each tile, the readFrom(Raster) method will be invoked in an arbitrary thread (may be the current one).

      Errors management

      If a tile processing throws an exception and the errorHandler is TileErrorHandler.THROW, then this method stops immediately; remaining tiles are not processed. This policy is suited to the cases where the caller will not return any result in case of error.

      Concurrency requirements

      Subclasses must override readFrom(Raster) with a concurrent implementation. The RenderedImage.getTile(int, int) implementation of the given image must also support concurrency.
      Parameters:
      source - the image to read. This is usually the image specified at construction time, but other images are okay if they share the same pixel and tile coordinate systems.
      Throws:
      ImagingOpException - if an exception occurred during RenderedImage.getTile(int, int) or readFrom(Raster) execution. This exception wraps the original exception as its cause.
    • parallelWriteTo

      public final void parallelWriteTo(WritableRenderedImage target)
      Executes the write action in parallel on tiles of the specified target image. The given target should be the same than the image specified at construction time. Only tiles intersecting the area of interest will be processed. For each tile, the writeTo(WritableRaster) method will be invoked in an arbitrary thread (may be the current one).

      Errors management

      If a tile processing throws an exception, then this method continues processing other tiles and will log or throw the exception only after all tiles have been processed. This policy is suited to the cases where the target image will continue to exist after this method call and we want to have as much valid values as possible.

      Concurrency requirements

      Subclasses must override writeTo(WritableRaster) with a concurrent implementation. The WritableRenderedImage.getWritableTile(int, int) and WritableRenderedImage.releaseWritableTile(int, int) implementations of the given image must also support concurrency.
      Parameters:
      target - the image where to write. This is usually the image specified at construction time, but other images are okay if they share the same pixel and tile coordinate systems.
      Throws:
      ImagingOpException - if an exception occurred during WritableRenderedImage.getWritableTile(int, int), writeTo(WritableRaster) or WritableRenderedImage.releaseWritableTile(int, int) execution. This exception wraps the original exception as its cause.
    • executor

      private static <RT extends Raster> Collector<RT,Void,Void> executor(BiConsumer<Void,RT> action)
      Returns a collector to be used only as an executor: the accumulator is null and the combiner does nothing.
      Type Parameters:
      RT - either Raster or WritableRaster.
      Parameters:
      action - the action to execute on each tile.
      Returns:
      a collector which will merely act as an executor for the given action.
    • executeOnReadable

      public final <A, R> R executeOnReadable(RenderedImage source, Collector<? super Raster,A,R> collector)
      Executes a specified read action in parallel on all tiles of the specified image. The action is specified by 3 or 4 properties of the given collector:
      • Collector.supplier() creates a new instance of type A for each thread (those instances may be null if such objects are not needed). That object does not need to be thread-safe since each instance will be used by only one thread. Note however that the thread may use that object for processing any number of Raster tiles, including zero.
      • Collector.accumulator() provides the consumer to execute on each tile. That consumer will receive two arguments: the above-cited supplied instance of A (unique to each thread, may be null), and the Raster instance to process. That consumer returns no value; instead the supplied instance of A should be modified in-place if desired.
      • Collector.combiner() provides a function which, given two instances of A computed by two different threads, combines them in a single instance of A. This combiner will be invoked after a thread finished to process all its Raster tiles, and only if the two objects to combine are not null. This combiner does not need to be thread-safe.
      • Collector.finisher() is invoked exactly once in current thread after the processing of all tiles have been completed in all threads. This function converts the final value of A into the type R to be returned. It is often an identity function.

      Errors management

      If an error occurred during the processing of a tile, then there is a choice depending on the value given to setErrorHandler(…):
      • If ErrorHandler.THROW, then all threads will finish the tiles they were processing at the time the error occurred, but will not take any other tile (i.e. remaining tiles will be left unprocessed). The exception that occurred is wrapped in an ImagingOpException and thrown.
      • If ErrorHandler.LOG, then the exception is wrapped in a LogRecord and the processing continues with other tiles. If more exceptions happen, those subsequent exceptions will be added to the first one with Throwable.addSuppressed(Throwable). After all tiles have been processed, the error handler will be invoked with that LogRecord.

      Concurrency requirements

      The RenderedImage.getTile(int, int) implementation of the given image must support concurrency.
      Type Parameters:
      A - the type of the thread-local object to be given to each thread.
      R - the type of the final result. This is often the same as A.
      Parameters:
      source - the image to read. This is usually the image specified at construction time, but other images are okay if they share the same pixel and tile coordinate systems.
      collector - the action to execute on each Raster, together with supplier and combiner of thread-local objects of type A. See above javadoc for more information.
      Returns:
      the final result computed by finisher (may be null).
      Throws:
      ImagingOpException - if an exception occurred during RenderedImage.getTile(int, int) or readFrom(Raster) execution, and the error handler is ErrorHandler.THROW.
      RuntimeException - if an exception occurred elsewhere (for example in the combiner or finisher).
    • executeOnWritable

      public final <A, R> R executeOnWritable(WritableRenderedImage target, Collector<? super WritableRaster,A,R> collector)
      Executes a specified write action in parallel on all tiles of the specified image. The action is specified by 3 or 4 properties of the given collector:
      • Collector.supplier() creates a new instance of type A for each thread (those instances may be null if such objects are not needed). That object does not need to be thread-safe since each instance will be used by only one thread. Note however that the thread may use that object for processing any number of WritableRaster tiles, including zero.
      • Collector.accumulator() provides the consumer to execute on each tile. That consumer will receive two arguments: the above-cited supplied instance of A (unique to each thread, may be null), and the WritableRaster instance to process. That consumer returns no value; instead the supplied instance of A should be modified in-place if desired.
      • Collector.combiner() provides a function which, given two instances of A computed by two different threads, combines them in a single instance of A. This combiner will be invoked after a thread finished to process all its WritableRaster tiles, and only if the two objects to combine are not null. This combiner does not need to be thread-safe.
      • Collector.finisher() is invoked exactly once in current thread after the processing of all tiles have been completed in all threads. This function converts the final value of A into the type R to be returned. It is often an identity function.

      Errors management

      If an error occurred during the processing of a tile, the exception is remembered and the processing continues with other tiles. If more exceptions happen, those subsequent exceptions will be added to the first one by Throwable.addSuppressed(Throwable). After all tiles have been processed, there is a choice depending on the value given to setErrorHandler(…):

      Concurrency requirements

      The WritableRenderedImage.getWritableTile(int, int) and WritableRenderedImage.releaseWritableTile(int, int) implementations of the given image must support concurrency.
      Type Parameters:
      A - the type of the thread-local object to be given to each thread.
      R - the type of the final result. This is often the same as A.
      Parameters:
      target - the image where to write. This is usually the image specified at construction time, but other images are okay if they share the same pixel and tile coordinate systems.
      collector - the action to execute on each WritableRaster, together with supplier and combiner of thread-local objects of type A. See above javadoc for more information.
      Returns:
      the final result computed by finisher. This is often null because the purpose of calling executeOnWritable(…) is more often to update existing tiles instead of to compute a value.
      Throws:
      ImagingOpException - if an exception occurred during WritableRenderedImage.getWritableTile(int, int), writeTo(WritableRaster) or WritableRenderedImage.releaseWritableTile(int, int) execution, and the error handler is ErrorHandler.THROW.
      RuntimeException - if an exception occurred elsewhere (for example in the combiner or finisher).
    • trimImagingWrapper

      private static Throwable trimImagingWrapper(Throwable ex)
      If the given exception is a wrapper providing no useful information, returns its non-null cause. Otherwise returns the given exception, possibly unwrapped.