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

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git

commit 2ee3a773ce3baf1549ca55dabe1deda5d0fababb
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Sat Nov 9 11:01:32 2024 -0500

    Add support to MessageDigestInputStream for setting a
    consumer for
    ProxyInputStream.afterRead(int)
---
 src/changes/changes.xml                            |  1 +
 .../commons/io/input/MessageDigestInputStream.java | 35 ++++++++++++---------
 .../io/input/MessageDigestInputStreamTest.java     | 36 +++++++++++++++++++++-
 3 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a8c8b926f..a68ce5623 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -73,6 +73,7 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add support to ThrottledInputStream for setting a consumer for 
ProxyInputStream.afterRead(int).</action>
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add support to ObservableInputStream for setting a consumer for 
ProxyInputStream.afterRead(int).</action>
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add support to MessageDigestCalculatingInputStream for setting a 
consumer for ProxyInputStream.afterRead(int).</action>
+      <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add support to MessageDigestInputStream for setting a consumer for 
ProxyInputStream.afterRead(int).</action>
       <!-- UPDATE -->
       <action dev="ggregory" type="update"             due-to="Gary 
Gregory">Bump org.apache.commons:commons-parent from 74 to 78 #670, #676, #679, 
#688.</action>
       <action dev="ggregory" type="update"             due-to="Gary 
Gregory">Bump commons.bytebuddy.version from 1.15.1 to 1.15.10 #672, #673, 
#685, #686, #694, #696, #698.</action>
diff --git 
a/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java 
b/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java
index 01b03996f..b3a0082fd 100644
--- a/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java
+++ b/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java
@@ -20,10 +20,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
 import java.util.Objects;
 
-import org.apache.commons.io.build.AbstractStreamBuilder;
-
 /**
  * This class is an example for using an {@link ObservableInputStream}. It 
creates its own {@link 
org.apache.commons.io.input.ObservableInputStream.Observer},
  * which calculates a checksum using a {@link MessageDigest}, for example, a 
SHA-512 sum.
@@ -62,12 +61,18 @@ public final class MessageDigestInputStream extends 
ObservableInputStream {
      * <p>
      * You must specify a message digest algorithm name or instance.
      * </p>
+     * <p>
+     * <em>The MD5 cryptographic algorithm is weak and should not be used.</em>
+     * </p>
      *
      * @see #get()
      */
     // @formatter:on
-    public static class Builder extends 
AbstractStreamBuilder<MessageDigestInputStream, Builder> {
+    public static class Builder extends AbstractBuilder<Builder> {
 
+        /**
+         * No default by design, call MUST set one.
+         */
         private MessageDigest messageDigest;
 
         /**
@@ -97,16 +102,16 @@ public final class MessageDigestInputStream extends 
ObservableInputStream {
          * @throws IOException                   if an I/O error occurs.
          * @see #getInputStream()
          */
-        @SuppressWarnings("resource")
         @Override
         public MessageDigestInputStream get() throws IOException {
-            return new MessageDigestInputStream(getInputStream(), 
messageDigest);
+            setObservers(Arrays.asList(new 
MessageDigestMaintainingObserver(messageDigest)));
+            return new MessageDigestInputStream(this);
         }
 
         /**
          * Sets the message digest.
          * <p>
-         * The MD5 cryptographic algorithm is weak and should not be used.
+         * <em>The MD5 cryptographic algorithm is weak and should not be 
used.</em>
          * </p>
          *
          * @param messageDigest the message digest.
@@ -120,7 +125,7 @@ public final class MessageDigestInputStream extends 
ObservableInputStream {
         /**
          * Sets the name of the name of the message digest algorithm.
          * <p>
-         * The MD5 cryptographic algorithm is weak and should not be used.
+         * <em>The MD5 cryptographic algorithm is weak and should not be 
used.</em>
          * </p>
          *
          * @param algorithm the name of the algorithm. See the MessageDigest 
section in the
@@ -173,6 +178,9 @@ public final class MessageDigestInputStream extends 
ObservableInputStream {
         return new Builder();
     }
 
+    /**
+     * A non-null MessageDigest.
+     */
     private final MessageDigest messageDigest;
 
     /**
@@ -181,23 +189,22 @@ public final class MessageDigestInputStream extends 
ObservableInputStream {
      * The MD5 cryptographic algorithm is weak and should not be used.
      * </p>
      *
-     * @param inputStream   the stream to calculate the message digest for
-     * @param messageDigest the message digest to use
+     * @param builder A builder use to get the stream to calculate the message 
digest and the message digest to use
      * @throws NullPointerException if messageDigest is null.
      */
-    private MessageDigestInputStream(final InputStream inputStream, final 
MessageDigest messageDigest) {
-        super(inputStream, new 
MessageDigestMaintainingObserver(messageDigest));
-        this.messageDigest = messageDigest;
+    private MessageDigestInputStream(final Builder builder) throws IOException 
{
+        super(builder);
+        this.messageDigest = Objects.requireNonNull(builder.messageDigest, 
"builder.messageDigest");
     }
 
     /**
-     * Gets the {@link MessageDigest}, which is being used for generating the 
checksum.
+     * Gets the {@link MessageDigest}, which is being used for generating the 
checksum, never null.
      * <p>
      * <em>Note</em>: The checksum will only reflect the data, which has been 
read so far. This is probably not, what you expect. Make sure, that the complete
      * data has been read, if that is what you want. The easiest way to do so 
is by invoking {@link #consume()}.
      * </p>
      *
-     * @return the message digest used
+     * @return the message digest used, never null.
      */
     public MessageDigest getMessageDigest() {
         return messageDigest;
diff --git 
a/src/test/java/org/apache/commons/io/input/MessageDigestInputStreamTest.java 
b/src/test/java/org/apache/commons/io/input/MessageDigestInputStreamTest.java
index 8f7208e08..94ca431a6 100644
--- 
a/src/test/java/org/apache/commons/io/input/MessageDigestInputStreamTest.java
+++ 
b/src/test/java/org/apache/commons/io/input/MessageDigestInputStreamTest.java
@@ -20,6 +20,7 @@ import static 
org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.ByteArrayInputStream;
@@ -30,10 +31,13 @@ import java.nio.file.Paths;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.codec.digest.MessageDigestAlgorithms;
+import org.apache.commons.io.IOExceptionList;
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.test.CustomIOException;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -61,6 +65,34 @@ public class MessageDigestInputStreamTest {
         // @formatter:on
     }
 
+    @Test
+    public void testAfterReadConsumer() throws Exception {
+        final AtomicBoolean boolRef = new AtomicBoolean();
+        // @formatter:off
+        try (InputStream bounded = MessageDigestInputStream.builder()
+                
.setMessageDigest(MessageDigest.getInstance(MessageDigestAlgorithms.SHA_512))
+                .setCharSequence("Hi")
+                .setAfterRead(i -> boolRef.set(true))
+                .get()) {
+            IOUtils.consume(bounded);
+        }
+        // @formatter:on
+        assertTrue(boolRef.get());
+        // Throwing
+        final String message = "test exception message";
+        // @formatter:off
+        try (InputStream bounded = MessageDigestInputStream.builder()
+                
.setMessageDigest(MessageDigest.getInstance(MessageDigestAlgorithms.SHA_512))
+                .setCharSequence("Hi")
+                .setAfterRead(i -> {
+                    throw new CustomIOException(message);
+                })
+                .get()) {
+            assertTrue(assertThrowsExactly(IOExceptionList.class, () -> 
IOUtils.consume(bounded)).getMessage().contains(message));
+        }
+        // @formatter:on
+    }
+
     @SuppressWarnings("resource")
     @Test
     public void testAvailableAfterClose() throws Exception {
@@ -83,7 +115,9 @@ public class MessageDigestInputStreamTest {
 
     @Test
     public void testNoDefault() throws Exception {
-        assertThrows(IllegalStateException.class, () -> 
MessageDigestInputStream.builder().get());
+        // No default by design, call MUST set a message digest
+        // Fail-fast, no need to try to process any input origin
+        assertThrows(NullPointerException.class, () -> 
MessageDigestInputStream.builder().get());
         assertThrows(NullPointerException.class, () -> 
MessageDigestInputStream.builder().setInputStream(new ByteArrayInputStream(new 
byte[] { 1 })).get());
     }
 

Reply via email to