SLING-9258 : Provide features to consumer when reading feature archive
diff --git a/pom.xml b/pom.xml
index 6fa1ac4..21d2557 100644
--- a/pom.xml
+++ b/pom.xml
@@ -162,7 +162,7 @@
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>2.8.9</version>
+            <version>3.3.3</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/feature/io/archive/ArchiveReader.java b/src/main/java/org/apache/sling/feature/io/archive/ArchiveReader.java
index 6bbad77..af7b404 100644
--- a/src/main/java/org/apache/sling/feature/io/archive/ArchiveReader.java
+++ b/src/main/java/org/apache/sling/feature/io/archive/ArchiveReader.java
@@ -16,9 +16,14 @@
  */
 package org.apache.sling.feature.io.archive;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -60,9 +65,9 @@
      * caller to close the input stream.
      *
      * @param in       The input stream to read from.
-     * @param consumer The plugin consuming the binaries, if {@code null} only the
-     *                 feature models are read
-     * @return The feature models
+     * @param consumer The plugin consuming the binaries, including the features.
+     *                 If no consumer is provided, only the features will be returned.
+     * @return The feature models mentioned in the manifest of the archive
      * @throws IOException If anything goes wrong
      */
     public static Set<Feature> read(final InputStream in,
@@ -83,10 +88,35 @@
         JarEntry entry = null;
         while ( ( entry = jis.getNextJarEntry() ) != null ) {
             if (!entry.isDirectory() && !entry.getName().startsWith("META-INF/")) {
-                if (featurePaths.contains(entry.getName())) { // feature
-                    features.add(FeatureJSONReader.read(new InputStreamReader(jis, "UTF-8"), entry.getName()));
-                } else { // artifact
-                    final ArtifactId id = ArtifactId.fromMvnPath(entry.getName());
+                final ArtifactId id = ArtifactId.fromMvnPath(entry.getName());
+
+                if (featurePaths.contains(entry.getName())) {
+                    // feature - read to string first
+                    final String contents;
+                    try ( final StringWriter writer = new StringWriter()) {
+                        // don't close the input stream
+                        final Reader reader = new InputStreamReader(jis, "UTF-8");
+                        final char[] buffer = new char[2048];
+                        int l;
+                        while ( (l = reader.read(buffer)) > 0) {
+                            writer.write(buffer, 0, l);
+                        }
+                        writer.flush();
+                        contents = writer.toString();
+                    }
+                    // add to features
+                    try ( final Reader reader = new StringReader(contents) ) {
+                        final Feature feature = FeatureJSONReader.read(reader, entry.getName());
+                        features.add(feature);
+                    }
+                    // pass to consumer
+                    if ( consumer != null ) {
+                        try ( final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8))) {
+                            consumer.consume(id, is);
+                        }
+                    }
+                } else {
+                    // artifact
                     if (consumer != null) {
                         consumer.consume(id, jis);
                     }
diff --git a/src/test/java/org/apache/sling/feature/io/archive/ArchiveWriterTest.java b/src/test/java/org/apache/sling/feature/io/archive/ArchiveWriterTest.java
index cfd09f1..ee3fa71 100644
--- a/src/test/java/org/apache/sling/feature/io/archive/ArchiveWriterTest.java
+++ b/src/test/java/org/apache/sling/feature/io/archive/ArchiveWriterTest.java
@@ -26,6 +26,9 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -34,6 +37,7 @@
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.junit.Test;
 
 public class ArchiveWriterTest {
@@ -65,16 +69,33 @@
         }
 
         final Set<ArtifactId> readIds = new HashSet<>();
+        final Set<ArtifactId> readFeatureIds = new HashSet<>();
+
         final List<Feature> features = new ArrayList<>();
         try (final InputStream in = new ByteArrayInputStream(archive)) {
             features.addAll(ArchiveReader.read(in, (id, is) -> {
-                readIds.add(id);
+
+                // read contents
                 byte[] read = readFromStream(is);
-                assertEquals(artifactBytes.length, read.length);
-                assertArrayEquals(artifactBytes, read);
+
+                // is feature?
+                if ( id.equals(f.getId()) ) {
+                    try ( final Reader reader = new StringReader(new String(read, StandardCharsets.UTF_8))) {
+                        final Feature readFeature = FeatureJSONReader.read(reader, id.toString());
+                        assertEquals(f.getId(), readFeature.getId());
+                        readFeatureIds.add(f.getId());
+                    }
+                } else {
+                    readIds.add(id);
+                    assertEquals(artifactBytes.length, read.length);
+                    assertArrayEquals(artifactBytes, read);
+                }
             }));
         }
 
+        assertEquals(1, readFeatureIds.size());
+        assertTrue(readFeatureIds.contains(f.getId()));
+
         assertEquals(1, readIds.size());
         assertTrue(readIds.contains(ArtifactId.parse("g:a:2")));