This is an automated email from the ASF dual-hosted git repository. Claudenw pushed a commit to branch make-license-collections-unmodifiable in repository https://gitbox.apache.org/repos/asf/creadur-rat.git
commit 2b0a37897efecf3053fd432f56d9c20582bd267d Author: Claude Warren <[email protected]> AuthorDate: Sun Jun 28 09:03:21 2026 +0100 make LicenseSetFactory return unmodifiable licenses sets --- .../java/org/apache/rat/ReportConfiguration.java | 3 +- .../org/apache/rat/analysis/AnalyserFactory.java | 9 ++--- .../rat/analysis/DocumentHeaderAnalyser.java | 6 +-- .../org/apache/rat/analysis/HeaderCheckWorker.java | 8 ++-- .../org/apache/rat/license/LicenseSetFactory.java | 44 +++++++++++++++++++--- .../src/test/java/org/apache/rat/DefaultsTest.java | 3 +- .../apache/rat/analysis/HeaderCheckWorkerTest.java | 17 +++++++-- .../apache/rat/documentation/velocity/RatTool.java | 9 ++--- 8 files changed, 71 insertions(+), 28 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..43c26b0f 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 @@ -38,6 +38,7 @@ import java.util.Objects; import java.util.SortedSet; import java.util.function.Consumer; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; import org.apache.commons.io.function.IOSupplier; import org.apache.commons.io.output.CloseShieldOutputStream; import org.apache.rat.analysis.IHeaderMatcher; @@ -671,7 +672,7 @@ public class ReportConfiguration { * @param filter The LicenseFilter to filter the licenses by. * @return the Sorted set of approved license categories. */ - public SortedSet<ILicense> getLicenses(final LicenseFilter filter) { + public UnmodifiableSortedSet<ILicense> getLicenses(final LicenseFilter filter) { return licenseSetFactory.getLicenses(filter); } diff --git a/apache-rat-core/src/main/java/org/apache/rat/analysis/AnalyserFactory.java b/apache-rat-core/src/main/java/org/apache/rat/analysis/AnalyserFactory.java index f2eca190..14a7dc84 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/analysis/AnalyserFactory.java +++ b/apache-rat-core/src/main/java/org/apache/rat/analysis/AnalyserFactory.java @@ -18,10 +18,9 @@ */ package org.apache.rat.analysis; -import java.util.Collection; -import java.util.Set; import java.util.function.Predicate; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; import org.apache.rat.ConfigurationException; import org.apache.rat.Defaults; import org.apache.rat.ReportConfiguration; @@ -80,7 +79,7 @@ public final class AnalyserFactory { */ public static DocumentAnalyser createConfiguredAnalyser(final ReportConfiguration configuration) { LicenseSetFactory licenseSetFactory = configuration.getLicenseSetFactory(); - Set<ILicense> licenses = licenseSetFactory.getLicenses(LicenseSetFactory.LicenseFilter.ALL); + UnmodifiableSortedSet<ILicense> licenses = licenseSetFactory.getLicenses(LicenseSetFactory.LicenseFilter.ALL); if (licenses.isEmpty()) { throw new ConfigurationException("At least one license must be defined"); } @@ -98,7 +97,7 @@ public final class AnalyserFactory { private static final class DefaultAnalyser implements DocumentAnalyser { /** The licenses to analyze */ - private final Collection<ILicense> licenses; + private final UnmodifiableSortedSet<ILicense> licenses; /** the Report Configuration */ private final ReportConfiguration configuration; /** The matcher for generated files */ @@ -109,7 +108,7 @@ public final class AnalyserFactory { * @param config the ReportConfiguration * @param licenses The licenses to analyse */ - DefaultAnalyser(final ReportConfiguration config, final Collection<ILicense> licenses) { + DefaultAnalyser(final ReportConfiguration config, final UnmodifiableSortedSet<ILicense> licenses) { this.licenses = licenses; this.configuration = config; this.generatedMatcher = configuration.getGeneratedMatcher(); diff --git a/apache-rat-core/src/main/java/org/apache/rat/analysis/DocumentHeaderAnalyser.java b/apache-rat-core/src/main/java/org/apache/rat/analysis/DocumentHeaderAnalyser.java index cec174f6..3f99b7f8 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/analysis/DocumentHeaderAnalyser.java +++ b/apache-rat-core/src/main/java/org/apache/rat/analysis/DocumentHeaderAnalyser.java @@ -20,8 +20,8 @@ package org.apache.rat.analysis; import java.io.IOException; import java.io.Reader; -import java.util.Collection; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; import org.apache.rat.api.Document; import org.apache.rat.document.DocumentAnalyser; import org.apache.rat.license.ILicense; @@ -35,7 +35,7 @@ import static java.lang.String.format; class DocumentHeaderAnalyser implements DocumentAnalyser { /** The license to analyse */ - private final Collection<ILicense> licenses; + private final UnmodifiableSortedSet<ILicense> licenses; /** The matcher for generated headers */ private final IHeaderMatcher generatedMatcher; @@ -43,7 +43,7 @@ class DocumentHeaderAnalyser implements DocumentAnalyser { * Constructs the HeaderAnalyser for the specific license. * @param licenses The licenses to analyse */ - DocumentHeaderAnalyser(final IHeaderMatcher generatedMatcher, final Collection<ILicense> licenses) { + DocumentHeaderAnalyser(final IHeaderMatcher generatedMatcher, final UnmodifiableSortedSet<ILicense> licenses) { super(); this.generatedMatcher = generatedMatcher; this.licenses = licenses; diff --git a/apache-rat-core/src/main/java/org/apache/rat/analysis/HeaderCheckWorker.java b/apache-rat-core/src/main/java/org/apache/rat/analysis/HeaderCheckWorker.java index 30243bb0..122a5f51 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/analysis/HeaderCheckWorker.java +++ b/apache-rat-core/src/main/java/org/apache/rat/analysis/HeaderCheckWorker.java @@ -21,10 +21,10 @@ package org.apache.rat.analysis; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; -import java.util.Collection; import java.util.Locale; import java.util.Objects; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; import org.apache.rat.ConfigurationException; import org.apache.rat.analysis.matchers.FullTextMatcher; import org.apache.rat.api.Document; @@ -54,7 +54,7 @@ public final class HeaderCheckWorker { /** The BufferedReader used to read the lines */ private final BufferedReader reader; /** The licenses to check for match */ - private final Collection<ILicense> licenses; + private final UnmodifiableSortedSet<ILicense> licenses; /** The document being processed */ private final Document document; /** The matcher for generated headers */ @@ -108,7 +108,7 @@ public final class HeaderCheckWorker { * @param licenses The licenses to check against. Not null. * @param name The document that is being checked. Possibly null. */ - public HeaderCheckWorker(final IHeaderMatcher generatedMatcher, final Reader reader, final Collection<ILicense> licenses, final Document name) { + public HeaderCheckWorker(final IHeaderMatcher generatedMatcher, final Reader reader, final UnmodifiableSortedSet<ILicense> licenses, final Document name) { this(generatedMatcher, reader, DEFAULT_NUMBER_OF_RETAINED_HEADER_LINES, licenses, name); } @@ -123,7 +123,7 @@ public final class HeaderCheckWorker { * @param document The document that is being checked. Possibly null. */ public HeaderCheckWorker(final IHeaderMatcher generatedMatcher, final Reader reader, - final int numberOfRetainedHeaderLine, final Collection<ILicense> licenses, + final int numberOfRetainedHeaderLine, final UnmodifiableSortedSet<ILicense> licenses, final Document document) { Objects.requireNonNull(reader, "Reader may not be null"); Objects.requireNonNull(licenses, "Licenses may not be null"); diff --git a/apache-rat-core/src/main/java/org/apache/rat/license/LicenseSetFactory.java b/apache-rat-core/src/main/java/org/apache/rat/license/LicenseSetFactory.java index 6fe00db5..5474501f 100644 --- a/apache-rat-core/src/main/java/org/apache/rat/license/LicenseSetFactory.java +++ b/apache-rat-core/src/main/java/org/apache/rat/license/LicenseSetFactory.java @@ -20,13 +20,19 @@ package org.apache.rat.license; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; +import org.apache.rat.ConfigurationException; import org.apache.rat.analysis.IHeaderMatcher; import org.apache.rat.analysis.IHeaders; +import org.apache.rat.utils.DefaultLog; import org.apache.rat.utils.Log; import org.apache.rat.utils.ReportingSet; @@ -121,6 +127,31 @@ public class LicenseSetFactory { licenses.forEach(l -> families.addIfNotPresent(l.getLicenseFamily())); } + public void validate() { + Log log = DefaultLog.getInstance(); + + // verify license definitions exist + if (getLicenses(LicenseFilter.ALL).isEmpty()) { + String msg = "At least one license must be defined"; + log.error(msg); + throw new ConfigurationException(msg); + } + + // verify that all approved license families exist + Set<String> exists = getLicenseFamilies(LicenseFilter.ALL) + .stream().map(ILicenseFamily::getFamilyCategory).collect(Collectors.toSet()); + Set<String> approved = new HashSet<>(approvedLicenseCategories); + approved.removeIf(exists::contains); + approved.forEach(name -> log.warn(String.format("License category '%s' was approved but does not exist.", name))); + + // verify that all approved licenses exist + exists = getLicenses(LicenseFilter.ALL) + .stream().map(ILicense::getId).collect(Collectors.toSet()); + approved = new HashSet<>(approvedLicenseIds); + approved.removeIf(exists::contains); + approved.forEach(name -> log.warn(String.format("License '%s' was approved but does not exist.", name))); + } + public void add(final LicenseSetFactory other) { this.families.addAll(other.families); this.licenses.addAll(other.licenses); @@ -289,18 +320,21 @@ public class LicenseSetFactory { * @param filter the types of LicenseFamily objects to return. * @return a SortedSet of ILicense objects. */ - public SortedSet<ILicense> getLicenses(final LicenseFilter filter) { + public UnmodifiableSortedSet<ILicense> getLicenses(final LicenseFilter filter) { + SortedSet<ILicense> result; switch (filter) { case ALL: - return Collections.unmodifiableSortedSet(licenses); + result = licenses; + break; case APPROVED: - SortedSet<ILicense> result = new TreeSet<>(); + result = new TreeSet<>(); licenses.stream().filter(getApprovedLicensePredicate()).forEach(result::add); - return result; + break; case NONE: default: - return Collections.emptySortedSet(); + result = Collections.emptySortedSet(); } + return (UnmodifiableSortedSet<ILicense>) UnmodifiableSortedSet.unmodifiableSortedSet(result); } /** diff --git a/apache-rat-core/src/test/java/org/apache/rat/DefaultsTest.java b/apache-rat-core/src/test/java/org/apache/rat/DefaultsTest.java index bfd5f31e..db9edb03 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/DefaultsTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/DefaultsTest.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Set; import java.util.TreeSet; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; import org.apache.rat.license.ILicense; import org.apache.rat.license.LicenseSetFactory.LicenseFilter; import org.junit.jupiter.api.Test; @@ -36,7 +37,7 @@ public class DefaultsTest { public void defaultConfigTest() { Defaults defaults = Defaults.builder().build(); - Set<ILicense> licenses = defaults.getLicenseSetFactory().getLicenses(LicenseFilter.ALL); + UnmodifiableSortedSet<ILicense> licenses = defaults.getLicenseSetFactory().getLicenses(LicenseFilter.ALL); Set<String> names = new TreeSet<>(); licenses.forEach(x -> names.add(x.getLicenseFamily().getFamilyCategory())); diff --git a/apache-rat-core/src/test/java/org/apache/rat/analysis/HeaderCheckWorkerTest.java b/apache-rat-core/src/test/java/org/apache/rat/analysis/HeaderCheckWorkerTest.java index b00aec08..02a51085 100644 --- a/apache-rat-core/src/test/java/org/apache/rat/analysis/HeaderCheckWorkerTest.java +++ b/apache-rat-core/src/test/java/org/apache/rat/analysis/HeaderCheckWorkerTest.java @@ -21,8 +21,11 @@ package org.apache.rat.analysis; import java.io.StringReader; -import java.util.Collections; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; import org.apache.rat.Defaults; import org.apache.rat.api.Document; import org.apache.rat.configuration.builders.AnyBuilder; @@ -31,19 +34,25 @@ import org.apache.rat.testhelpers.TestingDocument; import org.apache.rat.license.ILicense; import org.apache.rat.testhelpers.TestingLicense; import org.apache.rat.testhelpers.TestingMatcher; -import org.assertj.core.util.Lists; import org.junit.jupiter.api.Test; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class HeaderCheckWorkerTest { + /** Create an unmodifiable sorted set from members */ + private UnmodifiableSortedSet<ILicense> asLicenses(ILicense... licenses) { + SortedSet<ILicense> inner = new TreeSet<>(); + inner.addAll(List.of(licenses)); + return (UnmodifiableSortedSet<ILicense>) UnmodifiableSortedSet.unmodifiableSortedSet(inner); + } + @Test public void emptyInputIsUnknownTest() throws RatHeaderAnalysisException { final Document subject = new TestingDocument("subject"); subject.getMetaData().setApprovalPredicate(Defaults.builder().build().getLicenseSetFactory().getApprovedLicensePredicate()); ILicense matcher = new TestingLicense("test", "test"); - HeaderCheckWorker worker = new HeaderCheckWorker(new TestingMatcher(), new StringReader(""), Lists.list(matcher), subject); + HeaderCheckWorker worker = new HeaderCheckWorker(new TestingMatcher(), new StringReader(""), asLicenses(matcher), subject); worker.read(); assertThat(subject.getMetaData().unapprovedLicenses().count()).isEqualTo(1); assertThat(subject.getMetaData().unapprovedLicenses().toList().get(0).getLicenseFamily()).isEqualTo(ILicenseFamily.UNKNOWN); @@ -53,7 +62,7 @@ public class HeaderCheckWorkerTest { public void generatedFileDetectionTest() throws Exception { final Document subject = new TestingDocument(new StringReader("Generated from configure.ac by autoheader"), "subject"); IHeaderMatcher matcher = new AnyBuilder().setResource("/org/apache/rat/generation-keywords.txt").build(); - HeaderCheckWorker worker = new HeaderCheckWorker(matcher, subject.reader(), Collections.emptyList(), subject); + HeaderCheckWorker worker = new HeaderCheckWorker(matcher, subject.reader(), asLicenses(), subject); worker.read(); assertThat(subject.getMetaData().getDocumentType()).isEqualTo(Document.Type.IGNORED); } diff --git a/apache-rat-tools/src/main/java/org/apache/rat/documentation/velocity/RatTool.java b/apache-rat-tools/src/main/java/org/apache/rat/documentation/velocity/RatTool.java index 820e246e..ca1adadf 100644 --- a/apache-rat-tools/src/main/java/org/apache/rat/documentation/velocity/RatTool.java +++ b/apache-rat-tools/src/main/java/org/apache/rat/documentation/velocity/RatTool.java @@ -24,11 +24,11 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.SortedSet; import java.util.TreeSet; import java.util.stream.Collectors; import org.apache.commons.cli.Option; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; import org.apache.commons.lang3.StringUtils; import org.apache.rat.CLIOption; import org.apache.rat.CLIOptionCollection; @@ -187,9 +187,8 @@ public class RatTool { * @return the set of Matchers. */ public Set<Matcher> matchers() { - MatcherBuilderTracker tracker = MatcherBuilderTracker.instance(); Set<Matcher> documentationSet = new TreeSet<>(Comparator.comparing(Matcher::getName)); - for (Class<?> clazz : tracker.getClasses()) { + for (Class<?> clazz : MatcherBuilderTracker.instance().getClasses()) { Description desc = DescriptionBuilder.buildMap(clazz); documentationSet.add(new Matcher(desc, null)); } @@ -246,7 +245,7 @@ public class RatTool { * @return a list of license property descriptions. */ public List<Description> licenseProperties() { - SortedSet<ILicense> licenses = licenseSetFactory.getLicenses(LicenseSetFactory.LicenseFilter.ALL); + UnmodifiableSortedSet<ILicense> licenses = licenseSetFactory.getLicenses(LicenseSetFactory.LicenseFilter.ALL); Description licenseDescription = DescriptionBuilder.build(licenses.first()); List<Description> descriptions = new ArrayList<>(licenseDescription.filterChildren(d -> d.getType() == ComponentType.PARAMETER)); descriptions.sort(Comparator.comparing(Description::getCommonName)); @@ -258,7 +257,7 @@ public class RatTool { * @return the list of defined licenses. */ public List<License> licenses() { - Set<ILicense> licenses = licenseSetFactory.getLicenses(LicenseSetFactory.LicenseFilter.ALL); + UnmodifiableSortedSet<ILicense> licenses = licenseSetFactory.getLicenses(LicenseSetFactory.LicenseFilter.ALL); return licenses.stream().map(License::new).collect(Collectors.toList()); }
