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

Claudenw pushed a commit to branch create-IODescriptor
in repository https://gitbox.apache.org/repos/asf/creadur-rat.git

commit 0c7c791e40665137ddd16a073b034536a28b42da
Author: Claude Warren <[email protected]>
AuthorDate: Thu Jul 2 17:26:35 2026 +0100

    Creat IODescriptor to provide better context for input/output reporting.
    
    Update ReportConfiguration to use IODescriptor for output and stylesheet 
parameters.
    Update associated classes to utilize IODescriptor.
    Update tests to account for IODescriptor.
    Update UI generation for IODescriptor
---
 .../java/org/apache/rat/ReportConfiguration.java   | 77 ++++++++++++++++++----
 .../main/java/org/apache/rat/commandline/Arg.java  |  3 +-
 .../org/apache/rat/commandline/StyleSheets.java    | 16 +++--
 .../org/apache/rat/ReportConfigurationTest.java    |  6 +-
 .../org/apache/rat/ReporterOptionsProvider.java    |  2 +-
 .../src/test/java/org/apache/rat/ReporterTest.java |  8 +--
 .../test/AbstractConfigurationOptionsProvider.java |  4 +-
 .../main/java/org/apache/rat/mp/RatCheckMojo.java  |  2 +-
 .../main/java/org/apache/rat/mp/RatReportMojo.java |  2 +-
 .../main/java/org/apache/rat/anttasks/Report.java  |  4 +-
 .../org/apache/rat/tools/xsd/XsdGenerator.java     |  2 +-
 11 files changed, 91 insertions(+), 35 deletions(-)

diff --git 
a/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java 
b/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java
index 799dfaf5..bb0b405e 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java
@@ -20,6 +20,7 @@ package org.apache.rat;
 
 import java.io.File;
 import java.io.FileFilter;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -68,6 +69,10 @@ import org.apache.rat.walker.IReportableListWalker;
  */
 public class ReportConfiguration {
 
+    /** The IODescriptor for system.out */
+    public static final IODescriptor<OutputStream> SYSTEM_OUT =
+            // SONAR wants to require logging output, which is the wrong 
reporting channel for this case.
+            new IODescriptor<>("System.out", () -> 
CloseShieldOutputStream.wrap(System.out)); // NOSONAR
     /**
      * The styles of processing for various categories of documents.
      */
@@ -115,13 +120,13 @@ public class ReportConfiguration {
      */
     private String copyrightMessage;
     /**
-     * The IOSupplier that provides the output stream to write the report to.
+     * The IODescriptor that provides the output stream to write the report to.
      */
-    private IOSupplier<OutputStream> out;
+    private IODescriptor<OutputStream> out;
     /**
-     * The IOSupplier that provides the stylesheet to style the XML output.
+     * The IODescriptor that provides the stylesheet to style the XML output.
      */
-    private IOSupplier<InputStream> styleSheet;
+    private IODescriptor<InputStream> styleSheet;
 
     /**
      * A list of files to read file names from.
@@ -441,16 +446,25 @@ public class ReportConfiguration {
      * the report with.
      */
     public IOSupplier<InputStream> getStyleSheet() {
+        return styleSheet == null ? null : styleSheet.ioSupplier();
+    }
+
+    /**
+     * Gets the IODescriptor with the style sheet.
+     * @return the IODescriptor that describes the XSLT style sheet to style
+     * the report with.
+     */
+    public IODescriptor<InputStream> getStyleSheetDescriptor() {
         return styleSheet;
     }
 
     /**
-     * Sets the style sheet for custom processing. The IOSupplier may be called
+     * Sets the style sheet for custom processing. The IODescriptor may be 
called
      * multiple times, so the input stream must be able to be opened and closed
      * multiple times.
      * @param styleSheet the XSLT style sheet to style the report with.
      */
-    public void setStyleSheet(final IOSupplier<InputStream> styleSheet) {
+    public void setStyleSheet(final IODescriptor<InputStream> styleSheet) {
         this.styleSheet = styleSheet;
     }
 
@@ -498,7 +512,7 @@ public class ReportConfiguration {
      */
     public void setStyleSheet(final URL styleSheet) {
         Objects.requireNonNull(styleSheet, "Stylesheet file must not be null");
-        setStyleSheet(styleSheet::openStream);
+        setStyleSheet(new IODescriptor<>(styleSheet.toString(), 
styleSheet::openStream));
     }
 
     /**
@@ -510,7 +524,7 @@ public class ReportConfiguration {
      * the report to. A null value will use System.out.
      * @see CloseShieldOutputStream
      */
-    public void setOut(final IOSupplier<OutputStream> out) {
+    public void setOut(final IODescriptor<OutputStream> out) {
         this.out = out;
     }
 
@@ -518,7 +532,7 @@ public class ReportConfiguration {
      * Sets the OutputStream supplier to use the specified file. The file may 
be
      * opened and closed several times. File is deleted first and then may be
      * repeatedly opened in append mode.
-     * @see #setOut(IOSupplier)
+     * @see #setOut(IODescriptor)
      * @param file The file to create the supplier with.
      */
     public void setOut(final File file) {
@@ -534,7 +548,7 @@ public class ReportConfiguration {
         if (!parent.mkdirs() && !parent.isDirectory()) {
             DefaultLog.getInstance().warn("Unable to create directory: " + 
file.getParentFile());
         }
-        setOut(() -> new FileOutputStream(file, true));
+        setOut(IODescriptor.output(file));
     }
 
     /**
@@ -543,7 +557,16 @@ public class ReportConfiguration {
      * @return The supplier of the output stream to write the report to.
      */
     public IOSupplier<OutputStream> getOutput() {
-        return out == null ? () -> CloseShieldOutputStream.wrap(System.out) : 
out;
+        return getOutputDescriptor().ioSupplier();
+    }
+
+    /**
+     * Returns the output IODescriptor. If no stream has been set returns a
+     * descriptor for System.out.
+     * @return The IODescriptor of the output stream to write the report to.
+     */
+    public IODescriptor<OutputStream> getOutputDescriptor() {
+        return out == null ? SYSTEM_OUT : out;
     }
 
     /**
@@ -842,4 +865,36 @@ public class ReportConfiguration {
             throw new ConfigurationException(msg);
         }
     }
+
+    /**
+     * An IODescriptor comprises a name and an IOSupplier.  The name should 
identify the contents of the stream.
+     * @param name the name of the supplier.
+     * @param ioSupplier the IOSupplier that provides either an InputStream or 
an OutputStream
+     * @param <T> either InputStream or OutputStream.
+     */
+    public record IODescriptor<T>(String name, IOSupplier<T> ioSupplier) {
+
+        // OUTPUT CONSTRUCTORS
+
+        /**
+         * Creates an output IODescriptor for the file name within the working 
directory.
+         * @param name the name of the file to open.
+         * @param workingDirectory the working directory for the file.
+         * @return the Output IODescriptor.
+         */
+        static IODescriptor<OutputStream> output(final String name, final 
DocumentName workingDirectory) {
+            DocumentName docName = workingDirectory.resolve(name);
+            return new IODescriptor<>(name, () -> new 
FileOutputStream(docName.asFile()));
+        }
+
+        static IODescriptor<OutputStream> output(final File file) {
+            return new IODescriptor<>(file.toString(), () -> new 
FileOutputStream(file, true));
+        }
+
+        // INPUT CONSTRUCTORS
+
+        static IODescriptor<InputStream> input(final File file) {
+            return new IODescriptor<>(file.toString(), () -> new 
FileInputStream(file));
+        }
+    }
 }
diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java 
b/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java
index 314e9c27..d11e9056 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/Arg.java
@@ -38,7 +38,6 @@ import org.apache.commons.cli.OptionGroup;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.output.CloseShieldOutputStream;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.rat.ConfigurationException;
 import org.apache.rat.Defaults;
@@ -625,7 +624,7 @@ public enum Arg {
                 } catch (ParseException e) {
                     // we write to system out by default.
                     context.logParseException(e, selected, "System.out");
-                    context.getConfiguration().setOut(() -> 
CloseShieldOutputStream.wrap(System.out)); // NOSONAR
+                    
context.getConfiguration().setOut(ReportConfiguration.SYSTEM_OUT);
                 }
             }),
 
diff --git 
a/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java 
b/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java
index c73a9e4e..aef47ded 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java
@@ -25,8 +25,8 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Objects;
 
-import org.apache.commons.io.function.IOSupplier;
 import org.apache.rat.ConfigurationException;
+import org.apache.rat.ReportConfiguration;
 
 import static java.lang.String.format;
 
@@ -73,9 +73,11 @@ public enum StyleSheets {
      * Gets the IOSupplier for a style sheet.
      * @return an IOSupplier for the sheet.
      */
-    public IOSupplier<InputStream> getStyleSheet() {
-        return 
Objects.requireNonNull(StyleSheets.class.getClassLoader().getResource(format("org/apache/rat/%s.xsl",
 name)),
-                "missing stylesheet: " + name)::openStream;
+    public ReportConfiguration.IODescriptor<InputStream> getStyleSheet() {
+        URL url = 
StyleSheets.class.getClassLoader().getResource(format("org/apache/rat/%s.xsl", 
name));
+        Objects.requireNonNull(url, "missing stylesheet: " + name);
+        return new ReportConfiguration.IODescriptor<>(name, url::openStream);
+
     }
 
     /**
@@ -83,14 +85,14 @@ public enum StyleSheets {
      * @param name the short name for or the path to a style sheet.
      * @return the IOSupplier for the style sheet.
      */
-    public static IOSupplier<InputStream> getStyleSheet(final String name) {
+    public static ReportConfiguration.IODescriptor<InputStream> 
getStyleSheet(final String name) {
         URL url = 
StyleSheets.class.getClassLoader().getResource(format("org/apache/rat/%s.xsl", 
name));
         if (url != null) {
-            return url::openStream;
+            return new ReportConfiguration.IODescriptor<>(name, 
url::openStream);
         }
         Path p = Paths.get(name);
         if (p.toFile().exists()) {
-            return () -> Files.newInputStream(p);
+            return new ReportConfiguration.IODescriptor<>(name, () -> 
Files.newInputStream(p));
         }
         throw new ConfigurationException(format("Stylesheet file '%s' not 
found", name));
     }
diff --git 
a/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java 
b/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java
index 69af88b2..3b8ddc65 100644
--- a/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java
+++ b/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java
@@ -456,7 +456,7 @@ public class ReportConfigurationTest {
         assertThat(underTest.getWriter()).isNotNull();
 
         ByteArrayOutputStream stream = new ByteArrayOutputStream();
-        underTest.setOut(() -> stream);
+        underTest.setOut(new ReportConfiguration.IODescriptor("outputTest", () 
-> stream));
         assertThat(underTest.getOutput().get()).isEqualTo(stream);
         PrintWriter writer = underTest.getWriter().get();
         assertThat(writer).isNotNull();
@@ -482,7 +482,7 @@ public class ReportConfigurationTest {
 
         assertThat(underTest.getStyleSheet()).isNull();
         InputStream stream = mock(InputStream.class);
-        underTest.setStyleSheet(() -> stream);
+        underTest.setStyleSheet(new 
ReportConfiguration.IODescriptor("stylesheetTest", () -> stream));
         assertThat(underTest.getStyleSheet().get()).isEqualTo(stream);
 
         File file = mock(File.class);
@@ -540,7 +540,7 @@ public class ReportConfigurationTest {
     public void testSetOut() throws IOException {
         ReportConfiguration config = new ReportConfiguration();
         try (OutputStreamInterceptor osi = new OutputStreamInterceptor()) {
-            config.setOut(() -> osi);
+            config.setOut(new ReportConfiguration.IODescriptor("testSetOut",() 
-> osi));
             assertThat(osi.closeCount).isEqualTo(0);
             try (OutputStream os = config.getOutput().get()) {
                 assertThat(os).isNotNull();
diff --git 
a/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java 
b/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java
index 0ef6f019..0ed214d5 100644
--- a/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java
+++ b/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java
@@ -939,7 +939,7 @@ class ReporterOptionsProvider extends 
AbstractOptionsProvider implements Argumen
             String actualText = baos.toString(StandardCharsets.UTF_8);
             TextUtils.assertContainsExactly(1, "<resource 
encoding=\"ISO-8859-1\" mediaType=\"text/plain\" name=\"/stylesheet\" 
type=\"STANDARD\">", actualText);
 
-            try (InputStream expected = StyleSheets.getStyleSheet("xml").get();
+            try (InputStream expected = 
StyleSheets.getStyleSheet("xml").ioSupplier().get();
                  InputStream actual = config.getStyleSheet().get()) {
                 assertThat(IOUtils.contentEquals(expected, actual)).as("'xml' 
does not match").isTrue();
             }
diff --git a/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java 
b/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java
index 3d9c84e7..0a62b157 100644
--- a/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java
+++ b/apache-rat-core/src/test/java/org/apache/rat/ReporterTest.java
@@ -409,7 +409,7 @@ public class ReporterTest {
 
         ReportConfiguration configuration = initializeConfiguration();
         configuration.setStyleSheet(StyleSheets.XML.getStyleSheet());
-        configuration.setOut(() -> out);
+        configuration.setOut(new 
ReportConfiguration.IODescriptor("xmlReportTest", () -> out));
         new Reporter(configuration).output();
         Document doc = XmlUtils.toDom(new 
ByteArrayInputStream(out.toByteArray()));
 
@@ -457,7 +457,7 @@ public class ReporterTest {
                 "Generated at: ";
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         ReportConfiguration configuration = initializeConfiguration();
-        configuration.setOut(() -> out);
+        configuration.setOut(new 
ReportConfiguration.IODescriptor("plainReportTest", () -> out));
         new Reporter(configuration).output();
 
         out.flush();
@@ -473,7 +473,7 @@ public class ReporterTest {
     public void unapprovedLicensesReportTest() throws Exception {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         ReportConfiguration configuration = initializeConfiguration();
-        configuration.setOut(() -> out);
+        configuration.setOut(new 
ReportConfiguration.IODescriptor("unapprovedLicensesReportTest", () -> out));
         
configuration.setStyleSheet(this.getClass().getResource("/org/apache/rat/unapproved-licenses.xsl"));
         new Reporter(configuration).output();
 
@@ -489,7 +489,7 @@ public class ReporterTest {
     void listLicensesReportTest() throws Exception {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         ReportConfiguration configuration = initializeConfiguration();
-        configuration.setOut(() -> out);
+        configuration.setOut(new 
ReportConfiguration.IODescriptor("listLicensesReportTest", () -> out));
         
configuration.setStyleSheet(StyleSheets.UNAPPROVED_LICENSES.getStyleSheet());
         Reporter.listLicenses(configuration, 
LicenseSetFactory.LicenseFilter.NONE);
 
diff --git 
a/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java
 
b/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java
index 5d34d80a..84e30dc5 100644
--- 
a/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java
+++ 
b/apache-rat-core/src/test/java/org/apache/rat/test/AbstractConfigurationOptionsProvider.java
@@ -818,7 +818,7 @@ public abstract class AbstractConfigurationOptionsProvider 
extends AbstractOptio
             for (String sheet : new String[]{"plain-rat", "missing-headers", 
"unapproved-licenses", file.getAbsolutePath()}) {
                 args[0] = sheet;
                 ReportConfiguration config = 
generateConfig(ImmutablePair.of(option, args));
-                try (InputStream expected = 
StyleSheets.getStyleSheet(sheet).get();
+                try (InputStream expected = 
StyleSheets.getStyleSheet(sheet).ioSupplier().get();
                      InputStream actual = config.getStyleSheet().get()) {
                     assertThat(IOUtils.contentEquals(expected, actual)).as(() 
-> String.format("'%s' does not match", sheet)).isTrue();
                 }
@@ -845,7 +845,7 @@ public abstract class AbstractConfigurationOptionsProvider 
extends AbstractOptio
     protected void xmlTest() {
         assertDoesNotThrow(() -> {
             ReportConfiguration config = 
generateConfig(ImmutablePair.of(Arg.OUTPUT_STYLE.find("xml"), null));
-            try (InputStream expected = StyleSheets.getStyleSheet("xml").get();
+            try (InputStream expected = 
StyleSheets.getStyleSheet("xml").ioSupplier().get();
                  InputStream actual = config.getStyleSheet().get()) {
                 assertThat(IOUtils.contentEquals(expected, actual)).as("'xml' 
does not match").isTrue();
             }
diff --git 
a/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatCheckMojo.java 
b/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatCheckMojo.java
index 7bd6b1da..5a55a061 100644
--- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatCheckMojo.java
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatCheckMojo.java
@@ -234,7 +234,7 @@ public class RatCheckMojo extends AbstractRatMojo {
                        
!config.getClaimValidator().isValid(ClaimStatistic.Counter.UNAPPROVED, 
statistics.getCounter(ClaimStatistic.Counter.UNAPPROVED))) {
                    try {
                        ByteArrayOutputStream baos = new 
ByteArrayOutputStream();
-                       
reporter.output(StyleSheets.UNAPPROVED_LICENSES.getStyleSheet(), () -> baos);
+                       
reporter.output(StyleSheets.UNAPPROVED_LICENSES.getStyleSheet().ioSupplier(), 
() -> baos);
                        getLog().warn(baos.toString(StandardCharsets.UTF_8));
                    } catch (RuntimeException rte) {
                        throw rte;
diff --git 
a/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatReportMojo.java 
b/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatReportMojo.java
index 330d3c5e..6415641b 100644
--- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatReportMojo.java
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/RatReportMojo.java
@@ -446,7 +446,7 @@ public class RatReportMojo extends AbstractRatMojo 
implements MavenMultiPageRepo
                     config.reportExclusions(logWriter);
                 }
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                config.setOut(() -> baos);
+                config.setOut(new ReportConfiguration.IODescriptor("RAT 
output", () -> baos));
                 Reporter reporter = new Reporter(config);
                 reporter.output();
                 if (verbose) {
diff --git a/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java 
b/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java
index a069084f..cd91a8ec 100644
--- a/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java
+++ b/apache-rat-tasks/src/main/java/org/apache/rat/anttasks/Report.java
@@ -416,7 +416,7 @@ public class Report extends BaseAntTask {
                     o -> DefaultLog.getInstance().warn("Help option not 
supported"),
                     true);
             if (getValues(Arg.OUTPUT_FILE).isEmpty()) {
-                configuration.setOut(() -> new LogOutputStream(this, 
Project.MSG_INFO));
+                configuration.setOut(new 
ReportConfiguration.IODescriptor<>("RAT output", () -> new 
LogOutputStream(this, Project.MSG_INFO)));
             }
             DocumentName name = 
DocumentName.builder(getProject().getBaseDir()).build();
             configuration.addSource(new ResourceCollectionContainer(name, 
configuration, nestedResources));
@@ -444,7 +444,7 @@ public class Report extends BaseAntTask {
     public void execute() {
         try {
             Reporter r = new Reporter(validate(getConfiguration()));
-            r.output(StyleSheets.PLAIN.getStyleSheet(), () -> 
CloseShieldOutputStream.wrap(System.out));
+            r.output(StyleSheets.PLAIN.getStyleSheet().ioSupplier(), () -> 
CloseShieldOutputStream.wrap(System.out));
             r.output();
         } catch (BuildException e) {
             throw e;
diff --git 
a/apache-rat-tools/src/main/java/org/apache/rat/tools/xsd/XsdGenerator.java 
b/apache-rat-tools/src/main/java/org/apache/rat/tools/xsd/XsdGenerator.java
index a3ceb01c..68437fed 100644
--- a/apache-rat-tools/src/main/java/org/apache/rat/tools/xsd/XsdGenerator.java
+++ b/apache-rat-tools/src/main/java/org/apache/rat/tools/xsd/XsdGenerator.java
@@ -71,7 +71,7 @@ public class XsdGenerator {
         XsdGenerator generator = new XsdGenerator();
 
         try (InputStream in = generator.getInputStream();
-             InputStream styleIn = StyleSheets.XML.getStyleSheet().get()) {
+             InputStream styleIn = 
StyleSheets.XML.getStyleSheet().ioSupplier().get()) {
             Transformer transformer = StandardXmlFactory.create(styleIn);
             transformer.transform(new StreamSource(in),
                     new StreamResult(new OutputStreamWriter(System.out, 
StandardCharsets.UTF_8)));

Reply via email to