This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 7538f73be1dc48aa3a0933fa92d9b6c1899699c1
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Feb 10 12:47:42 2021 +0100

    Apply `ErrorHandler` during sequential operations too, not only during 
parallel operations.
---
 .../java/org/apache/sis/image/ImageProcessor.java  |  6 ---
 .../sis/internal/coverage/j2d/TileOpExecutor.java  | 48 +++++++++-------------
 2 files changed, 20 insertions(+), 34 deletions(-)

diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java 
b/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java
index 146ba81..808a425 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/ImageProcessor.java
@@ -867,12 +867,6 @@ public class ImageProcessor implements Cloneable {
      *   <li>{@linkplain #getErrorHandler() Error handler} (whether to fail if 
an exception is thrown).</li>
      * </ul>
      *
-     * <h4>Limitation</h4>
-     * Current implementation ignores the {@linkplain #getErrorHandler() error 
handler} in sequential execution
-     * (i.e. error handler is used only during parallel execution). In 
addition, there is not yet a mechanism
-     * for specifying which tile to produce in replacement of tiles that can 
not be computed.
-     * Those limitations may be addressed in a future version.
-     *
      * @param  source          the image to compute immediately (may be {@code 
null}).
      * @param  areaOfInterest  pixel coordinates of the region to prefetch, or 
{@code null} for the whole image.
      * @return image with all tiles intersecting the AOI computed, or {@code 
null} if the given image was null.
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/TileOpExecutor.java
 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/TileOpExecutor.java
index 46e563d..7a7e27b 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/TileOpExecutor.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/TileOpExecutor.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.coverage.j2d;
 
+import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.util.stream.Collector;
 import java.util.function.BiConsumer;
@@ -198,9 +199,9 @@ public class TileOpExecutor {
      * Only tiles intersecting the area of interest will be processed.
      * For each tile, the {@link #readFrom(Raster)} method will be invoked in 
current thread.
      *
-     * <p>If a tile processing throws an exception, 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.</p>
+     * <p>If a tile processing throws an exception and the {@link 
#errorHandler} is {@link 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.</p>
      *
      * <p>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.</p>
@@ -212,17 +213,16 @@ public class TileOpExecutor {
      *         {@linkplain ImagingOpException#getCause() cause}.
      */
     public final void readFrom(final RenderedImage source) {
+        final ErrorHandler.Report errors = new ErrorHandler.Report();
         for (int ty = minTileY; ty <= maxTileY; ty++) {
             for (int tx = minTileX; tx <= maxTileX; tx++) try {
                 readFrom(source.getTile(tx, ty));
             } catch (Exception ex) {
-                Throwable e = trimImagingWrapper(ex);
-                if (!(e instanceof ImagingOpException)) {
-                    e = new 
ImagingOpException(Resources.format(Resources.Keys.CanNotProcessTile_2, tx, 
ty)).initCause(ex);
-                }
-                throw (ImagingOpException) e;
+                errors.add(new Point(tx, ty), trimImagingWrapper(ex), null);
+                if (errorHandler == TileErrorHandler.THROW) break;
             }
         }
+        errorHandler.publish(errors);
     }
 
     /**
@@ -232,9 +232,9 @@ public class TileOpExecutor {
      * For each tile, the {@link #writeTo(WritableRaster)} method will be 
invoked in current thread.
      *
      * <p>If a tile processing throws an exception, then this method continues 
processing other tiles
-     * and will throw the wrapper exception only after all tiles have been 
processed. This policy is
+     * 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 a relatively consistent state.</p>
+     * we want to have as much valid values as possible.</p>
      *
      * <p>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.</p>
@@ -246,7 +246,7 @@ public class TileOpExecutor {
      *         This exception wraps the original exception as its {@linkplain 
ImagingOpException#getCause() cause}.
      */
     public final void writeTo(final WritableRenderedImage target) {
-        ImagingOpException error = null;
+        final ErrorHandler.Report errors = new ErrorHandler.Report();
         for (int ty = minTileY; ty <= maxTileY; ty++) {
             for (int tx = minTileX; tx <= maxTileX; tx++) try {
                 final WritableRaster tile = target.getWritableTile(tx, ty);
@@ -256,20 +256,12 @@ public class TileOpExecutor {
                     target.releaseWritableTile(tx, ty);
                 }
             } catch (Exception ex) {
-                final Throwable e = trimImagingWrapper(ex);
-                if (error != null) {
-                    error.addSuppressed(e);
-                } else if (e instanceof ImagingOpException) {
-                    error = (ImagingOpException) e;
-                } else {
-                    error = new 
ImagingOpException(Resources.format(Resources.Keys.CanNotUpdateTile_2, tx, ty));
-                    error.initCause(e);
-                }
+                final Point tile = new Point(tx, ty);
+                errors.add(tile, trimImagingWrapper(ex), () -> 
Resources.forLocale(null)
+                            .getLogRecord(Level.WARNING, 
Resources.Keys.CanNotUpdateTile_2, tile.x, tile.y));
             }
         }
-        if (error != null) {
-            throw error;
-        }
+        errorHandler.publish(errors);
     }
 
     /**
@@ -280,9 +272,9 @@ public class TileOpExecutor {
      * in an arbitrary thread (may be the current one).
      *
      * <h4>Errors management</h4>
-     * If a tile processing throws an exception, then the other threads will 
finish computing
-     * their current tile but no other tiles will be fetched; remaining tiles 
are not processed.
-     * This policy is suited to the cases where the caller will not return any 
result in case of error.
+     * If a tile processing throws an exception and the {@link #errorHandler} 
is {@link 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.
      *
      * <h4>Concurrency requirements</h4>
      * Subclasses must override {@link #readFrom(Raster)} with a concurrent 
implementation.
@@ -318,9 +310,9 @@ public class TileOpExecutor {
      *
      * <h4>Errors management</h4>
      * If a tile processing throws an exception, then this method continues 
processing other tiles
-     * and will throw the wrapper exception only after all tiles have been 
processed. This policy is
+     * 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 a relatively consistent state.
+     * we want to have as much valid values as possible.
      *
      * <h4>Concurrency requirements</h4>
      * Subclasses must override {@link #writeTo(WritableRaster)} with a 
concurrent implementation.

Reply via email to