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)));
