You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@creadur.apache.org by "Claudenw (via GitHub)" <gi...@apache.org> on 2024/04/01 11:17:24 UTC

[PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Claudenw opened a new pull request, #233:
URL: https://github.com/apache/creadur-rat/pull/233

   Contains all the changes for RAT-355 and RAT-366 as one package.
   
   The two issues were intertwined to the point where multiple files would be updated  by both changes and in conflicting ways.  This branch contains the changes from both.
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555611993


##########
apache-rat-core/src/main/java/org/apache/rat/Documentation.java:
##########
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.builders.AbstractBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+
+/**
+ * Generates text based documentation for Licenses, LicenceFamilies, and Matchers. 
+ * 
+ * Utilizes the same command line as the CLI based Report client so that additional licenses, etc. can be added.
+ *
+ */
+public class Documentation {
+
+    private static final String INDENT = "   ";
+
+    private Documentation() {
+    }
+
+    /**
+     * Output the ReportConfiguration to a writer.
+     * @param cfg The configuration to write.
+     * @param writer the writer to write to.
+     * @throws IOException on error.
+     */
+    public static void output(ReportConfiguration cfg, Writer writer) throws IOException {
+        writer.write(String.format("%n>>>> LICENSES <<<<%n%n"));
+        for (ILicense l : cfg.getLicenses(LicenseFilter.all)) {
+            printLicense(l, writer);
+        }
+
+        writer.write(String.format("%n>>>> MATCHERS (Datatype IHeaderMatcher) <<<<%n%n"));
+        for (Class<? extends AbstractBuilder> mClazz : MatcherBuilderTracker.INSTANCE.getClasses()) {
+            try {
+                AbstractBuilder builder = mClazz.getConstructor().newInstance();
+                printMatcher(DescriptionBuilder.buildMap(builder.builtClass()), writer);
+            } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
+                    | IllegalArgumentException | InvocationTargetException e) {
+                throw new ConfigurationException(
+                        String.format("Can not instantiate matcher builder  %s ", mClazz.getName()), e);
+            }
+        }
+
+        writer.write(String.format("%n>>>> FAMILIES (Datatype ILicenseFamily) <<<<%n%n"));
+        for (ILicenseFamily family : cfg.getLicenseFamilies(LicenseFilter.all)) {
+            printFamily(family, writer);
+        }
+    }
+
+    private static void printFamily(ILicenseFamily family, Writer writer) throws IOException {
+        writer.write(String.format("'%s' - %s%n", family.getFamilyCategory().trim(), family.getFamilyName()));
+    }
+
+    private static void printMatcher(Description matcher, Writer writer) throws IOException {
+        writer.write(String.format("'%s' - %s%n", matcher.getCommonName(), matcher.getDescription()));
+        printChildren(1, matcher.getChildren(), writer);
+
+    }
+
+    private static void printLicense(ILicense license, Writer writer) throws IOException {
+        Description dLicense = license.getDescription();
+        writer.write(String.format("'%s' - %s %n", dLicense.getCommonName(), dLicense.getDescription()));
+        printChildren(1, dLicense.getChildren(), writer);
+    }
+
+    private static void writeIndent(int indent, Writer writer) throws IOException {
+        for (int i = 0; i < indent; i++) {
+            writer.write(INDENT);
+        }
+    }
+
+    private static void printChildren(int indent, Map<String, Description> children, Writer writer) throws IOException {
+        for (Description d : children.values()) {
+            writeIndent(indent, writer);
+            switch (d.getType()) {
+            case Parameter:
+            case BuilderParam:
+                writer.write(String.format("'%s' %s (Datatype: %s%s)%n", d.getCommonName(), d.getDescription(),
+                        d.isCollection() ? "Collection of " : "", d.getChildType().getSimpleName()));
+                break;
+            case Unlabeled:
+                writer.write(String.format("'%s name' %s (Datatype: %s%s)%n", d.getCommonName(), d.getDescription(),
+                        d.isCollection() ? "Collection of " : "", d.getChildType().getSimpleName()));
+                break;
+            case License:
+                // do noting

Review Comment:
   Typo ;) nothing - i though of moving it to a default block .... when reading it first.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555910495


##########
apache-rat-core/src/main/java/org/apache/rat/api/Document.java:
##########
@@ -24,7 +24,26 @@
 
 import org.apache.rat.document.CompositeDocumentException;
 
+/**
+ * The representation of a document being scanned.
+ */
 public interface Document {
+    /**
+     * An enumeraton of document types.
+     */
+    enum Type {
+        /** A generated document. */
+        generated, 
+        /** An unknowns document type. */

Review Comment:
   Typo: An unknown?!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564204184


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/MatcherRefBuilder.java:
##########
@@ -56,31 +68,53 @@ public MatcherRefBuilder setMatchers(Map<String, IHeaderMatcher> matchers) {
 
     @Override
     public IHeaderMatcher build() {
+        if (matchers == null) {
+            throw new ConfigurationException("'matchers' not set");
+        }
         IHeaderMatcher result = matchers.get(referenceId);
         return result != null ? result : new IHeaderMatcherProxy(referenceId, matchers);
     }
 
     @Override
     public String toString() {
-        return "MathcerRefBuilder: "+referenceId;
+        return "MathcerRefBuilder: " + referenceId;
     }
-    
+
     /**
-     * A class that is a proxy to the actual matcher.  It retrieves the actual matcher from the map of
-     * matcher ids to matcher instances one the first use of the matcher.  This allows earlier read matchers
-     * to reference later constructed matchers as long as all the matchers are constructed before the earlier one is 
-     * used.
+     * A class that is a proxy to the actual matcher. It retrieves the actual
+     * matcher from the map of matcher ids to matcher instances one the first use of

Review Comment:
   on the first use of .....



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564218868


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/TextBuilder.java:
##########
@@ -22,27 +22,24 @@
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rat.ConfigurationException;
-import org.apache.rat.analysis.IHeaderMatcher;
 import org.apache.rat.analysis.matchers.FullTextMatcher;
 import org.apache.rat.analysis.matchers.SimpleTextMatcher;
 
 /**
  * Builds text based matcher based on the complexity of the text to match.

Review Comment:
   Builds a text based matcher?!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1565988070


##########
apache-rat-tasks/src/test/resources/antunit/report-bad-configurations.xml:
##########
@@ -59,7 +58,7 @@
   </target>
 
   <target name="testNoStylesheet">
-    <rat:report format="styled">
+    <rat:report styleReport="styled">

Review Comment:
   format is deprecated (but still works), styleReport is the new attribute.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564258251


##########
apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/impl/base/XmlWriter.java:
##########
@@ -514,6 +526,17 @@ private void writeAttributeContent(CharSequence content) throws IOException {
         writeEscaped(content, true);
     }
 
+    private void prepareForData() throws IOException {
+        if (elementNames.isEmpty()) {
+            if (elementsWritten) {
+                throw new OperationNotAllowedException("Root element has already been closed.");
+            } 
+            throw new OperationNotAllowedException("An element must be opened before content can be written.");
+        }
+        if (inElement) {
+            writer.write('>');
+        }
+    }
     /**
      * Writes content. Calling this method will automatically Note that this method

Review Comment:
   Calling this method will automatically .... seems like a copy&paste thing - 
   Do you want to add info that the element is closed automtically?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564497770


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */

Review Comment:
   We do not.  I didn't want to bring it in unless we had a good reason to.  Do we have tooling that would use it?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564515824


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {
+                        notes = desc;
+                    } else {
+                        writeAttribute(desc, component);
+                    }
+                }
+                for (Description desc : description.childrenOfType(Component.Type.BuilderParam)) {
+                    if ("family".equals(desc.getCommonName())) {
+                        try {
+                            ILicenseFamily family = (ILicenseFamily) desc.getter(component.getClass())
+                                    .invoke(component);
+                            if (family != null) {
+                                writer.attribute("family", family.getFamilyCategory().trim());
+                            }
+                        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
+                                | InvocationTargetException | SecurityException e) {
+                            configuration.getLog().error(e.toString());
+                        }
+                    }
+                }
+                // end of attributes
+                if (notes != null && StringUtils.isNotBlank(notes.getParamValue(configuration.getLog(), component))) {
+                    writeComment(notes);
+                    writer.openElement(notes.getCommonName());
+                    writeContent(notes, component);
+                    writer.closeElement();
+                }
+                for (Description desc : description.childrenOfType(Component.Type.Unlabeled)) {
+                    writeDescription(desc, component);
+                }
+                writer.closeElement();
+                break;
+            case Parameter:
+                if ("id".equals(description.getCommonName())) {
+                    try {
+                        String idValue = description.getParamValue(configuration.getLog(), component);
+                        // if a UUID skip it.
+                        if (idValue != null) {
+                            UUID.fromString(idValue.toString());
+                            return;
+                        }
+                    } catch (IllegalArgumentException expected) {
+                        // do nothing.
+                    }
+                }
+                writeAttribute(description, component);
+                break;
+            case Unlabeled:
+                try {
+                    Object obj = description.getter(component.getClass()).invoke(component);
+                    if (obj instanceof Iterable) {
+                        for (Object o2 : (Iterable<?>) obj) {
+                            processUnlabled(o2);

Review Comment:
   unlabelled has been removed as a type.



##########
apache-rat-core/src/main/java/org/apache/rat/report/claim/ClaimStatistic.java:
##########
@@ -19,100 +19,62 @@
 
 package org.apache.rat.report.claim;
 
+import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.rat.api.Document;
+
 
 /**
  * This class provides a numerical overview about
  * the report.
  */
 public class ClaimStatistic {
-    private Map<String, Integer> documentCategoryMap, licenseFamilyCodeMap, licenseFamilyNameMap;
-    private int numApproved, numUnApproved, numGenerated, numUnknown;
-
-    /**
-     * @return Returns the number of files with approved licenses.
-     */
-    public int getNumApproved() {
-        return numApproved;
-    }
-
-    /**
-     * Sets the number of files with approved licenses.
-     * @param pNumApproved number of files with approved licenses.
-     */
-    public void setNumApproved(int pNumApproved) {
-        numApproved = pNumApproved;
-    }
-
-    /**
-     * @return Returns the number of files with unapproved licenses.
-     * <em>Note:</em> This might include files with unknown
-     * licenses.
-     * @see #getNumUnknown()
-     */
-    public int getNumUnApproved() {
-        return numUnApproved;
-    }
-
-    /**
-     * Sets the number of files with unapproved licenses.
-     * @param pNumUnApproved number of files with unapproved licenses.
-     */
-    public void setNumUnApproved(int pNumUnApproved) {
-        numUnApproved = pNumUnApproved;
-    }
-
-    /**
-     * @return Returns the number of generated files.
-     */
-    public int getNumGenerated() {
-        return numGenerated;
-    }
+    /** The counter types */
+    public enum Counter { 

Review Comment:
   Changed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564513148


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {
+                        notes = desc;
+                    } else {
+                        writeAttribute(desc, component);
+                    }
+                }
+                for (Description desc : description.childrenOfType(Component.Type.BuilderParam)) {
+                    if ("family".equals(desc.getCommonName())) {
+                        try {
+                            ILicenseFamily family = (ILicenseFamily) desc.getter(component.getClass())
+                                    .invoke(component);
+                            if (family != null) {
+                                writer.attribute("family", family.getFamilyCategory().trim());
+                            }
+                        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
+                                | InvocationTargetException | SecurityException e) {
+                            configuration.getLog().error(e.toString());
+                        }
+                    }
+                }
+                // end of attributes
+                if (notes != null && StringUtils.isNotBlank(notes.getParamValue(configuration.getLog(), component))) {
+                    writeComment(notes);
+                    writer.openElement(notes.getCommonName());
+                    writeContent(notes, component);
+                    writer.closeElement();
+                }
+                for (Description desc : description.childrenOfType(Component.Type.Unlabeled)) {
+                    writeDescription(desc, component);
+                }
+                writer.closeElement();
+                break;
+            case Parameter:
+                if ("id".equals(description.getCommonName())) {

Review Comment:
   all constants have been extracted.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555626164


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/IHeaders.java:
##########
@@ -0,0 +1,37 @@
+package org.apache.rat.analysis;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+
+/**
+ * The processed headers from a file.
+ */
+public interface IHeaders {
+    /**
+     * Gets raw header as found in the document. 
+     * @return the raw header as read from the file.
+     */
+    public String raw();
+
+    /**
+     * Gets the pruned header.  This is the header with all non letter and non number characters removed and the string converted to lower case..

Review Comment:
   typo: ..



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555930879


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Component.java:
##########
@@ -0,0 +1,48 @@
+package org.apache.rat.config.parameters;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Interface that marks a configuration component like a License or Matcher.
+ *
+ */
+public interface Component {
+    /** Types of components */
+    public enum Type {

Review Comment:
   Uppercasing?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "jbonofre (via GitHub)" <gi...@apache.org>.
jbonofre commented on PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#issuecomment-2053896244

   Sorry guys, I'm late on this one. I will take a look today.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564500321


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();

Review Comment:
   Extracted to XMLConfig



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564255897


##########
apache-rat-core/src/main/java/org/apache/rat/report/claim/impl/xml/SimpleXmlClaimReporter.java:
##########
@@ -140,9 +100,9 @@ public void startReport() throws RatException {
     @Override
     public void endReport() throws RatException {
         try {
-            writer.closeDocument();
+            writer.closeElement();
         } catch (IOException e) {
-            throw new RatException("Cannot close last element", e);
+            throw new RatException("Cannot open start element", e);

Review Comment:
   "Cannot close start element"? endReport() should not open the start element here.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564970399


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 
+ scope of this document.  In this document we will address how to define licenses in the default XML format.
+ 
+ The XML document has a root node named "rat-config" which comprises 4 major sections: "Families", 
+ "Licenses", "Approved" and "Matchers".
+ 
+* Families
+ 
+ Families are groups that define licenses that share similarities.  Each family has an id and a name, and example
+ of an entry in this section is
+ 
++------------------------------------------+
+ <rat-config>
+    <families>
+        <family id="AL" name="Apache License Version 2.0" />
+    </families>
+ </rat-config>
++------------------------------------------+
+ 
+* Matchers
+
+ Matchers define tests that check the contents of files for specific patterns.  Matchers are defined in Java
+ code and are required to have Builder classes that build them.  There is {{{./matcher_def.html}additional documentation 
+ explaining how to create new Matchers}}.  In the XML document Matchers are identified by the "matcher" element that has
+ a single "class" property.  The value of the "class" property is the fully qualified class name that 
+ identifies a Builder class.  An example of a matchers entry is
+ 
++------------------------------------------+
+ <rat-config>
+    <matchers>
+        <matcher class="org.apache.rat.configuration.builders.AnyBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.SpdxBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.TextBuilder" />
+    </matcher>
+ </rat-config>
++------------------------------------------+
+ 
+* Licenses
+
+ License elements have three properties: "family", "id", and "name". The family property must refer to
+ the "id" of a family element.  The family element can be defined in the current document or in another
+ included document.  It has to exist by the time all the configuration files are read.  The "id" element
+ is optional, if it is not provided the id will be set to the id of the associated family.  However, the 
+ "id" property must be unique across all licenses.  The "name" property is also optional.  If not specified
+ the name of the associated family will be used.  It is recommened that each license have a unique name

Review Comment:
   2x typo: It is recommended that each license has a ..... 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564968102


##########
src/site/apt/index.apt.vm:
##########
@@ -63,6 +63,16 @@ Apache Rat
  {{{./issue-management.html}patch}} or
  {{{./mailing-lists.html}talk to us}}
  whenever Rat falls short.
+ 
+** How do I extend Rat
+ 
+ There are several standard ways to extend Rat.
+ 
+   * Add a {{{./license_def.html}license definition}} via an XML file.
+   
+   * Add a new {{{./matcher_def.html}Matcher definition}}. Requires Java expertice.
+   
+   * Add a new definition format.  Requires java expertice as well as expertice with the format.

Review Comment:
   Typo 2x: expertise;
   I'd prefer to uppercase Java.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564965074


##########
apache-rat-tasks/pom.xml:
##########
@@ -105,7 +105,7 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
+      <!--<plugin>

Review Comment:
   Are these tests removed or did you change the testing mechanism for Ant?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564974753


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.

Review Comment:
   For matters of consistency: is there a difference between ID and id or Id?
   I spotted the same in Javadoc of the changes and asked myself if there is a semantic difference between the two or if we should just decide to use one notation in all places.
   Personally I'm fine with "Id" in the code and "id" in written text.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555985106


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Description.java:
##########
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.parameters;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.rat.ConfigurationException;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.utils.Log;
+
+/**
+ * A description of a component.
+ */
+public class Description {
+    /** The type of component this describes */
+    private final Type type;
+    /**
+     * The common name for the component. Set by ConfigComponent.name() or
+     * class/field name.
+     */
+    private final String name;
+    /** The description for the component */
+    private final String desc;
+    /** The class of the getter/setter parameter */
+    private final Class<?> childClass;
+    /** True if the getter/setter expects a collection of childClass objects */
+    private final boolean isCollection;
+    /**
+     * a map of name to Description for all the components that are children the
+     * described component
+     */
+    private final Map<String, Description> children;
+
+    /**
+     * Constructor.
+     * 
+     * @param type the type of the component.
+     * @param name the name of the component.
+     * @param desc the description of the component.
+     * @param isCollection true if the getter/setter expects a collection
+     * @param childClass the class for expected for the getter/setter.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.
+     */
+    public Description(Type type, String name, String desc, boolean isCollection, Class<?> childClass,
+            Collection<Description> children) {
+        this.type = type;
+        this.name = name;
+        this.desc = desc;
+        this.isCollection = isCollection;
+        this.childClass = childClass;
+        this.children = new TreeMap<>();
+        if (children != null) {
+            children.forEach(d -> {
+                this.children.put(d.name, d);
+            });
+        }
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param configComponent the configuration component
+     * @param isCollection the collection flag.
+     * @param childClass the type of object that the method getter/setter expects.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.
+     */
+    public Description(ConfigComponent configComponent, boolean isCollection, Class<?> childClass,
+            Collection<Description> children) {
+        this(configComponent.type(), configComponent.name(), configComponent.desc(), isCollection, childClass,
+                children);
+    }
+
+    /**
+     * Gets the type of the component.
+     * 
+     * @return the component type.
+     */
+    public Type getType() {
+        return type;
+    }
+
+    /**
+     * Get the isCollection flag.
+     * 
+     * @return true if this is a collection.
+     */
+    public boolean isCollection() {
+        return isCollection;
+    }
+
+    /**
+     * Get the class of the objcts for the getter/setter.

Review Comment:
   Typo: objects



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555628312


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/LicenseCollection.java:
##########
@@ -22,33 +22,37 @@
 import java.util.Collections;
 
 import org.apache.rat.analysis.matchers.AbstractMatcherContainer;
+import org.apache.rat.config.parameters.Description;
 import org.apache.rat.license.ILicense;
 import org.apache.rat.license.ILicenseFamily;
 
 /**
- * A collection of ILicenses that acts as a single License for purposes of Analysis.
+ * A collection of ILicenses that acts as a single License for purposes of
+ * Analysis.
  * <p>
- * This class process each license in turn on each {@code matches(String)} call.  When a match is found the 
- * ILicenseFamily for the matching license is captured and used as the family for this license. If no matching 
- * license has been found the default {@code dummy} license category is used.
+ * This class process each license in turn on each {@code matches(String)} call.
+ * When a match is found the ILicenseFamily for the matching license is captured
+ * and used as the family for this license. If no matching license has been
+ * found the default {@code dummy} license category is used.
  */
+
 class LicenseCollection extends AbstractMatcherContainer implements ILicense {
 
     private static final ILicenseFamily DEFAULT = ILicenseFamily.builder().setLicenseFamilyCategory("Dummy")

Review Comment:
   Not sure how this dummy is handled in the report, would NONE be clearer here as the family does actually not do anything?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555911296


##########
apache-rat-core/src/main/java/org/apache/rat/api/Document.java:
##########
@@ -24,7 +24,26 @@
 
 import org.apache.rat.document.CompositeDocumentException;
 
+/**
+ * The representation of a document being scanned.
+ */
 public interface Document {
+    /**
+     * An enumeraton of document types.
+     */
+    enum Type {
+        /** A generated document. */
+        generated, 

Review Comment:
   Shouldn't we be UPPERCASE here to comply with Java standards?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564201219


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/MatcherRefBuilder.java:
##########
@@ -20,19 +20,26 @@
 
 import java.util.Map;
 
+import org.apache.rat.ConfigurationException;
 import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
 
 /**
- * A reference matching Matcher builder.
- * <p>
- * This class stores a matcher id as a reference to the matcher.  It also has a map of matcher ids to the matcher
- * instances.  When build is called the matcher reference is looked up in the map.  If it is found then it is returned
- * value from the {@code build()} call.  If the reference is not located then a IHeaderMatcherProxy is returned.
- * the IHeaderMatcherProxy is resolved in a later configuration construction phase.
+ * A reference matching Matcher builder. <p> This class stores a matcher id as a
+ * reference to the matcher. It also has a map of matcher ids to the matcher
+ * instances. When build is called the matcher reference is looked up in the

Review Comment:
   When {@code build()} is called ....



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564196856


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java:
##########
@@ -279,14 +334,13 @@ private ILicense parseLicense(Node licenseNode) {
         StringBuilder notesBuilder = new StringBuilder();
         nodeListConsumer(licenseNode.getChildNodes(), x -> {
             if (x.getNodeType() == Node.ELEMENT_NODE) {
-                if (x.getNodeName().equals(NOTE)) {
+                if (NOTE.equals(x.getNodeName())) {
                     notesBuilder.append(x.getTextContent()).append("\n");

Review Comment:
   Would System.lineSeparator() be more correct here?
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564260890


##########
apache-rat-core/src/main/java/org/apache/rat/utils/Log.java:
##########
@@ -59,51 +59,105 @@ public enum Level {
      */
     void log(Level level, String message);
     
+    /**
+     * Write a log message at the specified level.
+     * @param level the level to write the message at.
+     * @param message the mesage to write.
+     */
     default void log(Level level, Object message) {
         log(level, message == null ? "NULL" : message.toString());
     }
     
+    /**
+     * Write a message at DEBUG level.
+     * @param message the message to write.
+     */
     default void debug(Object message) {
         log(Level.DEBUG, message);
     }
 
+    /**
+     * Write a message at INFO level.
+     * @param message the message to write.
+     */
     default void info(Object message) {
         log(Level.INFO, message);
     }
     
+    /**
+     * Write a message at WARN level.
+     * @param message the message to write.
+     */
     default void warn(Object message) {
         log(Level.WARN, message);
     }
     
+    /**
+     * Write a message at ERROR level.
+     * @param message the message to write.
+     */
     default void error(Object message) {
         log(Level.ERROR, message);
     }
-    default void log(Level level, String message, Throwable t) {       
+    
+    /**
+     * Write a log message and report throwable stack trace at the specified log level.
+     * @param level the level to report at
+     * @param message the message for the log
+     * @param throwable the throwable
+     */
+    default void log(Level level, String message, Throwable throwable) {       
         StringWriter writer = new StringWriter(500);
         PrintWriter pWriter = new PrintWriter(writer);
         pWriter.print(message);
         pWriter.print(System.lineSeparator());
-        t.printStackTrace(pWriter);
+        throwable.printStackTrace(pWriter);

Review Comment:
   The docs says that printStackTrace() prints to StandardErr. I thought we want to log this as part of the given message or is it okay to write a logLevel in DEBUG that outputs the stacktrace on ERROR?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564247234


##########
apache-rat-core/src/main/java/org/apache/rat/license/LicenseSetFactory.java:
##########
@@ -220,5 +221,5 @@ public static ILicense search(ILicense target, SortedSet<ILicense> licenses) {
         SortedSet<ILicense> part = licenses.tailSet(target);
         return (!part.isEmpty() && part.first().compareTo(target) == 0) ? part.first() : null;

Review Comment:
   Can target be null? Should we use part().first().equals(target) instead of the compareTo==0?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564969176


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.

Review Comment:
   Typo: that can serve



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564975345


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {

Review Comment:
   Not sure if there is a way to reference parts of sources, but in case it remains we should stick a big warning in IHeaderMatcher to keep the site up2date.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555625327


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/IHeaderMatcher.java:
##########
@@ -110,10 +71,39 @@ public String toString() {
     interface Builder {
         /**
          * Build the IHeaderMatcher.
+         * 
+         * Implementations of this interface should return a specific child class of IHeaderMatcher.
+         * 
          * @return a new IHeaderMatcher.
          */
         IHeaderMatcher build();
 
+        /**
+         * Gets the class that is build by this builder.
+         * @return The class that is build by this builder.
+         */
+        default Class<?> builtClass() throws SecurityException {
+            try {
+                return this.getClass().getMethod("build").getReturnType();
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+            }
+        }
+
+        /**
+         * Gets the Description for this builder.
+         * @return The description of the builder 
+         */
+        default Description getDescription() {
+            Class<?> clazz = builtClass();
+            if (clazz == IHeaderMatcher.class) {
+                throw new ImplementationException(String.format(
+                        "Class %s must implement built() method to return a child class of IHeaderMatcher", 

Review Comment:
   typo: build()?



##########
apache-rat-core/src/main/java/org/apache/rat/analysis/IHeaderMatcher.java:
##########
@@ -110,10 +71,39 @@ public String toString() {
     interface Builder {
         /**
          * Build the IHeaderMatcher.
+         * 
+         * Implementations of this interface should return a specific child class of IHeaderMatcher.
+         * 
          * @return a new IHeaderMatcher.
          */
         IHeaderMatcher build();
 
+        /**
+         * Gets the class that is build by this builder.
+         * @return The class that is build by this builder.
+         */
+        default Class<?> builtClass() throws SecurityException {
+            try {
+                return this.getClass().getMethod("build").getReturnType();
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+            }
+        }
+
+        /**
+         * Gets the Description for this builder.
+         * @return The description of the builder 
+         */
+        default Description getDescription() {
+            Class<?> clazz = builtClass();
+            if (clazz == IHeaderMatcher.class) {
+                throw new ImplementationException(String.format(
+                        "Class %s must implement built() method to return a child class of IHeaderMatcher", 

Review Comment:
   typo: build()/buildMap()?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555987496


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Description.java:
##########
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.parameters;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.rat.ConfigurationException;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.utils.Log;
+
+/**
+ * A description of a component.
+ */
+public class Description {
+    /** The type of component this describes */
+    private final Type type;
+    /**
+     * The common name for the component. Set by ConfigComponent.name() or
+     * class/field name.
+     */
+    private final String name;
+    /** The description for the component */
+    private final String desc;
+    /** The class of the getter/setter parameter */
+    private final Class<?> childClass;
+    /** True if the getter/setter expects a collection of childClass objects */
+    private final boolean isCollection;
+    /**
+     * a map of name to Description for all the components that are children the
+     * described component
+     */
+    private final Map<String, Description> children;
+
+    /**
+     * Constructor.
+     * 
+     * @param type the type of the component.
+     * @param name the name of the component.
+     * @param desc the description of the component.
+     * @param isCollection true if the getter/setter expects a collection
+     * @param childClass the class for expected for the getter/setter.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.
+     */
+    public Description(Type type, String name, String desc, boolean isCollection, Class<?> childClass,
+            Collection<Description> children) {
+        this.type = type;
+        this.name = name;
+        this.desc = desc;
+        this.isCollection = isCollection;
+        this.childClass = childClass;
+        this.children = new TreeMap<>();
+        if (children != null) {
+            children.forEach(d -> {
+                this.children.put(d.name, d);
+            });
+        }
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param configComponent the configuration component
+     * @param isCollection the collection flag.
+     * @param childClass the type of object that the method getter/setter expects.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.

Review Comment:
   Typo: of the described component



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555914329


##########
apache-rat-core/src/main/java/org/apache/rat/api/MetaData.java:
##########
@@ -18,340 +18,128 @@
  */
 package org.apache.rat.api;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Stream;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
 
 /**
  * Data about the document under test..
  */
 public class MetaData {
 
-    public static final String RAT_BASE_URL = "http://org/apache/rat/meta-data";
-    
-    // Document Categories
-    public static final String RAT_URL_DOCUMENT_CATEGORY = RAT_BASE_URL + "#FileCategory";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_GENERATED = "GEN  ";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_UNKNOWN = "?????";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_ARCHIVE = "archive";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_NOTICE = "notice";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_BINARY = "binary";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_STANDARD = "standard";
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_GENERATED = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_GENERATED);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_UNKNOWN = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_UNKNOWN);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_ARCHIVE = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_ARCHIVE);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_NOTICE = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_NOTICE);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_BINARY = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_BINARY);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_STANDARD = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_STANDARD);
-    
-    // Header Categories
-    public static final String RAT_URL_HEADER_CATEGORY = RAT_BASE_URL + "#HeaderCategory";
-    
-    // License Family Categories
-    public static final String RAT_URL_LICENSE_FAMILY_CATEGORY= RAT_BASE_URL + "#LicenseFamilyCategory";
-    // Shortcuts used in report output, must be exactly 5 characters
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GEN = "GEN  ";
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_UNKNOWN = "?????";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_ASL = "AL   ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_OASIS = "OASIS";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3CD = "W3CD ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3C = "W3C  ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_DOJO = "DOJO ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_TMF = "TMF  ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL1 ="GPL1 ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL2 ="GPL2 ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL3 = "GPL3 ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_MIT = "MIT  ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_CDDL1 = "CDDL1";
-
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GEN = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_GEN);
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_UNKNOWN = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_UNKNOWN);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_ASL = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_ASL);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_OASIS = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_OASIS);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_W3CD = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3CD);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_W3C = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3C);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_DOJO = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_DOJO);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_TMF = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_TMF);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GPL1 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL1);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GPL2 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL2);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GPL3 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL3);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_MIT = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_MIT);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_CDLL1 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_CDDL1);
-
-    // License Family Standard Names
-    public static final String RAT_URL_LICENSE_FAMILY_NAME= RAT_BASE_URL + "#LicenseFamilyName";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_W3C_SOFTWARE_COPYRIGHT = "W3C Software Copyright";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_W3C_DOCUMENT_COPYRIGHT = "W3C Document Copyright";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_OASIS_OPEN_LICENSE = "OASIS Open License";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_MODIFIED_BSD_LICENSE = "Modified BSD License";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_APACHE_LICENSE_VERSION_2_0 = "Apache License Version 2.0";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_1 =
-            "GNU General Public License, version 1";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_2 =
-            "GNU General Public License, version 2";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_3 =
-            "GNU General Public License, version 3";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_MIT =
-            "The MIT License";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_CDDL1 =
-            "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_ACADEMIC_FREE_LICENSE_VERSION_2_1 = "Academic Free License, Version 2.1";
-
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_UNKNOWN = "?????";
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_W3C_SOFTWARE_COPYRIGHT 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_W3C_SOFTWARE_COPYRIGHT);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_W3C_DOCUMENT_COPYRIGHT 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_W3C_DOCUMENT_COPYRIGHT);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_OASIS_OPEN_LICENSE 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_OASIS_OPEN_LICENSE);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_MODIFIED_BSD_LICENSE 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_MODIFIED_BSD_LICENSE);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_APACHE_LICENSE_VERSION_2_0
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_APACHE_LICENSE_VERSION_2_0);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_GPL_VERSION_1 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_1);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_GPL_VERSION_2 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_2);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_GPL_VERSION_3 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_3);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_MIT = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_MIT);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_CDDL1 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_CDDL1);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_ACADEMIC_FREE_LICENSE_VERSION_2_1
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_ACADEMIC_FREE_LICENSE_VERSION_2_1);
+    /** The list of matched licenses */
+    private final SortedSet<ILicense> matchedLicenses;
+    /** The list of License Family Categories that are approved */
+    private final Set<String> approvedLicenses;
 
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_UNKNOWN
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_UNKNOWN); 
-    
-    // Header sample
-    public static final String RAT_URL_HEADER_SAMPLE = RAT_BASE_URL + "#HeaderSample";
-    
-    // License Approval
-    public static final String RAT_URL_APPROVED_LICENSE = RAT_BASE_URL + "#ApprovedLicense";
-    public static final String RAT_APPROVED_LICENSE_VALUE_TRUE = Boolean.TRUE.toString();
-    public static final String RAT_APPROVED_LICENSE_VALUE_FALSE = Boolean.FALSE.toString();
-    public static final Datum RAT_APPROVED_LICENSE_DATUM_TRUE = new Datum(RAT_URL_APPROVED_LICENSE, RAT_APPROVED_LICENSE_VALUE_TRUE);
-    public static final Datum RAT_APPROVED_LICENSE_DATUM_FALSE = new Datum(RAT_URL_APPROVED_LICENSE, RAT_APPROVED_LICENSE_VALUE_FALSE);
-    @Deprecated
-    public static final Datum RAT_APPROVED_LICENSE_DATIM_TRUE = RAT_APPROVED_LICENSE_DATUM_TRUE;
-    @Deprecated
-    public static final Datum RAT_APPROVED_LICENSE_DATIM_FALSE = RAT_APPROVED_LICENSE_DATUM_FALSE;
-
-    /** 
-     * Only likely to be a small quantity of data 
-     * so trade some performance for simplicity.
-     */
-    private final List<Datum> data;
+    private Document.Type documentType;
+    private String sampleHeader;
 
     /**
      * Create metadata without a content type.
      */
     public MetaData() {
-        this.data = new ArrayList<>(16);
+        this.matchedLicenses = new TreeSet<>();
+        this.approvedLicenses = new HashSet<>();
     }
-    
+
     /**
-     * Add the license information to the metadata.
-     * @param license the license to add metadata for.
+     * Determines if a mathcing license has been detected.
+     * @return true if there is a matching license.
      */
-    public void reportOnLicense(ILicense license) {
-        
-        if (StringUtils.isNotBlank(license.getNotes())) {
-            set(new MetaData.Datum(MetaData.RAT_URL_HEADER_SAMPLE, license.getNotes()));
-        }
-        set(new MetaData.Datum(MetaData.RAT_URL_HEADER_CATEGORY, license.getLicenseFamily().getFamilyCategory()));
-        set(new MetaData.Datum(MetaData.RAT_URL_LICENSE_FAMILY_CATEGORY, license.getLicenseFamily().getFamilyCategory()));
-        set(new MetaData.Datum(MetaData.RAT_URL_LICENSE_FAMILY_NAME, license.getLicenseFamily().getFamilyName()));
+    public boolean detectedLicense() {
+        return !matchedLicenses.isEmpty();
     }
 
-    
     /**
-     * Gets all data.
-     * @return unmodifiable view of the meta data.
+     * Sets the set of approved licenses.
+     * @param approvedLicenseFamilies the set of approved license families.
      */
-    public Collection<Datum> getData() {
-        return Collections.unmodifiableCollection(data);
+    public void setApprovedLicenses(Set<ILicenseFamily> approvedLicenseFamilies) {
+        licenses().filter(lic -> approvedLicenseFamilies.contains(lic.getLicenseFamily()))
+                .forEach(lic -> approvedLicenses.add(lic.getId()));
     }
-    
+
     /**
-     * Adds a new datum.
-     * Existing data with the same name are not replaced.
-     * @param datum datum to add.
-     * @see #set(org.apache.rat.api.MetaData.Datum)
+     * Gets the stream of licenses that have been matched.
+     * @return the stream of licenses that have been matched.
      */
-    public void add(final Datum datum) {
-       data.add(datum); 
+    public Stream<ILicense> licenses() {
+        return matchedLicenses.stream();
     }
-    
+
     /**
-     * Puts in a new datum replacing any existing data.
-     * Any current data matching the name are removed.
-     * @param datum not null
-     * @see #add(org.apache.rat.api.MetaData.Datum)
+     * Gets the stream of approved licenses that have been matched.
+     * @return the stream of approved licenses theat have been matched.

Review Comment:
   Typo: that



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564251232


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {

Review Comment:
   Extract as constant as other occurences above?



##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {
+                        notes = desc;
+                    } else {
+                        writeAttribute(desc, component);
+                    }
+                }
+                for (Description desc : description.childrenOfType(Component.Type.BuilderParam)) {
+                    if ("family".equals(desc.getCommonName())) {

Review Comment:
   Extract as constant as other occurences above?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564972954


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 
+ scope of this document.  In this document we will address how to define licenses in the default XML format.
+ 
+ The XML document has a root node named "rat-config" which comprises 4 major sections: "Families", 
+ "Licenses", "Approved" and "Matchers".
+ 
+* Families
+ 
+ Families are groups that define licenses that share similarities.  Each family has an id and a name, and example
+ of an entry in this section is
+ 
++------------------------------------------+
+ <rat-config>
+    <families>
+        <family id="AL" name="Apache License Version 2.0" />
+    </families>
+ </rat-config>
++------------------------------------------+
+ 
+* Matchers
+
+ Matchers define tests that check the contents of files for specific patterns.  Matchers are defined in Java
+ code and are required to have Builder classes that build them.  There is {{{./matcher_def.html}additional documentation 
+ explaining how to create new Matchers}}.  In the XML document Matchers are identified by the "matcher" element that has
+ a single "class" property.  The value of the "class" property is the fully qualified class name that 
+ identifies a Builder class.  An example of a matchers entry is
+ 
++------------------------------------------+
+ <rat-config>
+    <matchers>
+        <matcher class="org.apache.rat.configuration.builders.AnyBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.SpdxBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.TextBuilder" />
+    </matcher>
+ </rat-config>
++------------------------------------------+
+ 
+* Licenses
+
+ License elements have three properties: "family", "id", and "name". The family property must refer to
+ the "id" of a family element.  The family element can be defined in the current document or in another
+ included document.  It has to exist by the time all the configuration files are read.  The "id" element
+ is optional, if it is not provided the id will be set to the id of the associated family.  However, the 
+ "id" property must be unique across all licenses.  The "name" property is also optional.  If not specified
+ the name of the associated family will be used.  It is recommened that each license have a unique name
+ as name conflicts make problem determination difficult.
+ 
+ License elements have two child element types.  The first is "notes".  There may be multiple "notes" 
+ child elements.  They are simple text elements that define notes about the license.  The other element
+ is a Matcher type.  A matcher element is defined by a builder in the "matchers" section as described
+ above.  The matchers listed in the example above define the "any", "spdx", and "text" matcher elements.
+ 
+ When defining the license the matcher is required and only one may be defined.  However, there are matchers
+ that accept multiple matcher child nodes.  In the example below the CDDL1 license uses the "any" matcher.
+ The "any" matcher accepts multiple child matchers and will report a match if any of the enclosed matchers
+ report a match. In the example below the "any" matcher has "text" and "spdx" child matchers.  The "text"
+ matcher will match the enclosed text and the "spdx" matcher matches {{{https://spdx.org/licenses/}SPDX}}
+ tags.  The second license defined below is the "ILLUMOS" license.  It shares the same family as the CDDL1
+ license, has its own "id" and "name" properties.  It also has a "note" child element that tells the user
+ that it is a modified CDDL1 license.  The license has a single "text" matcher.
+ 
++------------------------------------------+
+ <rat-config>
+    <licenses>
+        <license family="CDDL1">
+            <any>
+                <text>The contents of this file are subject to the terms of the
+                    Common Development and Distribution License("CDDL") (the
+                    "License"). You may not use this file except in compliance
+                    with the License.</text>
+                <spdx name='CDDL-1.0' />
+            </any>
+        </license>
+
+        <license family="CDDL1" id="ILLUMOS" name="ILLUMOS CDDL1 Derived license">
+            <note>Modified CDDL1 license</note>
+            <text>The contents of this file are subject to the terms of
+                the Common Development and Distribution License (the
+                "License") You may not use this file except in compliance
+                with the License. </text>
+        </license>
+    </licenses>
+ </rat-config>
++------------------------------------------+
+ 
+* Approved 
+ 
+ Approved element lists the approved licenses from this configuration.  It is possible to define licenses
+ that you want to detect but not allow.  If the "approved" element is not present all defined families
+ are considered to be approved.  The approved entry has "family" child entries that have "license_ref"
+ properties that reference the "id" of the family being approved.
+ 
++------------------------------------------+
+ <rat-config>
+    <approved>
+        <family license_ref='AL' />
+    </approved>
+ </rat-config>
++------------------------------------------+
+
+* Listing components
+
+ All the components (Licenses and Matchers) defined in the system can be displayed using the Documentation
+ tool.  To run the too execute:
+
++------------------------------------------+
+java -jar apache-rat-${project.version}.jar org.apache.rat.Documentation
++------------------------------------------+
+
+ The tool take the same arguments as the standard rat CLI, so additional license files can be defined.

Review Comment:
   Typo: Rat CLI



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564500995


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:

Review Comment:
   All enums have been changed to upper case.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564487716


##########
apache-rat-core/src/main/java/org/apache/rat/document/impl/ArchiveEntryDocument.java:
##########
@@ -37,44 +36,44 @@ public class ArchiveEntryDocument implements Document {
 
     private final MetaData metaData = new MetaData();
 
-    public ArchiveEntryDocument(File file, byte[] contents) throws RatException {
+    public ArchiveEntryDocument(File file, byte[] contents) {
         super();
         name = DocumentImplUtils.toName(file);
         this.contents = contents;
     }
 
+    @Override
     public MetaData getMetaData() {
         return metaData;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public InputStream inputStream() throws IOException {
         return new ByteArrayInputStream(contents);
     }
 
+    @Override
     public boolean isComposite() {
         return DocumentImplUtils.isZipStream(new ByteArrayInputStream(contents));

Review Comment:
   Actually, this file has no technical changes and should be reverted.  But in answer to your question yes, and it is an area I will be looking into shortly.  I want us to use the SPDX license matching code to see if we can match LICENSE files and I want to do that within archive files.



##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/TextBuilder.java:
##########
@@ -22,27 +22,24 @@
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rat.ConfigurationException;
-import org.apache.rat.analysis.IHeaderMatcher;
 import org.apache.rat.analysis.matchers.FullTextMatcher;
 import org.apache.rat.analysis.matchers.SimpleTextMatcher;
 
 /**
  * Builds text based matcher based on the complexity of the text to match.

Review Comment:
   reworked.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1566045733


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.

Review Comment:
   No semantic difference.  I have tried to clean the documentation to make it all "id"



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1566294449


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface
+interface Builder {
+    /**
+     * Build the IHeaderMatcher.
+     * 
+     * Implementations of this interface should return a specific child class of IHeaderMatcher.
+     * 
+     * @return a new IHeaderMatcher.
+     */
+    IHeaderMatcher build();
+
+    /**
+     * Gets the class that is build by this builder.
+     * @return The class that is build by this builder.
+     */
+    default Class<?> builtClass() throws SecurityException {
+        try {
+            return this.getClass().getMethod("build").getReturnType();
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+        }
+    }
+
+    /**
+     * Gets the Description for this builder.
+     * @return The description of the builder 
+     */
+    default Description getDescription() {
+        Class<?> clazz = builtClass();
+        if (clazz == IHeaderMatcher.class) {
+            throw new ImplementationException(String.format(
+                    "Class %s must implement built() method to return a child class of IHeaderMatcher", 
+                    this.getClass()));
+        }
+        return DescriptionBuilder.buildMap(clazz);
+    }
+}
++------------------------------------------+
+
+  The work of handling the Id and some other tasks is handled by the AbstractBuilder.
+  
++------------------------------------------+
+public abstract class AbstractBuilder implements IHeaderMatcher.Builder {
+
+    private String id;
+
+    /**
+     * Protected empty constructor.
+     */
+    protected AbstractBuilder() {
+    }
+
+    /**
+     * Set the id for the matcher.
+     * @param id the id to use.
+     * @return this builder for chaining.
+     */
+    public final AbstractBuilder setId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    /**
+     * @return {@code true} if the id is not null and not blank.
+     */
+    public final boolean hasId() {
+        return !StringUtils.isBlank(id);
+    }
+
+    /**
+     * @return the id as specified in the builder.
+     */
+    protected String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s with id %s", this.getClass(), id);
+    }
+}  
++------------------------------------------+
+  
+  So we have:
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.configuration.builders.AbstractBuilder;
+
+public class QSCBuilder extends AbstractBuilder. {
+    QSCMatcher build() {
+        return new QSCMatcher(getId());
+    }
+}
++------------------------------------------+
+
+** Registering the builder for use in XML configuration 
+
+  In order to use the matcher in a Rat configuration it has to be registered with the system.  This can be done by creating file with the builder specified and passing it

Review Comment:
   Currently we only have an XML configuration parser but the system is open to new implementations.  I have updated the documentation to reflect XML configuration.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564221716


##########
apache-rat-core/src/main/java/org/apache/rat/document/impl/ArchiveEntryDocument.java:
##########
@@ -37,44 +36,44 @@ public class ArchiveEntryDocument implements Document {
 
     private final MetaData metaData = new MetaData();
 
-    public ArchiveEntryDocument(File file, byte[] contents) throws RatException {
+    public ArchiveEntryDocument(File file, byte[] contents) {
         super();
         name = DocumentImplUtils.toName(file);
         this.contents = contents;
     }
 
+    @Override
     public MetaData getMetaData() {
         return metaData;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public InputStream inputStream() throws IOException {
         return new ByteArrayInputStream(contents);
     }
 
+    @Override
     public boolean isComposite() {
         return DocumentImplUtils.isZipStream(new ByteArrayInputStream(contents));

Review Comment:
   Could we change the interface to internally wrap/add the ByteArrayInputStream in isZipStream() and autoclose it with a tryWithresources construct?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564525024


##########
apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/impl/base/XmlWriter.java:
##########
@@ -525,24 +548,36 @@ private void writeAttributeContent(CharSequence content) throws IOException {
      */
     @Override
     public IXmlWriter content(CharSequence content) throws IOException {
-        if (elementNames.isEmpty()) {
-            if (elementsWritten) {
-                throw new OperationNotAllowedException("Root element has already been closed.");
-            } 
-            throw new OperationNotAllowedException("An element must be opened before content can be written.");
-        }
-        if (inElement) {
-            writer.write('>');
-        }
-        writeBodyContent(content);
+        prepareForData();
+        writeEscaped(content, false);
         inElement = false;
         return this;
     }
 
-    private void writeBodyContent(final CharSequence content) throws IOException {
-        writeEscaped(content, false);
+    
+    /**
+     * Writes content. Calling this method will automatically Note that this method
+     * does not use CDATA.
+     *
+     * @param content the content to write
+     * @return this object
+     * @throws OperationNotAllowedException if called before any call to
+     * {@link #openElement} or after the first element has been closed
+     */
+    @Override
+    public IXmlWriter cdata(CharSequence content) throws IOException {
+        prepareForData();
+        StringBuilder sb = new StringBuilder(content);
+        int found;
+        while (-1 != (found = sb.indexOf("]]>"))) {
+            sb.replace(found, found+3, "<!- Rat removed CDATA closure here ->");

Review Comment:
   It was supposed to be a real comment, though it is in the middle of a CDATA block.
   Perhaps I should have inserted a new CDATA block start after the closure rather than removing the original cdata block.
   
   The issure arises when samples from XML document include an ending CDATA tag.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564977476


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");

Review Comment:
   Initially I thought of being able to use one of the Matchers provided within this PR - shouldn't I be able to "concatenate" matchers, such as ..... (pseudocode only):
   
   AndMatcher.match(TextMatcher.contains("quality"), TextMatcher.contains("speed"), TextMatcher.contains("cost")) 
   
   But maybe it is just too late now ;) and I misunderstood the example or above matchers in the code.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1567942299


##########
apache-rat-tasks/src/test/resources/antunit/report-bad-configurations.xml:
##########
@@ -59,7 +58,7 @@
   </target>
 
   <target name="testNoStylesheet">
-    <rat:report format="styled">
+    <rat:report styleReport="styled">

Review Comment:
   I guess we should a not about the deprecation and the new attribute in:
   https://github.com/apache/creadur-rat/blob/master/apache-rat-tasks/src/site/apt/report.apt



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564496622


##########
apache-rat-core/src/main/java/org/apache/rat/license/LicenseSetFactory.java:
##########
@@ -220,5 +221,5 @@ public static ILicense search(ILicense target, SortedSet<ILicense> licenses) {
         SortedSet<ILicense> part = licenses.tailSet(target);
         return (!part.isEmpty() && part.first().compareTo(target) == 0) ? part.first() : null;

Review Comment:
   ILicense does not override `equals` but does implement comparable, so `equals` may not always work as expected.  A null target will throw a null pointer exception.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1565985468


##########
apache-rat-tasks/pom.xml:
##########
@@ -105,7 +105,7 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
+      <!--<plugin>

Review Comment:
   I forgot to re-enable them. 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564538194


##########
apache-rat-core/src/test/java/org/apache/rat/analysis/matchers/AbstractMatcherTest.java:
##########
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.analysis.matchers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Locale;
+
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.analysis.IHeaders;
+
+public class AbstractMatcherTest {
+
+    private IHeaders dummyHeader = makeHeaders(null, null);
+
+    protected void assertValues(IHeaderMatcher target, boolean... values) {
+        for (int i = 0; i < values.length; i++) {
+            final int idx = i;

Review Comment:
   do we need this assignment due to the lambda or can we use the counter/i instead?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564536412


##########
apache-rat-core/src/test/java/org/apache/rat/ReportTest.java:
##########
@@ -55,9 +61,9 @@ public void testDefaultConfiguration() throws ParseException, IOException {
 
     @Test
     public void testOutputOption() throws Exception {
-        CommandLine cl = new DefaultParser().parse(Report.buildOptions(), new String[]{ "-o", "target/test" });
+        CommandLine cl = new DefaultParser().parse(Report.buildOptions(), new String[] { "-o", "target/test" });
         ReportConfiguration config = Report.createConfiguration("target/test-classes/elements", cl);
-        Reporter.report(config);
+        new Reporter(config).output();
         File output = new File("target/test");

Review Comment:
   Should we use jUnit Testfolders here instead?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564966381


##########
apache-rat-tasks/src/test/resources/antunit/report-bad-configurations.xml:
##########
@@ -59,7 +58,7 @@
   </target>
 
   <target name="testNoStylesheet">
-    <rat:report format="styled">
+    <rat:report styleReport="styled">

Review Comment:
   Does that mean we need more docs about how to use RAT within the Ant sphere? Are these changes similar to the unintendedly breaking changes that were introduced with 0.16.0?
   https://creadur.apache.org/rat/apache-rat-tasks/index.html
   https://creadur.apache.org/rat/apache-rat-tasks/report.html



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555658668


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/matchers/CopyrightMatcher.java:
##########
@@ -104,13 +139,37 @@ public CopyrightMatcher(String id, String start, String stop, String owner) {
         }
     }
 
+    /**
+     * Gets the start date of the copyright.
+     * @return the start date of the copyright or {@code null} if not set
+     */
+    public String getStart() {
+        return start;
+    }
+
+    /**
+     * Gets the end date of the copyright.
+     * @return the end date of the copyright or {@code null} if not set
+     */
+    public String getEnd() {
+        return end;
+    }
+
+    /**
+     * Gets the owner of the copyright.
+     * @return the owner of the copyright or {@code null} if not set
+     */
+    public String getOwner() {
+        return owner;
+    }
+
     @Override
-    protected boolean doMatch(String line) {
-        String lowerLine = line.toLowerCase();
-        if (lowerLine.contains("copyright") || lowerLine.contains("(c)") || line.contains("©")) {
-            Matcher matcher = COPYRIGHT_PATTERN.matcher(line);
+    public boolean matches(IHeaders headers) {
+        String lowerLine = headers.raw().toLowerCase();
+        if (lowerLine.contains("copyright") || lowerLine.contains("(c)") || lowerLine.contains("©")) {

Review Comment:
   Would it make sense to match &copy; as well in case of HTML files?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#issuecomment-2042164066

   **Builder changes:**
    * Matcher Builders now return specific type, not the IHeaderMatcher but a subclass of that.
    
   **Matcher changes:**
    * removed state tracking code.
    * added ConfigComponent annotations to describe the matcher and it properties.
    * in some cases added getter methods to retrieve property values.
   
   **Metadata / ClaimStatistic changes**
     Complete rewrite to simplify setting and getting values (`Metadata`) and to track those values (`ClaimStatistic`)
     
   **AbstractClaimReporter**
    * Changed to use Document.Type and Metadata.
    * Significant simplification.
    
   **ClaimAggregator**
    * modified to use Document.Type and new ClaimStatistic api.
    
   **SimpleXmlClaimReporter **
   
    * modified to handle multiple licenses for single document.
    
    
   **ILicenseFamily  changes:**
   
   Added definitions for Generated and Unknown family categories so that they are defined in one place.
   
   **ILicenseChanges**
   
   Removed `derivedfrom` attribute as it was added recently and unused.
     
   **IXmlWriter / XMLWriter changes**
   
    * added cdata method
    
   **Should change**
   
   Remove `ToNameTransformer` as it is not used and not part of the API
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1566000528


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 
+ scope of this document.  In this document we will address how to define licenses in the default XML format.
+ 
+ The XML document has a root node named "rat-config" which comprises 4 major sections: "Families", 
+ "Licenses", "Approved" and "Matchers".
+ 
+* Families
+ 
+ Families are groups that define licenses that share similarities.  Each family has an id and a name, and example
+ of an entry in this section is
+ 
++------------------------------------------+
+ <rat-config>
+    <families>
+        <family id="AL" name="Apache License Version 2.0" />
+    </families>
+ </rat-config>
++------------------------------------------+
+ 
+* Matchers
+
+ Matchers define tests that check the contents of files for specific patterns.  Matchers are defined in Java
+ code and are required to have Builder classes that build them.  There is {{{./matcher_def.html}additional documentation 
+ explaining how to create new Matchers}}.  In the XML document Matchers are identified by the "matcher" element that has
+ a single "class" property.  The value of the "class" property is the fully qualified class name that 
+ identifies a Builder class.  An example of a matchers entry is
+ 
++------------------------------------------+
+ <rat-config>
+    <matchers>
+        <matcher class="org.apache.rat.configuration.builders.AnyBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.SpdxBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.TextBuilder" />
+    </matcher>
+ </rat-config>
++------------------------------------------+
+ 
+* Licenses
+
+ License elements have three properties: "family", "id", and "name". The family property must refer to
+ the "id" of a family element.  The family element can be defined in the current document or in another
+ included document.  It has to exist by the time all the configuration files are read.  The "id" element
+ is optional, if it is not provided the id will be set to the id of the associated family.  However, the 
+ "id" property must be unique across all licenses.  The "name" property is also optional.  If not specified
+ the name of the associated family will be used.  It is recommened that each license have a unique name

Review Comment:
   "license have" is the future perfect tense (I think that is what it is called. "license has" would be past perfect.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555626922


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/LicenseCollection.java:
##########
@@ -22,33 +22,37 @@
 import java.util.Collections;
 
 import org.apache.rat.analysis.matchers.AbstractMatcherContainer;
+import org.apache.rat.config.parameters.Description;
 import org.apache.rat.license.ILicense;
 import org.apache.rat.license.ILicenseFamily;
 
 /**
- * A collection of ILicenses that acts as a single License for purposes of Analysis.
+ * A collection of ILicenses that acts as a single License for purposes of
+ * Analysis.
  * <p>
- * This class process each license in turn on each {@code matches(String)} call.  When a match is found the 
- * ILicenseFamily for the matching license is captured and used as the family for this license. If no matching 
- * license has been found the default {@code dummy} license category is used.
+ * This class process each license in turn on each {@code matches(String)} call.

Review Comment:
   typo: processes instead of process



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555989822


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Description.java:
##########
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.parameters;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.rat.ConfigurationException;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.utils.Log;
+
+/**
+ * A description of a component.
+ */
+public class Description {
+    /** The type of component this describes */
+    private final Type type;
+    /**
+     * The common name for the component. Set by ConfigComponent.name() or
+     * class/field name.
+     */
+    private final String name;
+    /** The description for the component */
+    private final String desc;
+    /** The class of the getter/setter parameter */
+    private final Class<?> childClass;
+    /** True if the getter/setter expects a collection of childClass objects */
+    private final boolean isCollection;
+    /**
+     * a map of name to Description for all the components that are children the
+     * described component
+     */
+    private final Map<String, Description> children;
+
+    /**
+     * Constructor.
+     * 
+     * @param type the type of the component.
+     * @param name the name of the component.
+     * @param desc the description of the component.
+     * @param isCollection true if the getter/setter expects a collection
+     * @param childClass the class for expected for the getter/setter.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.
+     */
+    public Description(Type type, String name, String desc, boolean isCollection, Class<?> childClass,
+            Collection<Description> children) {
+        this.type = type;
+        this.name = name;
+        this.desc = desc;
+        this.isCollection = isCollection;
+        this.childClass = childClass;
+        this.children = new TreeMap<>();
+        if (children != null) {
+            children.forEach(d -> {
+                this.children.put(d.name, d);
+            });
+        }
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param configComponent the configuration component
+     * @param isCollection the collection flag.
+     * @param childClass the type of object that the method getter/setter expects.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.
+     */
+    public Description(ConfigComponent configComponent, boolean isCollection, Class<?> childClass,
+            Collection<Description> children) {
+        this(configComponent.type(), configComponent.name(), configComponent.desc(), isCollection, childClass,
+                children);
+    }
+
+    /**
+     * Gets the type of the component.
+     * 
+     * @return the component type.
+     */
+    public Type getType() {
+        return type;
+    }
+
+    /**
+     * Get the isCollection flag.
+     * 
+     * @return true if this is a collection.
+     */
+    public boolean isCollection() {
+        return isCollection;
+    }
+
+    /**
+     * Get the class of the objcts for the getter/setter.
+     * 
+     * @return the getter/setter param class.
+     */
+    public Class<?> getChildType() {
+        return childClass;
+    }
+
+    /**
+     * Gets the common name for the matcher. (e.g. 'text', 'spdx', etc.) May not be
+     * null.
+     * 
+     * @return The common name for the item being inspected.
+     */
+    public String getCommonName() {
+        return name;
+    }
+
+    /**
+     * Gets the description of descriptive text for the component. May be an empty
+     * string or null.
+     * 
+     * @return the descriptive text;
+     */
+    public String getDescription() {
+        return desc;
+    }
+
+    /**
+     * Retrieve the value of a the described parameter from the specified object.
+     * 
+     * If the parameter is a collection return {@code null}.
+     * 
+     * @param log the Log to log issues to. 
+     * @param object the object that contains the value.
+     * @return the string value.
+     */
+    public String getParamValue(Log log, Object object) {
+        if (isCollection) {
+            return null;
+        }
+        try {
+            Object val = getter(object.getClass()).invoke(object);
+            return val == null ? null : val.toString();
+        } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException | NoSuchMethodException
+                | SecurityException e) {
+            log.error(System.err.format("Can not retrieve value for '%s' from %s\n", name, object.getClass().getName()),
+                    e);
+            return null;
+        }
+    }
+
+    /**
+     * Gets a map of the parameters that the object contains. For example Copyright
+     * has 'start', 'stop', and 'owner' parameters. Some IHeaderMatchers have simple
+     * text values (e.g. 'regex' or 'text' types) these should list an unnamed
+     * parameter (empty string) with the text value.
+     * 
+     * @return the map of parameters to the objects that represent them.
+     */
+    public Map<String, Description> getChildren() {
+        return children;
+    }
+
+    /**
+     * Get all the children of a specific type
+     * 
+     * @param type the type to return
+     * @return the collection of children of the specified type.
+     */
+    public Collection<Description> childrenOfType(Type type) {
+        return children.values().stream().filter(d -> d.type == type).collect(Collectors.toList());
+    }
+
+    private String methodName(String prefix) {
+        return prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
+    }
+
+    /**
+     * Returns the getter for the component in the specified class.
+     * 
+     * @param clazz the Class to get the getter from.
+     * @return the getter Method.
+     * @throws NoSuchMethodException if the class does not have the getter.
+     * @throws SecurityException if the getter can not be accessed.
+     */
+    public Method getter(Class<?> clazz) throws NoSuchMethodException, SecurityException {
+        return clazz.getMethod(methodName("get"));
+    }
+
+    /**
+     * Returns the setter for the component in the specified class. Notes:
+     * <ul>
+     * <li>License can not be set in components. They are top level components.</li>
+     * <li>Matcher expects an "add" method that accepts an
+     * IHeaderMatcher.Builder.</li>
+     * <li>Parameter expects a {@code set(String)} method.</li>
+     * <li>Unlabeled expects a {@code set(String)} method.</li>
+     * <li>BuilderParam expects a {@code set} method that takes a
+     * {@code childeClass} argument.</li>
+     * </ul>
+     * 
+     * @param clazz the Class to get the getter from, generally a Builder class..
+     * @return the getter Method.
+     * @throws NoSuchMethodException if the class does not have the getter.
+     * @throws SecurityException if the getter can not be accessed.
+     */
+    public Method setter(Class<?> clazz) throws NoSuchMethodException, SecurityException {
+        switch (type) {
+        case License:
+            throw new NoSuchMethodException("Can not set a License as a child");
+        case Matcher:
+            return clazz.getMethod("add", IHeaderMatcher.Builder.class);
+        case Parameter:
+        case Unlabeled:
+            return clazz.getMethod(methodName("set"), String.class);
+        case BuilderParam:
+            return clazz.getMethod(methodName("set"), childClass);
+        }
+        // should not happen
+        throw new IllegalStateException("Type " + type + " not valid.");
+    }
+
+    private void callSetter(Log log, Description description, IHeaderMatcher.Builder builder, String value) {
+        try {
+            description.setter(builder.getClass()).invoke(builder, value);
+        } catch (NoSuchMethodException e) {
+            String msg = String.format("No setter for '%s' on %s", description.getCommonName(), builder.getClass().getCanonicalName()); 
+            log.error(msg);
+            throw new ConfigurationException(msg);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                |  SecurityException e) {
+            String msg = String.format("can not call setter for '%s' on %s", description.getCommonName(), builder.getClass().getCanonicalName());

Review Comment:
   Unable to instead of cannot? Not sure where this message is shown.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1554886994


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*

Review Comment:
   The functionality in this class should be in an XMLConfigurationWriter that this class will use to deserialize the configuration.



##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Component.java:
##########
@@ -0,0 +1,48 @@
+package org.apache.rat.config.parameters;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Interface that marks a configuration component like a License or Matcher.
+ *
+ */
+public interface Component {
+    /** Types of components */
+    public enum Type {
+        /** A License, the top level component. May not be used as a child of any component type. */
+        License,
+        /** A Matcher */
+        Matcher,
+        /** A Parameter for example the "id" parameter found in every component */
+        Parameter,
+        /** A parameter without a name.  Generally this is a value for the item.  For example the enclosed matchers in the "or" license. */
+        Unlabeled,

Review Comment:
   this type mixes presentation with functionality.  It should be removed and specific display issues addressed in the format serializers/deserializers
   



##########
apache-rat-core/src/main/java/org/apache/rat/Documentation.java:
##########
@@ -0,0 +1,152 @@
+/*

Review Comment:
   This class should be placed in the apache-rat-tools project and documented .



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564252525


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {
+                        notes = desc;
+                    } else {
+                        writeAttribute(desc, component);
+                    }
+                }
+                for (Description desc : description.childrenOfType(Component.Type.BuilderParam)) {
+                    if ("family".equals(desc.getCommonName())) {
+                        try {
+                            ILicenseFamily family = (ILicenseFamily) desc.getter(component.getClass())
+                                    .invoke(component);
+                            if (family != null) {
+                                writer.attribute("family", family.getFamilyCategory().trim());
+                            }
+                        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
+                                | InvocationTargetException | SecurityException e) {
+                            configuration.getLog().error(e.toString());
+                        }
+                    }
+                }
+                // end of attributes
+                if (notes != null && StringUtils.isNotBlank(notes.getParamValue(configuration.getLog(), component))) {
+                    writeComment(notes);
+                    writer.openElement(notes.getCommonName());
+                    writeContent(notes, component);
+                    writer.closeElement();
+                }
+                for (Description desc : description.childrenOfType(Component.Type.Unlabeled)) {
+                    writeDescription(desc, component);
+                }
+                writer.closeElement();
+                break;
+            case Parameter:
+                if ("id".equals(description.getCommonName())) {
+                    try {
+                        String idValue = description.getParamValue(configuration.getLog(), component);
+                        // if a UUID skip it.
+                        if (idValue != null) {
+                            UUID.fromString(idValue.toString());
+                            return;

Review Comment:
   Does this leave broken XML? Maybe I do not understand it correctly ..... or does it just not write any thing as parameters do not have descriptions?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564980464


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface
+interface Builder {
+    /**
+     * Build the IHeaderMatcher.
+     * 
+     * Implementations of this interface should return a specific child class of IHeaderMatcher.
+     * 
+     * @return a new IHeaderMatcher.
+     */
+    IHeaderMatcher build();
+
+    /**
+     * Gets the class that is build by this builder.
+     * @return The class that is build by this builder.
+     */
+    default Class<?> builtClass() throws SecurityException {
+        try {
+            return this.getClass().getMethod("build").getReturnType();
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+        }
+    }
+
+    /**
+     * Gets the Description for this builder.
+     * @return The description of the builder 
+     */
+    default Description getDescription() {
+        Class<?> clazz = builtClass();
+        if (clazz == IHeaderMatcher.class) {
+            throw new ImplementationException(String.format(
+                    "Class %s must implement built() method to return a child class of IHeaderMatcher", 
+                    this.getClass()));
+        }
+        return DescriptionBuilder.buildMap(clazz);
+    }
+}
++------------------------------------------+
+
+  The work of handling the Id and some other tasks is handled by the AbstractBuilder.
+  
++------------------------------------------+
+public abstract class AbstractBuilder implements IHeaderMatcher.Builder {
+
+    private String id;
+
+    /**
+     * Protected empty constructor.
+     */
+    protected AbstractBuilder() {
+    }
+
+    /**
+     * Set the id for the matcher.
+     * @param id the id to use.
+     * @return this builder for chaining.
+     */
+    public final AbstractBuilder setId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    /**
+     * @return {@code true} if the id is not null and not blank.
+     */
+    public final boolean hasId() {
+        return !StringUtils.isBlank(id);
+    }
+
+    /**
+     * @return the id as specified in the builder.
+     */
+    protected String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s with id %s", this.getClass(), id);
+    }
+}  
++------------------------------------------+
+  
+  So we have:
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.configuration.builders.AbstractBuilder;
+
+public class QSCBuilder extends AbstractBuilder. {
+    QSCMatcher build() {
+        return new QSCMatcher(getId());
+    }
+}
++------------------------------------------+
+
+** Registering the builder for use in XML configuration 
+
+  In order to use the matcher in a Rat configuration it has to be registered with the system.  This can be done by creating file with the builder specified and passing it
+  to the command line runner as a license ( "--licenses" option) file.  The XML parser will accept "<QSC>" as the matcher in license definitions. Since this is a joke license 
+  we should create a joke family to contain any such licenses and a QSC license that uses the QSC matcher.  The new license file now looks like:
+
++------------------------------------------+
+<rat-config>
+    <families>
+        <family id="Joke" name="A joke license" />
+    </families>
+    <licenses>
+        <license family="Joke" id="QSC" name="The QSC license">
+            <qsc/>
+        </license>
+    </licenses>
+    <matchers>
+        <matcher class="com.example.ratMatcher.QSCBuilder" />
+    </matchers>
+</rat-config>
++------------------------------------------+
+
+  If the license entry did not have an "id" attribute its ID would be the same as the family.
+
+* A more complex example
+
+ In many cases it is necessary to set properties on the matcher.  So let's write a generalized version of the QSC matcher that accepts any 3 strings and triggers if all 3 are found
+ in the header.
+
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "TPM", desc = "Checks that the three string are found in the header")
+public class TPMatcher extends AbstraactHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The first parameter")
+    private final String one;
+    
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The second parameter")
+    private final String two;
+    
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The third parameter")
+    private final String three;
+
+    public TPMatcher(String id, String one, String two, String three) { 
+        super(id);
+        if (StringUtils.isEmpthy(one) || StringUtils.isEmpty(two) || StringUtils.isEmpty(three) {
+            throw new ConfigurationException( "None of the three properties (one, two, or three) may be empty");
+        }
+        this.one = one;
+        this.two = two;
+        this.three = three;
+    }
+    
+    public String getOne() { return one; }
+
+    public String getThree() { return two; }
+
+    public String getTwo() { return three; }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains(one) && text.contains(two) && text.contains(three);
+    }
+}
++------------------------------------------+
+
+ The ComponentConfigurations with the parameter type indicate that the members specify properties of the component.  The Matcher must have a "get" method for each parameter and the builder
+ must have a corresponding "set" method.  The names of the methods and the attributes in the XML paarser can be changed by adding a 'name' attribute to the ConfigComponent.
+
+ The builder now looks like:
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.configuration.builders.AbstractBuilder;
+
+public class TPBuilder extends AbstractBuilder {
+
+    private String one;
+    
+    private String two;
+    
+    private String three;
+
+    TPMatcher build() {
+        return new TPMatcher(one, two, three);
+    }
+    
+    public TPBuilder setOne(String one) { this.one = one; }
+
+    public TPBuilder setTwo(String two) { this.two = two; }
+
+    public TPBuilder setThree(String three) { this.three = three; }
+}
++------------------------------------------+
+
+ And the new license file looks like:
+
++------------------------------------------+
+<rat-config>
+    <families>
+        <family id="Joke" name="A joke license" />
+    </families>
+    <licenses>
+        <license family="Joke" id="QSC" name="The QSC license">
+            <qsc/>
+        </license>
+        <license family="Joke" id="TPM" name="The TPM Check">
+            <tpm one="once" two="upon" three="time">
+        </license>
+    </licenses>
+    <matchers>
+        <matcher class="com.example.ratMatcher.QSCBuilder" />
+        <matcher class="com.example.ratMatcher.TPBuilder" />
+    </matchers>
+</rat-config>
++------------------------------------------+
+
+* Embedded matchers.
+
+ It is possible to create matchers that embed other matchers.  The examples in the codebase are the "All", "Any" and "Not" matchers and their associated builders.

Review Comment:
   Could we link to the three matchers in Rat (Gitbox):
   * All
   * Any
   * Not
   
   I'd assume that anyone wanting to add new ones would like to take a closer look at these base matchers.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564979233


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface
+interface Builder {
+    /**
+     * Build the IHeaderMatcher.
+     * 
+     * Implementations of this interface should return a specific child class of IHeaderMatcher.
+     * 
+     * @return a new IHeaderMatcher.
+     */
+    IHeaderMatcher build();
+
+    /**
+     * Gets the class that is build by this builder.
+     * @return The class that is build by this builder.
+     */
+    default Class<?> builtClass() throws SecurityException {
+        try {
+            return this.getClass().getMethod("build").getReturnType();
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+        }
+    }
+
+    /**
+     * Gets the Description for this builder.
+     * @return The description of the builder 
+     */
+    default Description getDescription() {
+        Class<?> clazz = builtClass();
+        if (clazz == IHeaderMatcher.class) {
+            throw new ImplementationException(String.format(
+                    "Class %s must implement built() method to return a child class of IHeaderMatcher", 
+                    this.getClass()));
+        }
+        return DescriptionBuilder.buildMap(clazz);
+    }
+}
++------------------------------------------+
+
+  The work of handling the Id and some other tasks is handled by the AbstractBuilder.
+  
++------------------------------------------+
+public abstract class AbstractBuilder implements IHeaderMatcher.Builder {
+
+    private String id;
+
+    /**
+     * Protected empty constructor.
+     */
+    protected AbstractBuilder() {
+    }
+
+    /**
+     * Set the id for the matcher.
+     * @param id the id to use.
+     * @return this builder for chaining.
+     */
+    public final AbstractBuilder setId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    /**
+     * @return {@code true} if the id is not null and not blank.
+     */
+    public final boolean hasId() {
+        return !StringUtils.isBlank(id);
+    }
+
+    /**
+     * @return the id as specified in the builder.
+     */
+    protected String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s with id %s", this.getClass(), id);
+    }
+}  
++------------------------------------------+
+  
+  So we have:
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.configuration.builders.AbstractBuilder;
+
+public class QSCBuilder extends AbstractBuilder. {
+    QSCMatcher build() {
+        return new QSCMatcher(getId());
+    }
+}
++------------------------------------------+
+
+** Registering the builder for use in XML configuration 
+
+  In order to use the matcher in a Rat configuration it has to be registered with the system.  This can be done by creating file with the builder specified and passing it
+  to the command line runner as a license ( "--licenses" option) file.  The XML parser will accept "<QSC>" as the matcher in license definitions. Since this is a joke license 
+  we should create a joke family to contain any such licenses and a QSC license that uses the QSC matcher.  The new license file now looks like:
+
++------------------------------------------+
+<rat-config>
+    <families>
+        <family id="Joke" name="A joke license" />
+    </families>
+    <licenses>
+        <license family="Joke" id="QSC" name="The QSC license">
+            <qsc/>
+        </license>
+    </licenses>
+    <matchers>
+        <matcher class="com.example.ratMatcher.QSCBuilder" />
+    </matchers>
+</rat-config>
++------------------------------------------+
+
+  If the license entry did not have an "id" attribute its ID would be the same as the family.
+
+* A more complex example
+
+ In many cases it is necessary to set properties on the matcher.  So let's write a generalized version of the QSC matcher that accepts any 3 strings and triggers if all 3 are found
+ in the header.
+
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "TPM", desc = "Checks that the three string are found in the header")
+public class TPMatcher extends AbstraactHeaderMatcher {

Review Comment:
   Typo: AbstractHeaderMatcher



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564235828


##########
apache-rat-core/src/main/java/org/apache/rat/license/ILicense.java:
##########
@@ -22,42 +22,58 @@
 import java.util.Objects;
 import java.util.SortedSet;
 
+import org.apache.rat.ConfigurationException;
 import org.apache.rat.analysis.IHeaderMatcher;
 
 /**
  * The definition of a License.
  */
 public interface ILicense extends IHeaderMatcher, Comparable<ILicense> {
     /**
+     * Gets the license family.
      * @return the ILicenseFamily implementation for this license.
      */
     ILicenseFamily getLicenseFamily();
 
     /**
-     * @return the notes associated with this license.  May be null or empty.
+     * Gets the notes associated with the license.
+     * @return the notes associated with this license. May be null or empty.
      */
     String getNotes();
 
     /**
-     * @return the id of a license that this license is derived from. May be null.
-     */
-    String derivedFrom();
-    
-    /**
-     * Returns the name of this license.  If no name was specified then the name of the family is returned.
+     * Returns the name of this license. If no name was specified then the name of
+     * the family is returned.
+     * 
      * @return the name of this license.
      */
     String getName();
 
     /**
+     * Gets the name of the family that this license if part of.
+     * @return the name of the license family that this license is part of.
+     */
+    default String getFamilyName() {
+        return getLicenseFamily().getFamilyName();
+    }
+
+    /**
+     * Get the header matcher for this license.
+     * @return the header matcher for this license.
+     */
+    IHeaderMatcher getMatcher();
+
+    /**
+     * Gets a builder for licenses.
      * @return An ILicense.Builder instance.
      */
     static ILicense.Builder builder() {
         return new Builder();
     }
 
     /**
-     * @return The comparator for used to sort Licenses. 
+     * Gets the comparator for comparing licenses.
+     * @return The comparator for used to sort Licenses.

Review Comment:
   The comparator that is used for sorting licenses.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564214513


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/NotBuilder.java:
##########
@@ -19,24 +19,23 @@
 package org.apache.rat.configuration.builders;
 
 import org.apache.rat.ConfigurationException;
-import org.apache.rat.analysis.IHeaderMatcher;
 import org.apache.rat.analysis.matchers.NotMatcher;
 
 /**
  * A builder for the NotMatcher.
  */
 public class NotBuilder extends ChildContainerBuilder {
-    
+
     @Override
-    public IHeaderMatcher build() {
+    public NotMatcher build() {
         if (children.size() != 1) {
             throw new ConfigurationException("'not' type matcher requires one and only one enclosed matcher");
         }
         return new NotMatcher(getId(), children.get(0).build());
     }
-    
+
     @Override
     public String toString() {
-        return String.format( "NotBuilder: %s", !children.isEmpty() ? children.get(0) : null );
+        return String.format("NotBuilder: %s", !children.isEmpty() ? children.get(0) : null);

Review Comment:
   What is the semantics of an empty NotBuilder? Is it "not empty"? 
   Personally I'd expect an empty notBuilder to be in an illegal state



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1563980407


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Description.java:
##########
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.parameters;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.rat.ConfigurationException;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.utils.Log;
+
+/**
+ * A description of a component.
+ */
+public class Description {
+    /** The type of component this describes */
+    private final Type type;
+    /**
+     * The common name for the component. Set by ConfigComponent.name() or
+     * class/field name.
+     */
+    private final String name;
+    /** The description for the component */
+    private final String desc;
+    /** The class of the getter/setter parameter */
+    private final Class<?> childClass;
+    /** True if the getter/setter expects a collection of childClass objects */
+    private final boolean isCollection;
+    /**
+     * a map of name to Description for all the components that are children the
+     * described component
+     */
+    private final Map<String, Description> children;
+
+    /**
+     * Constructor.
+     * 
+     * @param type the type of the component.
+     * @param name the name of the component.
+     * @param desc the description of the component.
+     * @param isCollection true if the getter/setter expects a collection
+     * @param childClass the class for expected for the getter/setter.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.
+     */
+    public Description(Type type, String name, String desc, boolean isCollection, Class<?> childClass,
+            Collection<Description> children) {
+        this.type = type;
+        this.name = name;
+        this.desc = desc;
+        this.isCollection = isCollection;
+        this.childClass = childClass;
+        this.children = new TreeMap<>();
+        if (children != null) {
+            children.forEach(d -> {
+                this.children.put(d.name, d);
+            });
+        }
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param configComponent the configuration component
+     * @param isCollection the collection flag.
+     * @param childClass the type of object that the method getter/setter expects.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.
+     */
+    public Description(ConfigComponent configComponent, boolean isCollection, Class<?> childClass,
+            Collection<Description> children) {
+        this(configComponent.type(), configComponent.name(), configComponent.desc(), isCollection, childClass,
+                children);
+    }
+
+    /**
+     * Gets the type of the component.
+     * 
+     * @return the component type.
+     */
+    public Type getType() {
+        return type;
+    }
+
+    /**
+     * Get the isCollection flag.
+     * 
+     * @return true if this is a collection.
+     */
+    public boolean isCollection() {
+        return isCollection;
+    }
+
+    /**
+     * Get the class of the objcts for the getter/setter.
+     * 
+     * @return the getter/setter param class.
+     */
+    public Class<?> getChildType() {
+        return childClass;
+    }
+
+    /**
+     * Gets the common name for the matcher. (e.g. 'text', 'spdx', etc.) May not be
+     * null.
+     * 
+     * @return The common name for the item being inspected.
+     */
+    public String getCommonName() {
+        return name;
+    }
+
+    /**
+     * Gets the description of descriptive text for the component. May be an empty
+     * string or null.
+     * 
+     * @return the descriptive text;
+     */
+    public String getDescription() {
+        return desc;
+    }
+
+    /**
+     * Retrieve the value of a the described parameter from the specified object.
+     * 
+     * If the parameter is a collection return {@code null}.
+     * 
+     * @param log the Log to log issues to. 
+     * @param object the object that contains the value.
+     * @return the string value.
+     */
+    public String getParamValue(Log log, Object object) {
+        if (isCollection) {
+            return null;
+        }
+        try {
+            Object val = getter(object.getClass()).invoke(object);
+            return val == null ? null : val.toString();
+        } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException | NoSuchMethodException
+                | SecurityException e) {
+            log.error(System.err.format("Can not retrieve value for '%s' from %s\n", name, object.getClass().getName()),
+                    e);
+            return null;
+        }
+    }
+
+    /**
+     * Gets a map of the parameters that the object contains. For example Copyright
+     * has 'start', 'stop', and 'owner' parameters. Some IHeaderMatchers have simple
+     * text values (e.g. 'regex' or 'text' types) these should list an unnamed
+     * parameter (empty string) with the text value.
+     * 
+     * @return the map of parameters to the objects that represent them.
+     */
+    public Map<String, Description> getChildren() {
+        return children;
+    }
+
+    /**
+     * Get all the children of a specific type
+     * 
+     * @param type the type to return
+     * @return the collection of children of the specified type.
+     */
+    public Collection<Description> childrenOfType(Type type) {
+        return children.values().stream().filter(d -> d.type == type).collect(Collectors.toList());
+    }
+
+    private String methodName(String prefix) {
+        return prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
+    }
+
+    /**
+     * Returns the getter for the component in the specified class.
+     * 
+     * @param clazz the Class to get the getter from.
+     * @return the getter Method.
+     * @throws NoSuchMethodException if the class does not have the getter.
+     * @throws SecurityException if the getter can not be accessed.
+     */
+    public Method getter(Class<?> clazz) throws NoSuchMethodException, SecurityException {
+        return clazz.getMethod(methodName("get"));
+    }
+
+    /**
+     * Returns the setter for the component in the specified class. Notes:
+     * <ul>
+     * <li>License can not be set in components. They are top level components.</li>
+     * <li>Matcher expects an "add" method that accepts an
+     * IHeaderMatcher.Builder.</li>
+     * <li>Parameter expects a {@code set(String)} method.</li>
+     * <li>Unlabeled expects a {@code set(String)} method.</li>
+     * <li>BuilderParam expects a {@code set} method that takes a
+     * {@code childeClass} argument.</li>
+     * </ul>
+     * 
+     * @param clazz the Class to get the getter from, generally a Builder class..
+     * @return the getter Method.
+     * @throws NoSuchMethodException if the class does not have the getter.
+     * @throws SecurityException if the getter can not be accessed.
+     */
+    public Method setter(Class<?> clazz) throws NoSuchMethodException, SecurityException {
+        switch (type) {
+        case License:
+            throw new NoSuchMethodException("Can not set a License as a child");
+        case Matcher:
+            return clazz.getMethod("add", IHeaderMatcher.Builder.class);
+        case Parameter:
+        case Unlabeled:
+            return clazz.getMethod(methodName("set"), String.class);
+        case BuilderParam:
+            return clazz.getMethod(methodName("set"), childClass);
+        }
+        // should not happen
+        throw new IllegalStateException("Type " + type + " not valid.");
+    }
+
+    private void callSetter(Log log, Description description, IHeaderMatcher.Builder builder, String value) {
+        try {
+            description.setter(builder.getClass()).invoke(builder, value);
+        } catch (NoSuchMethodException e) {
+            String msg = String.format("No setter for '%s' on %s", description.getCommonName(), builder.getClass().getCanonicalName()); 
+            log.error(msg);
+            throw new ConfigurationException(msg);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                |  SecurityException e) {
+            String msg = String.format("can not call setter for '%s' on %s", description.getCommonName(), builder.getClass().getCanonicalName());

Review Comment:
   On a 3rd party class if the setter is not public this exception is thrown, or if there is a security manager that restricts the call.  Changed the text to "Unable to call..."



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564978150


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface

Review Comment:
   same as above I'd prefer to directly link to RAT sources/interfaces/classes via Gitbox instead of copy&pasting them here.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564974001


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.

Review Comment:
   Would it make sense to link to the classes within Gitbox? Maybe this helps in case of refactorings as it would yield a 404 .....



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564247820


##########
apache-rat-core/src/main/java/org/apache/rat/policy/DefaultPolicy.java:
##########
@@ -45,6 +46,7 @@ public DefaultPolicy(final Collection<ILicenseFamily> approvedLicenseFamilies) {
 
     /**
      * adds an ILicenseFamily to the list of approved licenses.

Review Comment:
   Typo: Adds an ....



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555623334


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/HeaderCheckWorker.java:
##########
@@ -47,98 +53,103 @@ class HeaderCheckWorker {
 
     private final int numberOfRetainedHeaderLines;
     private final BufferedReader reader;
-    private final ILicense license;
+    private final Collection<ILicense> licenses;
     private final Document document;
 
-    private int headerLinesToRead;
-    private boolean finished = false;
+    /**
+     * Read the input and perform the header check.
+     *
+     * The number of lines indicates how many lines from the top of the file will be read for processing
+     * 
+     * @param reader The reader for the document.
+     * @param numberOfLines the number of lines to read from the header.
+     * @return The IHeaders instance for the header.  
+     * @throws IOException on input failure
+     */
+    public static IHeaders readHeader(BufferedReader reader, int numberOfLines) throws IOException {
+        final StringBuilder headers = new StringBuilder();
+        int headerLinesRead = 0;
+        String line;
+
+        while (headerLinesRead < numberOfLines && (line = reader.readLine()) != null) {
+            headers.append(line).append("\n");
+        }
+        final String raw = headers.toString();
+        final String pruned = FullTextMatcher.prune(raw).toLowerCase(Locale.ENGLISH);
+        return new IHeaders() {
+            @Override
+            public String raw() {
+                return raw;
+            }
+
+            @Override
+            public String pruned() {
+                return pruned;
+            }
+
+            @Override
+            public String toString() {
+                return "HeaderCheckWorker";

Review Comment:
   Should we use HeaderCheckWorker.class.getSimpleName() to make it refactoring-safer?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555355924


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Component.java:
##########
@@ -0,0 +1,48 @@
+package org.apache.rat.config.parameters;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Interface that marks a configuration component like a License or Matcher.
+ *
+ */
+public interface Component {
+    /** Types of components */

Review Comment:
   Remove this interface and move the `getDescription` method to IHeaderMatcher interface.
   Move the enclosed Type enum into Description class.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564250926


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:

Review Comment:
   Reading the usage of these enums I'd prefer to use Uppercase values to not mix it with class names (or confuse readers of the sources ;))



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564254665


##########
apache-rat-core/src/main/java/org/apache/rat/report/claim/impl/ClaimAggregator.java:
##########
@@ -19,84 +19,80 @@
 
 package org.apache.rat.report.claim.impl;
 
+import java.util.Map;
+
+import org.apache.rat.api.Document;
 import org.apache.rat.api.MetaData;
 import org.apache.rat.api.RatException;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
 import org.apache.rat.report.claim.ClaimStatistic;
-
-import java.util.HashMap;
-import java.util.Map;
-
+import org.apache.rat.report.claim.ClaimStatistic.Counter;
 
 /**
- * The aggregator is used to create a numerical statistic
- * of claims.
+ * The aggregator is used to create a numerical statistic of claims.
  */
 public class ClaimAggregator extends AbstractClaimReporter {
     private final ClaimStatistic statistic;
-    private final Map<String, Integer> numsByLicenseFamilyName = new HashMap<>();
-    private final Map<String, Integer> numsByLicenseFamilyCode = new HashMap<>();
-    private final Map<String, Integer> numsByFileType = new HashMap<>();
-    private int numApproved, numUnApproved, numGenerated, numUnknown;
 
-    public ClaimAggregator(ClaimStatistic pStatistic) {
-        statistic = pStatistic;
+    /**
+     * Constructor.
+     * @param statistic The statistic to store the statistics in.
+     */
+    public ClaimAggregator(ClaimStatistic statistic) {
+        this.statistic = statistic;
     }
-    
-    private void incMapValue(Map<String, Integer> pMap, String pKey) {
-        final Integer num = pMap.get(pKey);
-        final int newNum;
+
+    private <T> void incMapValue(Map<T, int[]> map, T key, int value) {
+        final int[] num = map.get(key);
+
         if (num == null) {
-            newNum = 1;
+            map.put(key, new int[] { value });
         } else {
-            newNum = num + 1;
+            num[0] += value;
         }
-        pMap.put(pKey, newNum);
     }
-    
+
     @Override
-    protected void handleDocumentCategoryClaim(String documentCategoryName) {
-        incMapValue(numsByFileType, documentCategoryName);
+    protected void handleDocumentCategoryClaim(Document.Type documentType) {
+        incMapValue(statistic.getDocumentCategoryMap(), documentType, 1);
     }
 
     @Override
-    protected void handleApprovedLicenseClaim(String licenseApproved) {
-        if (MetaData.RAT_APPROVED_LICENSE_VALUE_TRUE.equals(licenseApproved)) {
-            numApproved++;
+    protected void handleApprovedLicenseClaim(MetaData metadata) {
+        incValueMap(statistic.getCounterMap(), ClaimStatistic.Counter.Approved, metadata.approvedLicenses().count());
+        incValueMap(statistic.getCounterMap(), ClaimStatistic.Counter.Unapproved,
+                metadata.unapprovedLicenses().count());
+    }
+
+    private void incValueMap(Map<Counter, int[]> map, Counter key, long value) {

Review Comment:
   Why do we use long here and shorten it to integer internally?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564253245


##########
apache-rat-core/src/main/java/org/apache/rat/report/claim/ClaimStatistic.java:
##########
@@ -19,100 +19,62 @@
 
 package org.apache.rat.report.claim;
 
+import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.rat.api.Document;
+
 
 /**
  * This class provides a numerical overview about
  * the report.
  */
 public class ClaimStatistic {
-    private Map<String, Integer> documentCategoryMap, licenseFamilyCodeMap, licenseFamilyNameMap;
-    private int numApproved, numUnApproved, numGenerated, numUnknown;
-
-    /**
-     * @return Returns the number of files with approved licenses.
-     */
-    public int getNumApproved() {
-        return numApproved;
-    }
-
-    /**
-     * Sets the number of files with approved licenses.
-     * @param pNumApproved number of files with approved licenses.
-     */
-    public void setNumApproved(int pNumApproved) {
-        numApproved = pNumApproved;
-    }
-
-    /**
-     * @return Returns the number of files with unapproved licenses.
-     * <em>Note:</em> This might include files with unknown
-     * licenses.
-     * @see #getNumUnknown()
-     */
-    public int getNumUnApproved() {
-        return numUnApproved;
-    }
-
-    /**
-     * Sets the number of files with unapproved licenses.
-     * @param pNumUnApproved number of files with unapproved licenses.
-     */
-    public void setNumUnApproved(int pNumUnApproved) {
-        numUnApproved = pNumUnApproved;
-    }
-
-    /**
-     * @return Returns the number of generated files.
-     */
-    public int getNumGenerated() {
-        return numGenerated;
-    }
+    /** The counter types */
+    public enum Counter { 

Review Comment:
   Uppercase all enums?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564476180


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/ChildContainerBuilder.java:
##########
@@ -99,11 +102,11 @@ public AbstractBuilder add(Collection<IHeaderMatcher.Builder> children) {
     public List<IHeaderMatcher> getChildren() {
         return children.stream().map(IHeaderMatcher.Builder::build).collect(Collectors.toList());
     }
-    
+
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append( ":");
-        children.stream().map(Object::toString).forEach( x -> sb.append("\n").append(x));
+        StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append(":");
+        children.stream().map(Object::toString).forEach(x -> sb.append("\n").append(x));

Review Comment:
   All output \n have been converted to System.lineSeparator() or String.format based "%n"



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564549846


##########
apache-rat-core/src/test/java/org/apache/rat/analysis/matchers/AbstractMatcherTest.java:
##########
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.analysis.matchers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Locale;
+
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.analysis.IHeaders;
+
+public class AbstractMatcherTest {
+
+    private IHeaders dummyHeader = makeHeaders(null, null);
+
+    protected void assertValues(IHeaderMatcher target, boolean... values) {
+        for (int i = 0; i < values.length; i++) {
+            final int idx = i;

Review Comment:
   assignment needed for the lambda.



##########
apache-rat-core/src/test/java/org/apache/rat/ReportTest.java:
##########
@@ -55,9 +61,9 @@ public void testDefaultConfiguration() throws ParseException, IOException {
 
     @Test
     public void testOutputOption() throws Exception {
-        CommandLine cl = new DefaultParser().parse(Report.buildOptions(), new String[]{ "-o", "target/test" });
+        CommandLine cl = new DefaultParser().parse(Report.buildOptions(), new String[] { "-o", "target/test" });
         ReportConfiguration config = Report.createConfiguration("target/test-classes/elements", cl);
-        Reporter.report(config);
+        new Reporter(config).output();
         File output = new File("target/test");

Review Comment:
   Yes, fixed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564973518


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 
+ scope of this document.  In this document we will address how to define licenses in the default XML format.
+ 
+ The XML document has a root node named "rat-config" which comprises 4 major sections: "Families", 
+ "Licenses", "Approved" and "Matchers".
+ 
+* Families
+ 
+ Families are groups that define licenses that share similarities.  Each family has an id and a name, and example
+ of an entry in this section is
+ 
++------------------------------------------+
+ <rat-config>
+    <families>
+        <family id="AL" name="Apache License Version 2.0" />
+    </families>
+ </rat-config>
++------------------------------------------+
+ 
+* Matchers
+
+ Matchers define tests that check the contents of files for specific patterns.  Matchers are defined in Java
+ code and are required to have Builder classes that build them.  There is {{{./matcher_def.html}additional documentation 
+ explaining how to create new Matchers}}.  In the XML document Matchers are identified by the "matcher" element that has
+ a single "class" property.  The value of the "class" property is the fully qualified class name that 
+ identifies a Builder class.  An example of a matchers entry is
+ 
++------------------------------------------+
+ <rat-config>
+    <matchers>
+        <matcher class="org.apache.rat.configuration.builders.AnyBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.SpdxBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.TextBuilder" />
+    </matcher>
+ </rat-config>
++------------------------------------------+
+ 
+* Licenses
+
+ License elements have three properties: "family", "id", and "name". The family property must refer to
+ the "id" of a family element.  The family element can be defined in the current document or in another
+ included document.  It has to exist by the time all the configuration files are read.  The "id" element
+ is optional, if it is not provided the id will be set to the id of the associated family.  However, the 
+ "id" property must be unique across all licenses.  The "name" property is also optional.  If not specified
+ the name of the associated family will be used.  It is recommened that each license have a unique name
+ as name conflicts make problem determination difficult.
+ 
+ License elements have two child element types.  The first is "notes".  There may be multiple "notes" 
+ child elements.  They are simple text elements that define notes about the license.  The other element
+ is a Matcher type.  A matcher element is defined by a builder in the "matchers" section as described
+ above.  The matchers listed in the example above define the "any", "spdx", and "text" matcher elements.
+ 
+ When defining the license the matcher is required and only one may be defined.  However, there are matchers
+ that accept multiple matcher child nodes.  In the example below the CDDL1 license uses the "any" matcher.
+ The "any" matcher accepts multiple child matchers and will report a match if any of the enclosed matchers
+ report a match. In the example below the "any" matcher has "text" and "spdx" child matchers.  The "text"
+ matcher will match the enclosed text and the "spdx" matcher matches {{{https://spdx.org/licenses/}SPDX}}
+ tags.  The second license defined below is the "ILLUMOS" license.  It shares the same family as the CDDL1
+ license, has its own "id" and "name" properties.  It also has a "note" child element that tells the user
+ that it is a modified CDDL1 license.  The license has a single "text" matcher.
+ 
++------------------------------------------+
+ <rat-config>
+    <licenses>
+        <license family="CDDL1">
+            <any>
+                <text>The contents of this file are subject to the terms of the
+                    Common Development and Distribution License("CDDL") (the
+                    "License"). You may not use this file except in compliance
+                    with the License.</text>
+                <spdx name='CDDL-1.0' />
+            </any>
+        </license>
+
+        <license family="CDDL1" id="ILLUMOS" name="ILLUMOS CDDL1 Derived license">
+            <note>Modified CDDL1 license</note>
+            <text>The contents of this file are subject to the terms of
+                the Common Development and Distribution License (the
+                "License") You may not use this file except in compliance
+                with the License. </text>
+        </license>
+    </licenses>
+ </rat-config>
++------------------------------------------+
+ 
+* Approved 
+ 
+ Approved element lists the approved licenses from this configuration.  It is possible to define licenses
+ that you want to detect but not allow.  If the "approved" element is not present all defined families
+ are considered to be approved.  The approved entry has "family" child entries that have "license_ref"
+ properties that reference the "id" of the family being approved.
+ 
++------------------------------------------+
+ <rat-config>
+    <approved>
+        <family license_ref='AL' />
+    </approved>
+ </rat-config>
++------------------------------------------+
+
+* Listing components
+
+ All the components (Licenses and Matchers) defined in the system can be displayed using the Documentation
+ tool.  To run the too execute:
+
++------------------------------------------+
+java -jar apache-rat-${project.version}.jar org.apache.rat.Documentation

Review Comment:
   Would you mind using the same kind of linking as in 
   https://creadur.apache.org/rat/apache-rat/index.html
   "apache-rat/target/" ? 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564975996


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {

Review Comment:
   Typo: extends AbstractHeaderMatcher



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564978793


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface
+interface Builder {
+    /**
+     * Build the IHeaderMatcher.
+     * 
+     * Implementations of this interface should return a specific child class of IHeaderMatcher.
+     * 
+     * @return a new IHeaderMatcher.
+     */
+    IHeaderMatcher build();
+
+    /**
+     * Gets the class that is build by this builder.
+     * @return The class that is build by this builder.
+     */
+    default Class<?> builtClass() throws SecurityException {
+        try {
+            return this.getClass().getMethod("build").getReturnType();
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+        }
+    }
+
+    /**
+     * Gets the Description for this builder.
+     * @return The description of the builder 
+     */
+    default Description getDescription() {
+        Class<?> clazz = builtClass();
+        if (clazz == IHeaderMatcher.class) {
+            throw new ImplementationException(String.format(
+                    "Class %s must implement built() method to return a child class of IHeaderMatcher", 
+                    this.getClass()));
+        }
+        return DescriptionBuilder.buildMap(clazz);
+    }
+}
++------------------------------------------+
+
+  The work of handling the Id and some other tasks is handled by the AbstractBuilder.
+  
++------------------------------------------+
+public abstract class AbstractBuilder implements IHeaderMatcher.Builder {
+
+    private String id;
+
+    /**
+     * Protected empty constructor.
+     */
+    protected AbstractBuilder() {
+    }
+
+    /**
+     * Set the id for the matcher.
+     * @param id the id to use.
+     * @return this builder for chaining.
+     */
+    public final AbstractBuilder setId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    /**
+     * @return {@code true} if the id is not null and not blank.
+     */
+    public final boolean hasId() {
+        return !StringUtils.isBlank(id);
+    }
+
+    /**
+     * @return the id as specified in the builder.
+     */
+    protected String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s with id %s", this.getClass(), id);
+    }
+}  
++------------------------------------------+
+  
+  So we have:
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.configuration.builders.AbstractBuilder;
+
+public class QSCBuilder extends AbstractBuilder. {
+    QSCMatcher build() {
+        return new QSCMatcher(getId());
+    }
+}
++------------------------------------------+
+
+** Registering the builder for use in XML configuration 
+
+  In order to use the matcher in a Rat configuration it has to be registered with the system.  This can be done by creating file with the builder specified and passing it

Review Comment:
   Maybe the type just needs to be added for clarification purposes.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564978657


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface
+interface Builder {
+    /**
+     * Build the IHeaderMatcher.
+     * 
+     * Implementations of this interface should return a specific child class of IHeaderMatcher.
+     * 
+     * @return a new IHeaderMatcher.
+     */
+    IHeaderMatcher build();
+
+    /**
+     * Gets the class that is build by this builder.
+     * @return The class that is build by this builder.
+     */
+    default Class<?> builtClass() throws SecurityException {
+        try {
+            return this.getClass().getMethod("build").getReturnType();
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+        }
+    }
+
+    /**
+     * Gets the Description for this builder.
+     * @return The description of the builder 
+     */
+    default Description getDescription() {
+        Class<?> clazz = builtClass();
+        if (clazz == IHeaderMatcher.class) {
+            throw new ImplementationException(String.format(
+                    "Class %s must implement built() method to return a child class of IHeaderMatcher", 
+                    this.getClass()));
+        }
+        return DescriptionBuilder.buildMap(clazz);
+    }
+}
++------------------------------------------+
+
+  The work of handling the Id and some other tasks is handled by the AbstractBuilder.
+  
++------------------------------------------+
+public abstract class AbstractBuilder implements IHeaderMatcher.Builder {
+
+    private String id;
+
+    /**
+     * Protected empty constructor.
+     */
+    protected AbstractBuilder() {
+    }
+
+    /**
+     * Set the id for the matcher.
+     * @param id the id to use.
+     * @return this builder for chaining.
+     */
+    public final AbstractBuilder setId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    /**
+     * @return {@code true} if the id is not null and not blank.
+     */
+    public final boolean hasId() {
+        return !StringUtils.isBlank(id);
+    }
+
+    /**
+     * @return the id as specified in the builder.
+     */
+    protected String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s with id %s", this.getClass(), id);
+    }
+}  
++------------------------------------------+
+  
+  So we have:
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.configuration.builders.AbstractBuilder;
+
+public class QSCBuilder extends AbstractBuilder. {
+    QSCMatcher build() {
+        return new QSCMatcher(getId());
+    }
+}
++------------------------------------------+
+
+** Registering the builder for use in XML configuration 
+
+  In order to use the matcher in a Rat configuration it has to be registered with the system.  This can be done by creating file with the builder specified and passing it

Review Comment:
   this can be done by creating a file? What kind of file? XML or configuration file?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564977706


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.

Review Comment:
   typo: so that the



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1563972537


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/LicenseCollection.java:
##########
@@ -22,33 +22,37 @@
 import java.util.Collections;
 
 import org.apache.rat.analysis.matchers.AbstractMatcherContainer;
+import org.apache.rat.config.parameters.Description;
 import org.apache.rat.license.ILicense;
 import org.apache.rat.license.ILicenseFamily;
 
 /**
- * A collection of ILicenses that acts as a single License for purposes of Analysis.
+ * A collection of ILicenses that acts as a single License for purposes of
+ * Analysis.
  * <p>
- * This class process each license in turn on each {@code matches(String)} call.  When a match is found the 
- * ILicenseFamily for the matching license is captured and used as the family for this license. If no matching 
- * license has been found the default {@code dummy} license category is used.
+ * This class process each license in turn on each {@code matches(String)} call.
+ * When a match is found the ILicenseFamily for the matching license is captured
+ * and used as the family for this license. If no matching license has been
+ * found the default {@code dummy} license category is used.
  */
+
 class LicenseCollection extends AbstractMatcherContainer implements ILicense {
 
     private static final ILicenseFamily DEFAULT = ILicenseFamily.builder().setLicenseFamilyCategory("Dummy")

Review Comment:
   Class should have been deleted



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564515299


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {
+                        notes = desc;
+                    } else {
+                        writeAttribute(desc, component);
+                    }
+                }
+                for (Description desc : description.childrenOfType(Component.Type.BuilderParam)) {
+                    if ("family".equals(desc.getCommonName())) {
+                        try {
+                            ILicenseFamily family = (ILicenseFamily) desc.getter(component.getClass())
+                                    .invoke(component);
+                            if (family != null) {
+                                writer.attribute("family", family.getFamilyCategory().trim());
+                            }
+                        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
+                                | InvocationTargetException | SecurityException e) {
+                            configuration.getLog().error(e.toString());
+                        }
+                    }
+                }
+                // end of attributes
+                if (notes != null && StringUtils.isNotBlank(notes.getParamValue(configuration.getLog(), component))) {
+                    writeComment(notes);
+                    writer.openElement(notes.getCommonName());
+                    writeContent(notes, component);
+                    writer.closeElement();
+                }
+                for (Description desc : description.childrenOfType(Component.Type.Unlabeled)) {
+                    writeDescription(desc, component);
+                }
+                writer.closeElement();
+                break;
+            case Parameter:
+                if ("id".equals(description.getCommonName())) {
+                    try {
+                        String idValue = description.getParamValue(configuration.getLog(), component);
+                        // if a UUID skip it.
+                        if (idValue != null) {
+                            UUID.fromString(idValue.toString());
+                            return;

Review Comment:
   All IHeaderMatcher instances have to have a unique ID.  If none is specified we create a time based UUID for the processing run.  This verifies that a UUID is not output as the ID into the XML document.  I suppose there should be a warning to users not to use UUIDs ad matcher ids.  The current code, in XMLConfigurationWriter, handles this a bit differently but it still removes the ID from the XML on output if it is a UUID.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564518136


##########
apache-rat-core/src/main/java/org/apache/rat/report/claim/impl/ClaimAggregator.java:
##########
@@ -19,84 +19,80 @@
 
 package org.apache.rat.report.claim.impl;
 
+import java.util.Map;
+
+import org.apache.rat.api.Document;
 import org.apache.rat.api.MetaData;
 import org.apache.rat.api.RatException;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
 import org.apache.rat.report.claim.ClaimStatistic;
-
-import java.util.HashMap;
-import java.util.Map;
-
+import org.apache.rat.report.claim.ClaimStatistic.Counter;
 
 /**
- * The aggregator is used to create a numerical statistic
- * of claims.
+ * The aggregator is used to create a numerical statistic of claims.
  */
 public class ClaimAggregator extends AbstractClaimReporter {
     private final ClaimStatistic statistic;
-    private final Map<String, Integer> numsByLicenseFamilyName = new HashMap<>();
-    private final Map<String, Integer> numsByLicenseFamilyCode = new HashMap<>();
-    private final Map<String, Integer> numsByFileType = new HashMap<>();
-    private int numApproved, numUnApproved, numGenerated, numUnknown;
 
-    public ClaimAggregator(ClaimStatistic pStatistic) {
-        statistic = pStatistic;
+    /**
+     * Constructor.
+     * @param statistic The statistic to store the statistics in.
+     */
+    public ClaimAggregator(ClaimStatistic statistic) {
+        this.statistic = statistic;
     }
-    
-    private void incMapValue(Map<String, Integer> pMap, String pKey) {
-        final Integer num = pMap.get(pKey);
-        final int newNum;
+
+    private <T> void incMapValue(Map<T, int[]> map, T key, int value) {
+        final int[] num = map.get(key);
+
         if (num == null) {
-            newNum = 1;
+            map.put(key, new int[] { value });
         } else {
-            newNum = num + 1;
+            num[0] += value;
         }
-        pMap.put(pKey, newNum);
     }
-    
+
     @Override
-    protected void handleDocumentCategoryClaim(String documentCategoryName) {
-        incMapValue(numsByFileType, documentCategoryName);
+    protected void handleDocumentCategoryClaim(Document.Type documentType) {
+        incMapValue(statistic.getDocumentCategoryMap(), documentType, 1);
     }
 
     @Override
-    protected void handleApprovedLicenseClaim(String licenseApproved) {
-        if (MetaData.RAT_APPROVED_LICENSE_VALUE_TRUE.equals(licenseApproved)) {
-            numApproved++;
+    protected void handleApprovedLicenseClaim(MetaData metadata) {
+        incValueMap(statistic.getCounterMap(), ClaimStatistic.Counter.Approved, metadata.approvedLicenses().count());
+        incValueMap(statistic.getCounterMap(), ClaimStatistic.Counter.Unapproved,
+                metadata.unapprovedLicenses().count());
+    }
+
+    private void incValueMap(Map<Counter, int[]> map, Counter key, long value) {

Review Comment:
   ClaimAggregator historically tracks integer values.  However we have several cases where we have streams that we call `count()` on.  They return longs.  We could cast them or convert them here.  I have changed this to be an `int` value and cast the stream counts.  I don't think that we will have more than MAX_INT defined licenses categories or licenses.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564520043


##########
apache-rat-core/src/main/java/org/apache/rat/report/claim/impl/xml/SimpleXmlClaimReporter.java:
##########
@@ -140,9 +100,9 @@ public void startReport() throws RatException {
     @Override
     public void endReport() throws RatException {
         try {
-            writer.closeDocument();
+            writer.closeElement();
         } catch (IOException e) {
-            throw new RatException("Cannot close last element", e);
+            throw new RatException("Cannot open start element", e);

Review Comment:
   Stupid log error on my part.  Good catch.  We are indeed closing the element.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555612574


##########
apache-rat-core/src/main/java/org/apache/rat/Documentation.java:
##########
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.builders.AbstractBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+
+/**
+ * Generates text based documentation for Licenses, LicenceFamilies, and Matchers. 
+ * 
+ * Utilizes the same command line as the CLI based Report client so that additional licenses, etc. can be added.
+ *
+ */
+public class Documentation {
+
+    private static final String INDENT = "   ";
+
+    private Documentation() {
+    }
+
+    /**
+     * Output the ReportConfiguration to a writer.
+     * @param cfg The configuration to write.
+     * @param writer the writer to write to.
+     * @throws IOException on error.
+     */
+    public static void output(ReportConfiguration cfg, Writer writer) throws IOException {
+        writer.write(String.format("%n>>>> LICENSES <<<<%n%n"));
+        for (ILicense l : cfg.getLicenses(LicenseFilter.all)) {
+            printLicense(l, writer);
+        }
+
+        writer.write(String.format("%n>>>> MATCHERS (Datatype IHeaderMatcher) <<<<%n%n"));
+        for (Class<? extends AbstractBuilder> mClazz : MatcherBuilderTracker.INSTANCE.getClasses()) {
+            try {
+                AbstractBuilder builder = mClazz.getConstructor().newInstance();
+                printMatcher(DescriptionBuilder.buildMap(builder.builtClass()), writer);
+            } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
+                    | IllegalArgumentException | InvocationTargetException e) {
+                throw new ConfigurationException(
+                        String.format("Can not instantiate matcher builder  %s ", mClazz.getName()), e);
+            }
+        }
+
+        writer.write(String.format("%n>>>> FAMILIES (Datatype ILicenseFamily) <<<<%n%n"));
+        for (ILicenseFamily family : cfg.getLicenseFamilies(LicenseFilter.all)) {
+            printFamily(family, writer);
+        }
+    }
+
+    private static void printFamily(ILicenseFamily family, Writer writer) throws IOException {
+        writer.write(String.format("'%s' - %s%n", family.getFamilyCategory().trim(), family.getFamilyName()));
+    }
+
+    private static void printMatcher(Description matcher, Writer writer) throws IOException {
+        writer.write(String.format("'%s' - %s%n", matcher.getCommonName(), matcher.getDescription()));
+        printChildren(1, matcher.getChildren(), writer);
+
+    }
+
+    private static void printLicense(ILicense license, Writer writer) throws IOException {
+        Description dLicense = license.getDescription();
+        writer.write(String.format("'%s' - %s %n", dLicense.getCommonName(), dLicense.getDescription()));
+        printChildren(1, dLicense.getChildren(), writer);
+    }
+
+    private static void writeIndent(int indent, Writer writer) throws IOException {
+        for (int i = 0; i < indent; i++) {
+            writer.write(INDENT);
+        }
+    }
+
+    private static void printChildren(int indent, Map<String, Description> children, Writer writer) throws IOException {
+        for (Description d : children.values()) {
+            writeIndent(indent, writer);
+            switch (d.getType()) {
+            case Parameter:
+            case BuilderParam:
+                writer.write(String.format("'%s' %s (Datatype: %s%s)%n", d.getCommonName(), d.getDescription(),
+                        d.isCollection() ? "Collection of " : "", d.getChildType().getSimpleName()));
+                break;
+            case Unlabeled:
+                writer.write(String.format("'%s name' %s (Datatype: %s%s)%n", d.getCommonName(), d.getDescription(),
+                        d.isCollection() ? "Collection of " : "", d.getChildType().getSimpleName()));
+                break;
+            case License:
+                // do noting
+                break;
+            case Matcher:
+                writeIndent(indent + 1, writer);
+                writer.write(String.format("%s %s %n", d.isCollection() ? "Collection of " : "A ",
+                        d.getChildType().getSimpleName()));
+                printChildren(indent + 2, d.getChildren(), writer);
+                break;
+            }
+        }
+    }
+
+    /**
+     * Creates the documentation.  Writes to the outpus specified by the -o or --out option.  Defaults to System.out.

Review Comment:
   Typo: output



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564250356


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();

Review Comment:
   Should we extract this into XMLConfigurationReader.RESOURCE here?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564969756


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 
+ scope of this document.  In this document we will address how to define licenses in the default XML format.
+ 
+ The XML document has a root node named "rat-config" which comprises 4 major sections: "Families", 
+ "Licenses", "Approved" and "Matchers".
+ 
+* Families
+ 
+ Families are groups that define licenses that share similarities.  Each family has an id and a name, and example

Review Comment:
   two sentences ? Each family has ..... An example .....



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555908286


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/matchers/SimpleTextMatcher.java:
##########
@@ -19,36 +19,49 @@
 package org.apache.rat.analysis.matchers;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
 
 /**
  * A simple text matching IHeaderMatcher implementation.
  */
-public class SimpleTextMatcher extends AbstractSimpleMatcher {
-    private final String pattern;
+@ConfigComponent(type = Component.Type.Matcher, name = "text", desc = "Matches the enclosed the text")

Review Comment:
   Typo "the enclosed text"



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555955647


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Description.java:
##########
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.parameters;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.rat.ConfigurationException;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.utils.Log;
+
+/**
+ * A description of a component.
+ */
+public class Description {
+    /** The type of component this describes */
+    private final Type type;
+    /**
+     * The common name for the component. Set by ConfigComponent.name() or
+     * class/field name.
+     */
+    private final String name;
+    /** The description for the component */
+    private final String desc;
+    /** The class of the getter/setter parameter */
+    private final Class<?> childClass;
+    /** True if the getter/setter expects a collection of childClass objects */
+    private final boolean isCollection;
+    /**
+     * a map of name to Description for all the components that are children the
+     * described component
+     */
+    private final Map<String, Description> children;
+
+    /**
+     * Constructor.
+     * 
+     * @param type the type of the component.
+     * @param name the name of the component.
+     * @param desc the description of the component.
+     * @param isCollection true if the getter/setter expects a collection
+     * @param childClass the class for expected for the getter/setter.
+     * @param children the collection of descriptions for all the components that
+     * are children the described component.

Review Comment:
   Typo: of the described component



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555953422


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Description.java:
##########
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.parameters;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.rat.ConfigurationException;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.utils.Log;
+
+/**
+ * A description of a component.
+ */
+public class Description {
+    /** The type of component this describes */
+    private final Type type;
+    /**
+     * The common name for the component. Set by ConfigComponent.name() or
+     * class/field name.
+     */
+    private final String name;
+    /** The description for the component */
+    private final String desc;
+    /** The class of the getter/setter parameter */
+    private final Class<?> childClass;
+    /** True if the getter/setter expects a collection of childClass objects */
+    private final boolean isCollection;
+    /**
+     * a map of name to Description for all the components that are children the

Review Comment:
   Typo: children of the ....



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555913066


##########
apache-rat-core/src/main/java/org/apache/rat/api/MetaData.java:
##########
@@ -18,340 +18,128 @@
  */
 package org.apache.rat.api;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Stream;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
 
 /**
  * Data about the document under test..
  */
 public class MetaData {
 
-    public static final String RAT_BASE_URL = "http://org/apache/rat/meta-data";
-    
-    // Document Categories
-    public static final String RAT_URL_DOCUMENT_CATEGORY = RAT_BASE_URL + "#FileCategory";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_GENERATED = "GEN  ";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_UNKNOWN = "?????";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_ARCHIVE = "archive";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_NOTICE = "notice";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_BINARY = "binary";
-    public static final String RAT_DOCUMENT_CATEGORY_VALUE_STANDARD = "standard";
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_GENERATED = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_GENERATED);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_UNKNOWN = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_UNKNOWN);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_ARCHIVE = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_ARCHIVE);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_NOTICE = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_NOTICE);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_BINARY = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_BINARY);
-    public static final Datum RAT_DOCUMENT_CATEGORY_DATUM_STANDARD = new Datum(RAT_URL_DOCUMENT_CATEGORY, RAT_DOCUMENT_CATEGORY_VALUE_STANDARD);
-    
-    // Header Categories
-    public static final String RAT_URL_HEADER_CATEGORY = RAT_BASE_URL + "#HeaderCategory";
-    
-    // License Family Categories
-    public static final String RAT_URL_LICENSE_FAMILY_CATEGORY= RAT_BASE_URL + "#LicenseFamilyCategory";
-    // Shortcuts used in report output, must be exactly 5 characters
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GEN = "GEN  ";
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_UNKNOWN = "?????";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_ASL = "AL   ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_OASIS = "OASIS";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3CD = "W3CD ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3C = "W3C  ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_DOJO = "DOJO ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_TMF = "TMF  ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL1 ="GPL1 ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL2 ="GPL2 ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL3 = "GPL3 ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_MIT = "MIT  ";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_CATEGORY_VALUE_CDDL1 = "CDDL1";
-
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GEN = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_GEN);
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_UNKNOWN = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_UNKNOWN);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_ASL = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_ASL);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_OASIS = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_OASIS);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_W3CD = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3CD);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_W3C = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_W3C);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_DOJO = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_DOJO);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_TMF = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY, RAT_LICENSE_FAMILY_CATEGORY_VALUE_TMF);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GPL1 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL1);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GPL2 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL2);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_GPL3 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_GPL3);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_MIT = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_MIT);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_CATEGORY_DATUM_CDLL1 = new Datum(RAT_URL_LICENSE_FAMILY_CATEGORY,RAT_LICENSE_FAMILY_CATEGORY_VALUE_CDDL1);
-
-    // License Family Standard Names
-    public static final String RAT_URL_LICENSE_FAMILY_NAME= RAT_BASE_URL + "#LicenseFamilyName";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_W3C_SOFTWARE_COPYRIGHT = "W3C Software Copyright";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_W3C_DOCUMENT_COPYRIGHT = "W3C Document Copyright";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_OASIS_OPEN_LICENSE = "OASIS Open License";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_MODIFIED_BSD_LICENSE = "Modified BSD License";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_APACHE_LICENSE_VERSION_2_0 = "Apache License Version 2.0";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_1 =
-            "GNU General Public License, version 1";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_2 =
-            "GNU General Public License, version 2";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_3 =
-            "GNU General Public License, version 3";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_MIT =
-            "The MIT License";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_CDDL1 =
-            "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0";
-    @Deprecated
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_ACADEMIC_FREE_LICENSE_VERSION_2_1 = "Academic Free License, Version 2.1";
-
-    public static final String RAT_LICENSE_FAMILY_NAME_VALUE_UNKNOWN = "?????";
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_W3C_SOFTWARE_COPYRIGHT 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_W3C_SOFTWARE_COPYRIGHT);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_W3C_DOCUMENT_COPYRIGHT 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_W3C_DOCUMENT_COPYRIGHT);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_OASIS_OPEN_LICENSE 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_OASIS_OPEN_LICENSE);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_MODIFIED_BSD_LICENSE 
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_MODIFIED_BSD_LICENSE);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_APACHE_LICENSE_VERSION_2_0
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_APACHE_LICENSE_VERSION_2_0);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_GPL_VERSION_1 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_1);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_GPL_VERSION_2 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_2);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_GPL_VERSION_3 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_GPL_VERSION_3);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_MIT = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_MIT);
-    @Deprecated
-    public static final Datum
-            RAT_LICENSE_FAMILY_NAME_DATUM_CDDL1 = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_CDDL1);
-    @Deprecated
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_ACADEMIC_FREE_LICENSE_VERSION_2_1
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_ACADEMIC_FREE_LICENSE_VERSION_2_1);
+    /** The list of matched licenses */
+    private final SortedSet<ILicense> matchedLicenses;
+    /** The list of License Family Categories that are approved */
+    private final Set<String> approvedLicenses;
 
-    public static final Datum RAT_LICENSE_FAMILY_NAME_DATUM_UNKNOWN
-        = new Datum(RAT_URL_LICENSE_FAMILY_NAME, RAT_LICENSE_FAMILY_NAME_VALUE_UNKNOWN); 
-    
-    // Header sample
-    public static final String RAT_URL_HEADER_SAMPLE = RAT_BASE_URL + "#HeaderSample";
-    
-    // License Approval
-    public static final String RAT_URL_APPROVED_LICENSE = RAT_BASE_URL + "#ApprovedLicense";
-    public static final String RAT_APPROVED_LICENSE_VALUE_TRUE = Boolean.TRUE.toString();
-    public static final String RAT_APPROVED_LICENSE_VALUE_FALSE = Boolean.FALSE.toString();
-    public static final Datum RAT_APPROVED_LICENSE_DATUM_TRUE = new Datum(RAT_URL_APPROVED_LICENSE, RAT_APPROVED_LICENSE_VALUE_TRUE);
-    public static final Datum RAT_APPROVED_LICENSE_DATUM_FALSE = new Datum(RAT_URL_APPROVED_LICENSE, RAT_APPROVED_LICENSE_VALUE_FALSE);
-    @Deprecated
-    public static final Datum RAT_APPROVED_LICENSE_DATIM_TRUE = RAT_APPROVED_LICENSE_DATUM_TRUE;
-    @Deprecated
-    public static final Datum RAT_APPROVED_LICENSE_DATIM_FALSE = RAT_APPROVED_LICENSE_DATUM_FALSE;
-
-    /** 
-     * Only likely to be a small quantity of data 
-     * so trade some performance for simplicity.
-     */
-    private final List<Datum> data;
+    private Document.Type documentType;
+    private String sampleHeader;
 
     /**
      * Create metadata without a content type.
      */
     public MetaData() {
-        this.data = new ArrayList<>(16);
+        this.matchedLicenses = new TreeSet<>();
+        this.approvedLicenses = new HashSet<>();
     }
-    
+
     /**
-     * Add the license information to the metadata.
-     * @param license the license to add metadata for.
+     * Determines if a mathcing license has been detected.

Review Comment:
   Typo: matching



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1556240399


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/HeaderCheckWorker.java:
##########
@@ -47,98 +53,103 @@ class HeaderCheckWorker {
 
     private final int numberOfRetainedHeaderLines;
     private final BufferedReader reader;
-    private final ILicense license;
+    private final Collection<ILicense> licenses;
     private final Document document;
 
-    private int headerLinesToRead;
-    private boolean finished = false;
+    /**
+     * Read the input and perform the header check.
+     *
+     * The number of lines indicates how many lines from the top of the file will be read for processing
+     * 
+     * @param reader The reader for the document.
+     * @param numberOfLines the number of lines to read from the header.
+     * @return The IHeaders instance for the header.  
+     * @throws IOException on input failure
+     */
+    public static IHeaders readHeader(BufferedReader reader, int numberOfLines) throws IOException {
+        final StringBuilder headers = new StringBuilder();
+        int headerLinesRead = 0;
+        String line;
+
+        while (headerLinesRead < numberOfLines && (line = reader.readLine()) != null) {
+            headers.append(line).append("\n");
+        }
+        final String raw = headers.toString();
+        final String pruned = FullTextMatcher.prune(raw).toLowerCase(Locale.ENGLISH);

Review Comment:
   It probably will, but it is the current functionality.  Not sure how we should fix it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555362330


##########
apache-rat-core/src/main/java/org/apache/rat/api/RatException.java:
##########
@@ -19,9 +19,20 @@
 package org.apache.rat.api;
 
 public class RatException extends Exception {
+    
+    public static RatException asRatException(Exception e) {
+        return e instanceof RatException ? (RatException) e : new RatException(e);
+    }
 
     private static final long serialVersionUID = 4940711222435919034L;
 
+    public static RatException makeInstance(Exception e) {

Review Comment:
   remove this infavor of the `asRatException` method



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555621867


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/HeaderCheckWorker.java:
##########
@@ -47,98 +53,103 @@ class HeaderCheckWorker {
 
     private final int numberOfRetainedHeaderLines;
     private final BufferedReader reader;
-    private final ILicense license;
+    private final Collection<ILicense> licenses;
     private final Document document;
 
-    private int headerLinesToRead;
-    private boolean finished = false;
+    /**
+     * Read the input and perform the header check.
+     *
+     * The number of lines indicates how many lines from the top of the file will be read for processing
+     * 
+     * @param reader The reader for the document.
+     * @param numberOfLines the number of lines to read from the header.
+     * @return The IHeaders instance for the header.  
+     * @throws IOException on input failure
+     */
+    public static IHeaders readHeader(BufferedReader reader, int numberOfLines) throws IOException {
+        final StringBuilder headers = new StringBuilder();
+        int headerLinesRead = 0;
+        String line;
+
+        while (headerLinesRead < numberOfLines && (line = reader.readLine()) != null) {
+            headers.append(line).append("\n");
+        }
+        final String raw = headers.toString();
+        final String pruned = FullTextMatcher.prune(raw).toLowerCase(Locale.ENGLISH);

Review Comment:
   will this bring in problems with non-english stuff? I remember there is a bug in the bkclog that a chinese document is detected as binary .... just wondering



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555624677


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/IHeaderMatcher.java:
##########
@@ -110,10 +71,39 @@ public String toString() {
     interface Builder {
         /**
          * Build the IHeaderMatcher.
+         * 
+         * Implementations of this interface should return a specific child class of IHeaderMatcher.
+         * 
          * @return a new IHeaderMatcher.
          */
         IHeaderMatcher build();
 
+        /**
+         * Gets the class that is build by this builder.
+         * @return The class that is build by this builder.
+         */
+        default Class<?> builtClass() throws SecurityException {
+            try {
+                return this.getClass().getMethod("build").getReturnType();
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");

Review Comment:
   typo: always



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564198283


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/ChildContainerBuilder.java:
##########
@@ -52,39 +52,42 @@ protected ChildContainerBuilder() {
 
     /**
      * Reads a text file. Each line becomes a text matcher in the resulting list.
-     * 
+     *
      * @param resourceName the name of the resource to read.
      * @return a List of Matchers, one for each non-empty line in the input file.
      */
     public AbstractBuilder setResource(String resourceName) {
-          URL url = this.getClass().getResource(resourceName);
-            try (final InputStream in = url.openStream()) {
-                BufferedReader buffer = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
-                String txt;
-                while (null != (txt = buffer.readLine())) {
-                    txt = txt.trim();
-                    if (StringUtils.isNotBlank(txt)) {
-                        children.add(Builder.text().setText(txt));
-                    }
+        URL url = this.getClass().getResource(resourceName);
+        try (final InputStream in = url.openStream()) {
+            BufferedReader buffer = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));

Review Comment:
   Would we want to put the buffered reader into the tryWithResources as well?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564979664


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface
+interface Builder {
+    /**
+     * Build the IHeaderMatcher.
+     * 
+     * Implementations of this interface should return a specific child class of IHeaderMatcher.
+     * 
+     * @return a new IHeaderMatcher.
+     */
+    IHeaderMatcher build();
+
+    /**
+     * Gets the class that is build by this builder.
+     * @return The class that is build by this builder.
+     */
+    default Class<?> builtClass() throws SecurityException {
+        try {
+            return this.getClass().getMethod("build").getReturnType();
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException("the 'build' method of the Builder interface must alwasy be public");
+        }
+    }
+
+    /**
+     * Gets the Description for this builder.
+     * @return The description of the builder 
+     */
+    default Description getDescription() {
+        Class<?> clazz = builtClass();
+        if (clazz == IHeaderMatcher.class) {
+            throw new ImplementationException(String.format(
+                    "Class %s must implement built() method to return a child class of IHeaderMatcher", 
+                    this.getClass()));
+        }
+        return DescriptionBuilder.buildMap(clazz);
+    }
+}
++------------------------------------------+
+
+  The work of handling the Id and some other tasks is handled by the AbstractBuilder.
+  
++------------------------------------------+
+public abstract class AbstractBuilder implements IHeaderMatcher.Builder {
+
+    private String id;
+
+    /**
+     * Protected empty constructor.
+     */
+    protected AbstractBuilder() {
+    }
+
+    /**
+     * Set the id for the matcher.
+     * @param id the id to use.
+     * @return this builder for chaining.
+     */
+    public final AbstractBuilder setId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    /**
+     * @return {@code true} if the id is not null and not blank.
+     */
+    public final boolean hasId() {
+        return !StringUtils.isBlank(id);
+    }
+
+    /**
+     * @return the id as specified in the builder.
+     */
+    protected String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s with id %s", this.getClass(), id);
+    }
+}  
++------------------------------------------+
+  
+  So we have:
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.configuration.builders.AbstractBuilder;
+
+public class QSCBuilder extends AbstractBuilder. {
+    QSCMatcher build() {
+        return new QSCMatcher(getId());
+    }
+}
++------------------------------------------+
+
+** Registering the builder for use in XML configuration 
+
+  In order to use the matcher in a Rat configuration it has to be registered with the system.  This can be done by creating file with the builder specified and passing it
+  to the command line runner as a license ( "--licenses" option) file.  The XML parser will accept "<QSC>" as the matcher in license definitions. Since this is a joke license 
+  we should create a joke family to contain any such licenses and a QSC license that uses the QSC matcher.  The new license file now looks like:
+
++------------------------------------------+
+<rat-config>
+    <families>
+        <family id="Joke" name="A joke license" />
+    </families>
+    <licenses>
+        <license family="Joke" id="QSC" name="The QSC license">
+            <qsc/>
+        </license>
+    </licenses>
+    <matchers>
+        <matcher class="com.example.ratMatcher.QSCBuilder" />
+    </matchers>
+</rat-config>
++------------------------------------------+
+
+  If the license entry did not have an "id" attribute its ID would be the same as the family.
+
+* A more complex example
+
+ In many cases it is necessary to set properties on the matcher.  So let's write a generalized version of the QSC matcher that accepts any 3 strings and triggers if all 3 are found
+ in the header.
+
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "TPM", desc = "Checks that the three string are found in the header")
+public class TPMatcher extends AbstraactHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The first parameter")
+    private final String one;
+    
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The second parameter")
+    private final String two;
+    
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The third parameter")
+    private final String three;
+
+    public TPMatcher(String id, String one, String two, String three) { 
+        super(id);
+        if (StringUtils.isEmpthy(one) || StringUtils.isEmpty(two) || StringUtils.isEmpty(three) {
+            throw new ConfigurationException( "None of the three properties (one, two, or three) may be empty");
+        }
+        this.one = one;
+        this.two = two;
+        this.three = three;
+    }
+    
+    public String getOne() { return one; }
+
+    public String getThree() { return two; }
+
+    public String getTwo() { return three; }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains(one) && text.contains(two) && text.contains(three);
+    }
+}
++------------------------------------------+
+
+ The ComponentConfigurations with the parameter type indicate that the members specify properties of the component.  The Matcher must have a "get" method for each parameter and the builder
+ must have a corresponding "set" method.  The names of the methods and the attributes in the XML paarser can be changed by adding a 'name' attribute to the ConfigComponent.

Review Comment:
   typo: parser



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564972536


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 
+ scope of this document.  In this document we will address how to define licenses in the default XML format.
+ 
+ The XML document has a root node named "rat-config" which comprises 4 major sections: "Families", 
+ "Licenses", "Approved" and "Matchers".
+ 
+* Families
+ 
+ Families are groups that define licenses that share similarities.  Each family has an id and a name, and example
+ of an entry in this section is
+ 
++------------------------------------------+
+ <rat-config>
+    <families>
+        <family id="AL" name="Apache License Version 2.0" />
+    </families>
+ </rat-config>
++------------------------------------------+
+ 
+* Matchers
+
+ Matchers define tests that check the contents of files for specific patterns.  Matchers are defined in Java
+ code and are required to have Builder classes that build them.  There is {{{./matcher_def.html}additional documentation 
+ explaining how to create new Matchers}}.  In the XML document Matchers are identified by the "matcher" element that has
+ a single "class" property.  The value of the "class" property is the fully qualified class name that 
+ identifies a Builder class.  An example of a matchers entry is
+ 
++------------------------------------------+
+ <rat-config>
+    <matchers>
+        <matcher class="org.apache.rat.configuration.builders.AnyBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.SpdxBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.TextBuilder" />
+    </matcher>
+ </rat-config>
++------------------------------------------+
+ 
+* Licenses
+
+ License elements have three properties: "family", "id", and "name". The family property must refer to
+ the "id" of a family element.  The family element can be defined in the current document or in another
+ included document.  It has to exist by the time all the configuration files are read.  The "id" element
+ is optional, if it is not provided the id will be set to the id of the associated family.  However, the 
+ "id" property must be unique across all licenses.  The "name" property is also optional.  If not specified
+ the name of the associated family will be used.  It is recommened that each license have a unique name
+ as name conflicts make problem determination difficult.
+ 
+ License elements have two child element types.  The first is "notes".  There may be multiple "notes" 
+ child elements.  They are simple text elements that define notes about the license.  The other element
+ is a Matcher type.  A matcher element is defined by a builder in the "matchers" section as described
+ above.  The matchers listed in the example above define the "any", "spdx", and "text" matcher elements.
+ 
+ When defining the license the matcher is required and only one may be defined.  However, there are matchers
+ that accept multiple matcher child nodes.  In the example below the CDDL1 license uses the "any" matcher.
+ The "any" matcher accepts multiple child matchers and will report a match if any of the enclosed matchers
+ report a match. In the example below the "any" matcher has "text" and "spdx" child matchers.  The "text"
+ matcher will match the enclosed text and the "spdx" matcher matches {{{https://spdx.org/licenses/}SPDX}}
+ tags.  The second license defined below is the "ILLUMOS" license.  It shares the same family as the CDDL1
+ license, has its own "id" and "name" properties.  It also has a "note" child element that tells the user
+ that it is a modified CDDL1 license.  The license has a single "text" matcher.
+ 
++------------------------------------------+
+ <rat-config>
+    <licenses>
+        <license family="CDDL1">
+            <any>
+                <text>The contents of this file are subject to the terms of the
+                    Common Development and Distribution License("CDDL") (the
+                    "License"). You may not use this file except in compliance
+                    with the License.</text>
+                <spdx name='CDDL-1.0' />
+            </any>
+        </license>
+
+        <license family="CDDL1" id="ILLUMOS" name="ILLUMOS CDDL1 Derived license">
+            <note>Modified CDDL1 license</note>
+            <text>The contents of this file are subject to the terms of
+                the Common Development and Distribution License (the
+                "License") You may not use this file except in compliance
+                with the License. </text>
+        </license>
+    </licenses>
+ </rat-config>
++------------------------------------------+
+ 
+* Approved 
+ 
+ Approved element lists the approved licenses from this configuration.  It is possible to define licenses
+ that you want to detect but not allow.  If the "approved" element is not present all defined families
+ are considered to be approved.  The approved entry has "family" child entries that have "license_ref"
+ properties that reference the "id" of the family being approved.
+ 
++------------------------------------------+
+ <rat-config>
+    <approved>
+        <family license_ref='AL' />
+    </approved>
+ </rat-config>
++------------------------------------------+
+
+* Listing components
+
+ All the components (Licenses and Matchers) defined in the system can be displayed using the Documentation
+ tool.  To run the too execute:

Review Comment:
   Typo: tool



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#issuecomment-2054220779

   @Claudenw thanks for these big changes with tests and documentation. It's a lot of code that changed, but the examples and tests seem much more simple and straightforward to me.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564969032


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}

Review Comment:
   Let us use ASF links instead:
   https://gitbox.apache.org/repos/asf/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564967796


##########
src/site/apt/index.apt.vm:
##########
@@ -63,6 +63,16 @@ Apache Rat
  {{{./issue-management.html}patch}} or
  {{{./mailing-lists.html}talk to us}}
  whenever Rat falls short.
+ 
+** How do I extend Rat
+ 
+ There are several standard ways to extend Rat.
+ 
+   * Add a {{{./license_def.html}license definition}} via an XML file.
+   
+   * Add a new {{{./matcher_def.html}Matcher definition}}. Requires Java expertice.

Review Comment:
   Typo: Java expertise



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564251427


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {
+                        notes = desc;
+                    } else {
+                        writeAttribute(desc, component);
+                    }
+                }
+                for (Description desc : description.childrenOfType(Component.Type.BuilderParam)) {
+                    if ("family".equals(desc.getCommonName())) {
+                        try {
+                            ILicenseFamily family = (ILicenseFamily) desc.getter(component.getClass())
+                                    .invoke(component);
+                            if (family != null) {
+                                writer.attribute("family", family.getFamilyCategory().trim());
+                            }
+                        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
+                                | InvocationTargetException | SecurityException e) {
+                            configuration.getLog().error(e.toString());
+                        }
+                    }
+                }
+                // end of attributes
+                if (notes != null && StringUtils.isNotBlank(notes.getParamValue(configuration.getLog(), component))) {
+                    writeComment(notes);
+                    writer.openElement(notes.getCommonName());
+                    writeContent(notes, component);
+                    writer.closeElement();
+                }
+                for (Description desc : description.childrenOfType(Component.Type.Unlabeled)) {
+                    writeDescription(desc, component);
+                }
+                writer.closeElement();
+                break;
+            case Parameter:
+                if ("id".equals(description.getCommonName())) {

Review Comment:
   Extract as constant as other occurences above?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564249322


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */

Review Comment:
   "@VisibleForTesting" ? Not sure if we already have this annotation. I know it from Guava.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564258632


##########
apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/impl/base/XmlWriter.java:
##########
@@ -525,24 +548,36 @@ private void writeAttributeContent(CharSequence content) throws IOException {
      */
     @Override
     public IXmlWriter content(CharSequence content) throws IOException {
-        if (elementNames.isEmpty()) {
-            if (elementsWritten) {
-                throw new OperationNotAllowedException("Root element has already been closed.");
-            } 
-            throw new OperationNotAllowedException("An element must be opened before content can be written.");
-        }
-        if (inElement) {
-            writer.write('>');
-        }
-        writeBodyContent(content);
+        prepareForData();
+        writeEscaped(content, false);
         inElement = false;
         return this;
     }
 
-    private void writeBodyContent(final CharSequence content) throws IOException {
-        writeEscaped(content, false);
+    
+    /**
+     * Writes content. Calling this method will automatically Note that this method

Review Comment:
   Calling this method will automatically .... seems like a copy&paste thing - 
   Do you want to add info that the element is closed automtically?
   
   Pls add a linebreak before "Note that ..."



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564262038


##########
apache-rat-core/src/main/resources/org/apache/rat/plain-rat.xsl:
##########
@@ -53,42 +53,58 @@ Files with unapproved licenses:
 </xsl:if>
 <xsl:if test="descendant::resource[type/@name='archive']">
 Archives:
-<xsl:for-each select='descendant::resource[type/@name="archive"]'>
+<xsl:for-each select='descendant::resource[@type="archive"]'>
  + <xsl:value-of select='@name'/>
  <xsl:text>
  </xsl:text>
  </xsl:for-each>
 </xsl:if>
+<xsl:text>
 *****************************************************
-  Files with Apache License headers will be marked AL
-  Binary files (which do not require any license headers) will be marked B
-  Compressed archives will be marked A
-  Notices, licenses etc. will be marked N
+  Documents with unapproved licenses will start with a '!'
+  The next character identifies the document type.
+   
+   char         type
+    a       Archive file

Review Comment:
   Should we use uppercase chars to identify the document's type to be more compliant with current RAT reports?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564500839


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/SpdxBuilder.java:
##########
@@ -32,22 +31,22 @@ public class SpdxBuilder extends AbstractBuilder {
 
     /**
      * sets the name for the SPDX matcher
-     * @param name
-     * @return
+     * @param name The text that follows the colon ':' in the SPDX tag.
+     * @return this builder for chaining.
      */
     public SpdxBuilder setName(String name) {
-        Objects.requireNonNull(name, "name must not be null");
+        Objects.requireNonNull(name, "spdx name must not be null");

Review Comment:
   We are only looking for the identifier for the license [1] the search for the SPDX part is automatic.  But we should be consistent in the documentation.  Change to 'SPDX' made in all found documentation.
   
   [1] https://spdx.org/licenses/



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564522497


##########
apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/impl/base/XmlWriter.java:
##########
@@ -514,6 +526,17 @@ private void writeAttributeContent(CharSequence content) throws IOException {
         writeEscaped(content, true);
     }
 
+    private void prepareForData() throws IOException {
+        if (elementNames.isEmpty()) {
+            if (elementsWritten) {
+                throw new OperationNotAllowedException("Root element has already been closed.");
+            } 
+            throw new OperationNotAllowedException("An element must be opened before content can be written.");
+        }
+        if (inElement) {
+            writer.write('>');
+        }
+    }
     /**
      * Writes content. Calling this method will automatically Note that this method

Review Comment:
   I think all overridden methods should rely on the interface for documentation. :(



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1566295110


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {
+
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The id of the matcher.")
+    private final String id;
+
+    /**
+     * Constructs the IHeaderMatcher with an id value. If {@code id} is null then a
+     * unique random id is created.
+     * 
+     * @param id the Id to use.
+     */
+    protected AbstractHeaderMatcher(String id) {
+        this.id = StringUtils.isBlank(id) ? UUID.randomUUID().toString() : id;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    @Override
+    public Description getDescription() {
+        return DescriptionBuilder.build(this);
+    }
+}
++------------------------------------------+
+
+ So lets start by creating our matcher class and implementing the match method.
+
++------------------------------------------+
+package com.example.ratMatcher;
+
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.analysis.matchers.AbstractHeaderMatcher;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
+
+@ConfigComponent(type = Component.Type.Matcher, name = "QSC", desc = "Reports if the 'Quality, speed and cost, pick any two' rule is violated")
+public class QSCMatcher extends AbstraactHeaderMatcher {
+
+    public QSCMatcher(String id) {
+        super(id);
+    }
+
+    @Override
+    public boolean matches(IHeaders headers) {
+        String text = headers.prune()
+        return text.contains("quality") && text.contains("speed") && text.contains("cost");
+    }
+}
++------------------------------------------+
+
+ In the above example we use the ConfigComponent annotation to identify that this is a Matcher component, that it has the name 'QSC' and a description of what it does.  
+ If the "name" was not specified it would have been extracted from the class name by removing the "Matcher" from "QSCMatcher".
+
+ The Constructor calls the AbstractHeaderMatcher with a null argument so tha the parent class will assign an id.
+
+ The matcher uses the pruned text to check for the strings.  Pruned text has only the letters and numbers from the text included and all characters are converted to 
+ lower case.  There is an issue with this matcher in that it would match the string: "The quality of Dennis Hopper's acting, as Keanu Reeves costar in 'Speed', is outstanding."
+ 
+ the correction of that is left as an exercise for the reader.  Hint: matching the pruned text can be a quick gating check for a set of more expensive regular expression checks. 
+
+** The Matcher.Builder implementation
+
+  The builder must implement the IHeaderMatcher.Builder interface.
+
++------------------------------------------+
+@FunctionalInterface

Review Comment:
   all links now point to ASF gitbox.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1567906675


##########
apache-rat-tasks/pom.xml:
##########
@@ -105,7 +105,7 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
+      <!--<plugin>

Review Comment:
   Thanks.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555660664


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/matchers/OrMatcher.java:
##########
@@ -21,75 +21,44 @@
 import java.util.Collection;
 
 import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
 
 /**
- * A matcher that performs a logical {@code OR} across all the contained matchers.
+ * A matcher that performs a logical {@code OR} across all the contained
+ * matchers.
  */
+@ConfigComponent(type = Component.Type.Matcher, name = "any", desc = "Returns true if at least one of the enclosed matchers return true.")

Review Comment:
   "returns true"? 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555986918


##########
apache-rat-core/src/main/java/org/apache/rat/config/parameters/Description.java:
##########
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.parameters;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.rat.ConfigurationException;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.utils.Log;
+
+/**
+ * A description of a component.
+ */
+public class Description {
+    /** The type of component this describes */
+    private final Type type;
+    /**
+     * The common name for the component. Set by ConfigComponent.name() or
+     * class/field name.
+     */
+    private final String name;
+    /** The description for the component */
+    private final String desc;
+    /** The class of the getter/setter parameter */
+    private final Class<?> childClass;
+    /** True if the getter/setter expects a collection of childClass objects */
+    private final boolean isCollection;

Review Comment:
   When I read this the first time I instantly thought of isRecursive(), but it would imply a great many changes.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw merged PR #233:
URL: https://github.com/apache/creadur-rat/pull/233


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555631778


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/matchers/CopyrightMatcher.java:
##########
@@ -57,32 +63,61 @@ public class CopyrightMatcher extends AbstractSimpleMatcher {
 
     private final Pattern dateOwnerPattern;
     private final Pattern ownerDatePattern;
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The initial date of the copyright")
+    private final String start;
+    @ConfigComponent(type = Component.Type.Parameter, desc = "The last date the copyright we modifed")

Review Comment:
   ypo: was instead of we



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1555619725


##########
apache-rat-core/src/main/java/org/apache/rat/analysis/DocumentHeaderAnalyser.java:
##########
@@ -18,50 +18,50 @@
  */
 package org.apache.rat.analysis;
 
+import static java.lang.String.format;
+
 import java.io.IOException;
 import java.io.Reader;
+import java.util.Collection;
 
 import org.apache.rat.api.Document;
 import org.apache.rat.document.IDocumentAnalyser;
-import org.apache.rat.document.RatDocumentAnalysisException;
 import org.apache.rat.license.ILicense;
 import org.apache.rat.utils.Log;
 
-import static java.lang.String.format;
-
 /**
  * A Document analyzer that analyses document headers for a license.
  */
 class DocumentHeaderAnalyser implements IDocumentAnalyser {
 
-    /**
-     * The license to analyse
-     */
-    private final ILicense license;
+    /** The license to analyse */
+    private final Collection<ILicense> licenses;
     /** the logger to use */
     private final Log log;
 
     /**
      * Constructs the HeaderAnalyser for the specific license.
-     * 
+     *
      * @param license The license to analyse
      */
-    public DocumentHeaderAnalyser(final Log log, final ILicense license) {
+    public DocumentHeaderAnalyser(final Log log, final Collection<ILicense> licenses) {
         super();
-        this.license = license;
+        this.licenses = licenses;
         this.log = log;
     }
 
     @Override
-    public void analyse(Document document) throws RatDocumentAnalysisException {
+    public void analyse(Document document) {
         try (Reader reader = document.reader()) {
             log.debug(format("Processing: %s", document));
-            HeaderCheckWorker worker = new HeaderCheckWorker(reader, license, document);
+            HeaderCheckWorker worker = new HeaderCheckWorker(reader, licenses, document);
             worker.read();
         } catch (IOException e) {
-            throw new RatDocumentAnalysisException("Cannot read header", e);
+            log.warn(String.format("Can not read header of %s", document));

Review Comment:
   cannot?



##########
apache-rat-core/src/main/java/org/apache/rat/analysis/DocumentHeaderAnalyser.java:
##########
@@ -18,50 +18,50 @@
  */
 package org.apache.rat.analysis;
 
+import static java.lang.String.format;
+
 import java.io.IOException;
 import java.io.Reader;
+import java.util.Collection;
 
 import org.apache.rat.api.Document;
 import org.apache.rat.document.IDocumentAnalyser;
-import org.apache.rat.document.RatDocumentAnalysisException;
 import org.apache.rat.license.ILicense;
 import org.apache.rat.utils.Log;
 
-import static java.lang.String.format;
-
 /**
  * A Document analyzer that analyses document headers for a license.
  */
 class DocumentHeaderAnalyser implements IDocumentAnalyser {
 
-    /**
-     * The license to analyse
-     */
-    private final ILicense license;
+    /** The license to analyse */
+    private final Collection<ILicense> licenses;
     /** the logger to use */
     private final Log log;
 
     /**
      * Constructs the HeaderAnalyser for the specific license.
-     * 
+     *
      * @param license The license to analyse
      */
-    public DocumentHeaderAnalyser(final Log log, final ILicense license) {
+    public DocumentHeaderAnalyser(final Log log, final Collection<ILicense> licenses) {
         super();
-        this.license = license;
+        this.licenses = licenses;
         this.log = log;
     }
 
     @Override
-    public void analyse(Document document) throws RatDocumentAnalysisException {
+    public void analyse(Document document) {
         try (Reader reader = document.reader()) {
             log.debug(format("Processing: %s", document));
-            HeaderCheckWorker worker = new HeaderCheckWorker(reader, license, document);
+            HeaderCheckWorker worker = new HeaderCheckWorker(reader, licenses, document);
             worker.read();
         } catch (IOException e) {
-            throw new RatDocumentAnalysisException("Cannot read header", e);
+            log.warn(String.format("Can not read header of %s", document));
+            document.getMetaData().setDocumentType(Document.Type.unknown);
         } catch (RatHeaderAnalysisException e) {
-            throw new RatDocumentAnalysisException("Cannot analyse header", e);
+            log.warn(String.format("Can not process header of %s", document));

Review Comment:
   cannot?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564259367


##########
apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/impl/base/XmlWriter.java:
##########
@@ -525,24 +548,36 @@ private void writeAttributeContent(CharSequence content) throws IOException {
      */
     @Override
     public IXmlWriter content(CharSequence content) throws IOException {
-        if (elementNames.isEmpty()) {
-            if (elementsWritten) {
-                throw new OperationNotAllowedException("Root element has already been closed.");
-            } 
-            throw new OperationNotAllowedException("An element must be opened before content can be written.");
-        }
-        if (inElement) {
-            writer.write('>');
-        }
-        writeBodyContent(content);
+        prepareForData();
+        writeEscaped(content, false);
         inElement = false;
         return this;
     }
 
-    private void writeBodyContent(final CharSequence content) throws IOException {
-        writeEscaped(content, false);
+    
+    /**
+     * Writes content. Calling this method will automatically Note that this method
+     * does not use CDATA.
+     *
+     * @param content the content to write
+     * @return this object
+     * @throws OperationNotAllowedException if called before any call to
+     * {@link #openElement} or after the first element has been closed
+     */
+    @Override
+    public IXmlWriter cdata(CharSequence content) throws IOException {
+        prepareForData();
+        StringBuilder sb = new StringBuilder(content);
+        int found;
+        while (-1 != (found = sb.indexOf("]]>"))) {
+            sb.replace(found, found+3, "<!- Rat removed CDATA closure here ->");

Review Comment:
   Should this be a real comment <!-- or is this a special marker?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564259075


##########
apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/impl/base/XmlWriter.java:
##########
@@ -525,24 +548,36 @@ private void writeAttributeContent(CharSequence content) throws IOException {
      */
     @Override
     public IXmlWriter content(CharSequence content) throws IOException {
-        if (elementNames.isEmpty()) {
-            if (elementsWritten) {
-                throw new OperationNotAllowedException("Root element has already been closed.");
-            } 
-            throw new OperationNotAllowedException("An element must be opened before content can be written.");
-        }
-        if (inElement) {
-            writer.write('>');
-        }
-        writeBodyContent(content);
+        prepareForData();
+        writeEscaped(content, false);
         inElement = false;
         return this;
     }
 
-    private void writeBodyContent(final CharSequence content) throws IOException {
-        writeEscaped(content, false);
+    
+    /**
+     * Writes content. Calling this method will automatically Note that this method
+     * does not use CDATA.
+     *
+     * @param content the content to write
+     * @return this object
+     * @throws OperationNotAllowedException if called before any call to
+     * {@link #openElement} or after the first element has been closed
+     */
+    @Override
+    public IXmlWriter cdata(CharSequence content) throws IOException {

Review Comment:
   Pls reformat this method - thx.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564257079


##########
apache-rat-core/src/main/java/org/apache/rat/report/xml/writer/IXmlWriter.java:
##########
@@ -66,8 +76,8 @@ public interface IXmlWriter extends AutoCloseable {
     
     /**
      * Writes content.
-     * Calling this method will automatically 
-     * Note that this method does not use CDATA.
+     * Note that this method does not support CDATA.
+     * This method automatically excapes characters.

Review Comment:
   Typo: escapes characters



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564479047


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/NotBuilder.java:
##########
@@ -19,24 +19,23 @@
 package org.apache.rat.configuration.builders;
 
 import org.apache.rat.ConfigurationException;
-import org.apache.rat.analysis.IHeaderMatcher;
 import org.apache.rat.analysis.matchers.NotMatcher;
 
 /**
  * A builder for the NotMatcher.
  */
 public class NotBuilder extends ChildContainerBuilder {
-    
+
     @Override
-    public IHeaderMatcher build() {
+    public NotMatcher build() {
         if (children.size() != 1) {
             throw new ConfigurationException("'not' type matcher requires one and only one enclosed matcher");
         }
         return new NotMatcher(getId(), children.get(0).build());
     }
-    
+
     @Override
     public String toString() {
-        return String.format( "NotBuilder: %s", !children.isEmpty() ? children.get(0) : null );
+        return String.format("NotBuilder: %s", !children.isEmpty() ? children.get(0) : null);

Review Comment:
   The builder can be in a state where the enclosed matcher has not yet been constructed.  However, when the `build()` method is called it will throw an exception if the enclosed matcher is not defined.  
   
   I suppose the NotBuilder is in a Schrodengers Cat state if the matcher has not been defined.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564526816


##########
apache-rat-core/src/main/java/org/apache/rat/utils/Log.java:
##########
@@ -59,51 +59,105 @@ public enum Level {
      */
     void log(Level level, String message);
     
+    /**
+     * Write a log message at the specified level.
+     * @param level the level to write the message at.
+     * @param message the mesage to write.
+     */
     default void log(Level level, Object message) {
         log(level, message == null ? "NULL" : message.toString());
     }
     
+    /**
+     * Write a message at DEBUG level.
+     * @param message the message to write.
+     */
     default void debug(Object message) {
         log(Level.DEBUG, message);
     }
 
+    /**
+     * Write a message at INFO level.
+     * @param message the message to write.
+     */
     default void info(Object message) {
         log(Level.INFO, message);
     }
     
+    /**
+     * Write a message at WARN level.
+     * @param message the message to write.
+     */
     default void warn(Object message) {
         log(Level.WARN, message);
     }
     
+    /**
+     * Write a message at ERROR level.
+     * @param message the message to write.
+     */
     default void error(Object message) {
         log(Level.ERROR, message);
     }
-    default void log(Level level, String message, Throwable t) {       
+    
+    /**
+     * Write a log message and report throwable stack trace at the specified log level.
+     * @param level the level to report at
+     * @param message the message for the log
+     * @param throwable the throwable
+     */
+    default void log(Level level, String message, Throwable throwable) {       
         StringWriter writer = new StringWriter(500);
         PrintWriter pWriter = new PrintWriter(writer);
         pWriter.print(message);
         pWriter.print(System.lineSeparator());
-        t.printStackTrace(pWriter);
+        throwable.printStackTrace(pWriter);

Review Comment:
   `printStackTrace(writer)` will write to the writer and not to error.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564527324


##########
apache-rat-core/src/main/resources/org/apache/rat/plain-rat.xsl:
##########
@@ -53,42 +53,58 @@ Files with unapproved licenses:
 </xsl:if>
 <xsl:if test="descendant::resource[type/@name='archive']">
 Archives:
-<xsl:for-each select='descendant::resource[type/@name="archive"]'>
+<xsl:for-each select='descendant::resource[@type="archive"]'>
  + <xsl:value-of select='@name'/>
  <xsl:text>
  </xsl:text>
  </xsl:for-each>
 </xsl:if>
+<xsl:text>
 *****************************************************
-  Files with Apache License headers will be marked AL
-  Binary files (which do not require any license headers) will be marked B
-  Compressed archives will be marked A
-  Notices, licenses etc. will be marked N
+  Documents with unapproved licenses will start with a '!'
+  The next character identifies the document type.
+   
+   char         type
+    a       Archive file

Review Comment:
   Uppercase is now the default since the enums were changed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#issuecomment-2054033781

   Just a FYI: I have an implementation of a program that will write ANT tasks for any given command line configuration.  So adding new matchers in Ant is fairly easy.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1566018593


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 
+ scope of this document.  In this document we will address how to define licenses in the default XML format.
+ 
+ The XML document has a root node named "rat-config" which comprises 4 major sections: "Families", 
+ "Licenses", "Approved" and "Matchers".
+ 
+* Families
+ 
+ Families are groups that define licenses that share similarities.  Each family has an id and a name, and example
+ of an entry in this section is
+ 
++------------------------------------------+
+ <rat-config>
+    <families>
+        <family id="AL" name="Apache License Version 2.0" />
+    </families>
+ </rat-config>
++------------------------------------------+
+ 
+* Matchers
+
+ Matchers define tests that check the contents of files for specific patterns.  Matchers are defined in Java
+ code and are required to have Builder classes that build them.  There is {{{./matcher_def.html}additional documentation 
+ explaining how to create new Matchers}}.  In the XML document Matchers are identified by the "matcher" element that has
+ a single "class" property.  The value of the "class" property is the fully qualified class name that 
+ identifies a Builder class.  An example of a matchers entry is
+ 
++------------------------------------------+
+ <rat-config>
+    <matchers>
+        <matcher class="org.apache.rat.configuration.builders.AnyBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.SpdxBuilder" />
+        <matcher class="org.apache.rat.configuration.builders.TextBuilder" />
+    </matcher>
+ </rat-config>
++------------------------------------------+
+ 
+* Licenses
+
+ License elements have three properties: "family", "id", and "name". The family property must refer to
+ the "id" of a family element.  The family element can be defined in the current document or in another
+ included document.  It has to exist by the time all the configuration files are read.  The "id" element
+ is optional, if it is not provided the id will be set to the id of the associated family.  However, the 
+ "id" property must be unique across all licenses.  The "name" property is also optional.  If not specified
+ the name of the associated family will be used.  It is recommened that each license have a unique name
+ as name conflicts make problem determination difficult.
+ 
+ License elements have two child element types.  The first is "notes".  There may be multiple "notes" 
+ child elements.  They are simple text elements that define notes about the license.  The other element
+ is a Matcher type.  A matcher element is defined by a builder in the "matchers" section as described
+ above.  The matchers listed in the example above define the "any", "spdx", and "text" matcher elements.
+ 
+ When defining the license the matcher is required and only one may be defined.  However, there are matchers
+ that accept multiple matcher child nodes.  In the example below the CDDL1 license uses the "any" matcher.
+ The "any" matcher accepts multiple child matchers and will report a match if any of the enclosed matchers
+ report a match. In the example below the "any" matcher has "text" and "spdx" child matchers.  The "text"
+ matcher will match the enclosed text and the "spdx" matcher matches {{{https://spdx.org/licenses/}SPDX}}
+ tags.  The second license defined below is the "ILLUMOS" license.  It shares the same family as the CDDL1
+ license, has its own "id" and "name" properties.  It also has a "note" child element that tells the user
+ that it is a modified CDDL1 license.  The license has a single "text" matcher.
+ 
++------------------------------------------+
+ <rat-config>
+    <licenses>
+        <license family="CDDL1">
+            <any>
+                <text>The contents of this file are subject to the terms of the
+                    Common Development and Distribution License("CDDL") (the
+                    "License"). You may not use this file except in compliance
+                    with the License.</text>
+                <spdx name='CDDL-1.0' />
+            </any>
+        </license>
+
+        <license family="CDDL1" id="ILLUMOS" name="ILLUMOS CDDL1 Derived license">
+            <note>Modified CDDL1 license</note>
+            <text>The contents of this file are subject to the terms of
+                the Common Development and Distribution License (the
+                "License") You may not use this file except in compliance
+                with the License. </text>
+        </license>
+    </licenses>
+ </rat-config>
++------------------------------------------+
+ 
+* Approved 
+ 
+ Approved element lists the approved licenses from this configuration.  It is possible to define licenses
+ that you want to detect but not allow.  If the "approved" element is not present all defined families
+ are considered to be approved.  The approved entry has "family" child entries that have "license_ref"
+ properties that reference the "id" of the family being approved.
+ 
++------------------------------------------+
+ <rat-config>
+    <approved>
+        <family license_ref='AL' />
+    </approved>
+ </rat-config>
++------------------------------------------+
+
+* Listing components
+
+ All the components (Licenses and Matchers) defined in the system can be displayed using the Documentation
+ tool.  To run the too execute:
+
++------------------------------------------+
+java -jar apache-rat-${project.version}.jar org.apache.rat.Documentation

Review Comment:
   We should discuss this.  The index.html shows how to call the code if you have built it directly.  What we don't do is show how to run the tools if you have downloaded them.
   
   I want to expand tools to include simple scripts to run the basic command line tools given a download of a compressed file, or something similar to that.  Make it easy to run for people who are just downloading and running.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564252944


##########
apache-rat-core/src/main/java/org/apache/rat/report/ConfigurationReport.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ */
+package org.apache.rat.report;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ReportConfiguration;
+import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.Component.Type;
+import org.apache.rat.config.parameters.Description;
+import org.apache.rat.config.parameters.DescriptionBuilder;
+import org.apache.rat.configuration.MatcherBuilderTracker;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.configuration.builders.MatcherRefBuilder;
+import org.apache.rat.license.ILicense;
+import org.apache.rat.license.ILicenseFamily;
+import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.xml.writer.IXmlWriter;
+
+/**
+ * A report that dumps the ReportConfiguration into the XML output.
+ */
+public class ConfigurationReport extends AbstractReport {
+
+    private final ReportConfiguration configuration;
+    private final IXmlWriter writer;
+    private final Set<String> matchers;
+
+    /**
+     * Constructor.
+     * @param writer The writer to write the XML data to.
+     * @param configuration the configuration to dump
+     */
+    public ConfigurationReport(IXmlWriter writer, ReportConfiguration configuration) {
+        this.configuration = configuration;
+        this.writer = writer;
+        this.matchers = new HashSet<>();
+    }
+
+    @Override
+    public void startReport() throws RatException {
+        if (configuration.listFamilies() != LicenseFilter.none || configuration.listLicenses() != LicenseFilter.none) {
+            try {
+                writer.openElement(XMLConfigurationReader.ROOT);
+
+                // write Families section
+                SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
+                if (!families.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.FAMILIES);
+                    for (ILicenseFamily family : families) {
+                        writeFamily(family);
+                    }
+                    writer.closeElement(); // FAMILIES
+                }
+
+                // write licenses section
+                SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
+                if (!licenses.isEmpty()) {
+                    writer.openElement(XMLConfigurationReader.LICENSES);
+                    for (ILicense license : licenses) {
+                        writeDescription(license.getDescription(), license);
+                    }
+                    writer.closeElement();// LICENSES
+                }
+
+                // write approved section
+                writer.openElement(XMLConfigurationReader.APPROVED);
+                for (String family : configuration.getApprovedLicenseCategories()) {
+                    writer.openElement(XMLConfigurationReader.APPROVED)
+                            .attribute(XMLConfigurationReader.ATT_LICENSE_REF, family.trim()).closeElement();
+                }
+                writer.closeElement(); // APPROVED
+
+                // write matchers section
+                MatcherBuilderTracker tracker = MatcherBuilderTracker.INSTANCE;
+                writer.openElement(XMLConfigurationReader.MATCHERS);
+                for (Class<?> clazz : tracker.getClasses()) {
+                    writer.openElement(XMLConfigurationReader.MATCHER)
+                            .attribute(XMLConfigurationReader.ATT_CLASS_NAME, clazz.getCanonicalName()).closeElement();
+                }
+                writer.closeElement(); // MATCHERS
+
+                writer.closeElement(); // ROOT
+            } catch (IOException e) {
+                throw new RatException(e);
+            }
+        }
+    }
+
+    private void writeFamily(ILicenseFamily family) throws RatException {
+        try {
+            writer.openElement(XMLConfigurationReader.FAMILY)
+                    .attribute(XMLConfigurationReader.ATT_ID, family.getFamilyCategory().trim())
+                    .attribute(XMLConfigurationReader.ATT_NAME, family.getFamilyName());
+            writer.closeElement();
+        } catch (IOException e) {
+            throw new RatException(e);
+        }
+    }
+
+    private void writeDescriptions(Collection<Description> descriptions, Component component) throws RatException {
+        for (Description description : descriptions) {
+            writeDescription(description, component);
+        }
+    }
+
+    private void writeChildren(Description description, Component component) throws RatException {
+        writeDescriptions(description.childrenOfType(Type.Parameter), component);
+        writeDescriptions(description.childrenOfType(Type.Unlabeled), component);
+        writeDescriptions(description.childrenOfType(Type.Matcher), component);
+        writeDescriptions(description.childrenOfType(Type.License), component);
+    }
+
+    private void writeComment(Description description) throws IOException {
+        if (StringUtils.isNotBlank(description.getDescription())) {
+            writer.comment(description.getDescription());
+        }
+    }
+
+    private void writeContent(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.content(paramValue);
+        }
+    }
+
+    private void writeAttribute(Description description, Component component) throws IOException {
+        String paramValue = description.getParamValue(configuration.getLog(), component);
+        if (paramValue != null) {
+            writer.attribute(description.getCommonName(), paramValue);
+        }
+    }
+
+    /* package privete for testing */
+    void writeDescription(Description description, Component component) throws RatException {
+        try {
+            switch (description.getType()) {
+            case Matcher:
+                // see if id was registered
+                Optional<Description> id = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> XMLConfigurationReader.ATT_ID.equals(i.getCommonName())).findFirst();
+                if (id.isPresent()) {
+                    String idValue = id.get().getParamValue(configuration.getLog(), component);
+                    // if we have seen the ID before just put a reference to the other one.
+                    if (matchers.contains(idValue.toString())) {
+                        component = new MatcherRefBuilder.IHeaderMatcherProxy(idValue.toString(), null);
+                        description = component.getDescription();
+                    } else {
+                        matchers.add(idValue.toString());
+                    }
+                }
+                Optional<Description> resource = description.childrenOfType(Type.Parameter).stream()
+                        .filter(i -> "resource".equals(i.getCommonName())).findFirst();
+                if (resource.isPresent()) {
+                    Iterator<Map.Entry<String, Description>> iter = description.getChildren().entrySet().iterator();
+                    while (iter.hasNext()) {
+                        Map.Entry<String, Description> entry = iter.next();
+                        if (entry.getValue().isCollection()
+                                && IHeaderMatcher.class.isAssignableFrom(entry.getValue().getChildType())) {
+                            iter.remove();
+                        }
+                    }
+                }
+                writeComment(description);
+                writer.openElement(description.getCommonName());
+                writeChildren(description, component);
+                writer.closeElement();
+                break;
+            case License:
+                writer.openElement(XMLConfigurationReader.LICENSE);
+                Description notes = null;
+                for (Description desc : description.childrenOfType(Component.Type.Parameter)) {
+                    if ("notes".equals(desc.getCommonName())) {
+                        notes = desc;
+                    } else {
+                        writeAttribute(desc, component);
+                    }
+                }
+                for (Description desc : description.childrenOfType(Component.Type.BuilderParam)) {
+                    if ("family".equals(desc.getCommonName())) {
+                        try {
+                            ILicenseFamily family = (ILicenseFamily) desc.getter(component.getClass())
+                                    .invoke(component);
+                            if (family != null) {
+                                writer.attribute("family", family.getFamilyCategory().trim());
+                            }
+                        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
+                                | InvocationTargetException | SecurityException e) {
+                            configuration.getLog().error(e.toString());
+                        }
+                    }
+                }
+                // end of attributes
+                if (notes != null && StringUtils.isNotBlank(notes.getParamValue(configuration.getLog(), component))) {
+                    writeComment(notes);
+                    writer.openElement(notes.getCommonName());
+                    writeContent(notes, component);
+                    writer.closeElement();
+                }
+                for (Description desc : description.childrenOfType(Component.Type.Unlabeled)) {
+                    writeDescription(desc, component);
+                }
+                writer.closeElement();
+                break;
+            case Parameter:
+                if ("id".equals(description.getCommonName())) {
+                    try {
+                        String idValue = description.getParamValue(configuration.getLog(), component);
+                        // if a UUID skip it.
+                        if (idValue != null) {
+                            UUID.fromString(idValue.toString());
+                            return;
+                        }
+                    } catch (IllegalArgumentException expected) {
+                        // do nothing.
+                    }
+                }
+                writeAttribute(description, component);
+                break;
+            case Unlabeled:
+                try {
+                    Object obj = description.getter(component.getClass()).invoke(component);
+                    if (obj instanceof Iterable) {
+                        for (Object o2 : (Iterable<?>) obj) {
+                            processUnlabled(o2);

Review Comment:
   Typo in method name - processUnlabeled() instead?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564202140


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/MatcherRefBuilder.java:
##########
@@ -20,19 +20,26 @@
 
 import java.util.Map;
 
+import org.apache.rat.ConfigurationException;
 import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.analysis.IHeaders;
+import org.apache.rat.config.parameters.Component;
+import org.apache.rat.config.parameters.ConfigComponent;
 
 /**
- * A reference matching Matcher builder.
- * <p>
- * This class stores a matcher id as a reference to the matcher.  It also has a map of matcher ids to the matcher
- * instances.  When build is called the matcher reference is looked up in the map.  If it is found then it is returned
- * value from the {@code build()} call.  If the reference is not located then a IHeaderMatcherProxy is returned.
- * the IHeaderMatcherProxy is resolved in a later configuration construction phase.
+ * A reference matching Matcher builder. <p> This class stores a matcher id as a
+ * reference to the matcher. It also has a map of matcher ids to the matcher
+ * instances. When build is called the matcher reference is looked up in the
+ * map. If it is found then it is returned value from the {@code build()} call.

Review Comment:
   If it is found, its value is returned from the {@code build()} call.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564217809


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/SpdxBuilder.java:
##########
@@ -32,22 +31,22 @@ public class SpdxBuilder extends AbstractBuilder {
 
     /**
      * sets the name for the SPDX matcher
-     * @param name
-     * @return
+     * @param name The text that follows the colon ':' in the SPDX tag.
+     * @return this builder for chaining.
      */
     public SpdxBuilder setName(String name) {
-        Objects.requireNonNull(name, "name must not be null");
+        Objects.requireNonNull(name, "spdx name must not be null");

Review Comment:
   Does SPDX require uppercasing, if so we could enforce it here and in the constructor?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "Claudenw (via GitHub)" <gi...@apache.org>.
Claudenw commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564487716


##########
apache-rat-core/src/main/java/org/apache/rat/document/impl/ArchiveEntryDocument.java:
##########
@@ -37,44 +36,44 @@ public class ArchiveEntryDocument implements Document {
 
     private final MetaData metaData = new MetaData();
 
-    public ArchiveEntryDocument(File file, byte[] contents) throws RatException {
+    public ArchiveEntryDocument(File file, byte[] contents) {
         super();
         name = DocumentImplUtils.toName(file);
         this.contents = contents;
     }
 
+    @Override
     public MetaData getMetaData() {
         return metaData;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public InputStream inputStream() throws IOException {
         return new ByteArrayInputStream(contents);
     }
 
+    @Override
     public boolean isComposite() {
         return DocumentImplUtils.isZipStream(new ByteArrayInputStream(contents));

Review Comment:
   Actually, this file has no technical changes and should be reverted.  But in answer to your question yes, and it is an area I will be looking into shortly.  I want us to use the SPDX license matching code to see if we can match LICENSE files and I want to do that within archive files.
   
   I am reverting this file because there is no real change.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564199293


##########
apache-rat-core/src/main/java/org/apache/rat/configuration/builders/ChildContainerBuilder.java:
##########
@@ -99,11 +102,11 @@ public AbstractBuilder add(Collection<IHeaderMatcher.Builder> children) {
     public List<IHeaderMatcher> getChildren() {
         return children.stream().map(IHeaderMatcher.Builder::build).collect(Collectors.toList());
     }
-    
+
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append( ":");
-        children.stream().map(Object::toString).forEach( x -> sb.append("\n").append(x));
+        StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append(":");
+        children.stream().map(Object::toString).forEach(x -> sb.append("\n").append(x));

Review Comment:
   Not sure if it is a problem on Windows to have Linux file endings ... otherwise System.lineSeparator() again.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564975740


##########
src/site/apt/matcher_def.apt.vm:
##########
@@ -0,0 +1,364 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new Matchers
+                   --------------------------
+
+How to define matchers in Apache Rat
+
+ Matchers in Apache Rat are paired with Builders.  A Matcher must implement the "IHeaderMatcher" interface and its associated Builder must implement the IHeaderMatcher.Builder interface.
+
+* A simple example
+
+** The Matcher implementation
+
+ For our example we will implement a Matcher that implements the phrase "Quality, speed and cost, pick any two” by looking for the occurrence of all three words anywhere in the header.  
+ In most cases is it simplest to extend the AbstractHeaderMatcher class as this class will handle setting of the unique ID for instances that do not otherwise have a unique id.
+
++------------------------------------------+
+public interface IHeaderMatcher extends Component {
+    /**
+     * Get the identifier for this matcher.
+     * <p>
+     * All matchers must have unique identifiers
+     * </p>
+     * 
+     * @return the Identifier for this matcher.
+     */
+    String getId();
+
+    /**
+     * Resets this state of this matcher to its initial state in preparation for
+     * use with another document scan.  In most cases this method does not need to 
+     * do anything.
+     */
+    default void reset() {
+        // does nothing.
+    }
+
+    /**
+     * Attempts to match text in the IHeaders instance.
+     * 
+     * @param headers the representations of the headers to check
+     * @return {@code true} if the matcher matches the text, {@code false} otherwise.
+     */
+    boolean matches(IHeaders headers);
+}
++------------------------------------------+
+
++------------------------------------------+
+public abstract class AbstractHeaderMatcher implements IHeaderMatcher {

Review Comment:
   Maybe it is sufficient to add plain references to both classes as you provide a full example afterwards ?!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] RAT-355 and RAT-366 fixes in one package [creadur-rat]

Posted by "ottlinger (via GitHub)" <gi...@apache.org>.
ottlinger commented on code in PR #233:
URL: https://github.com/apache/creadur-rat/pull/233#discussion_r1564969396


##########
src/site/apt/license_def.apt.vm:
##########
@@ -0,0 +1,143 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~   Licensed to the Apache Software Foundation (ASF) under one or more
+~~   contributor license agreements.  See the NOTICE file distributed with
+~~   this work for additional information regarding copyright ownership.
+~~   The ASF licenses this file to You under the Apache License, Version 2.0
+~~   (the "License"); you may not use this file except in compliance with
+~~   the License.  You may obtain a copy of the License at
+~~
+~~       http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing, software
+~~   distributed under the License is distributed on an "AS IS" BASIS,
+~~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~   See the License for the specific language governing permissions and
+~~   limitations under the License.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                   --------------------------
+                   How to define new licenses
+                   --------------------------
+
+How to define licenses in Apache Rat
+
+ All licenses in Apache Rat are defined in configuration files.  There is a default 
+ {{{https://github.com/apache/creadur-rat/blob/master/apache-rat-core/src/main/resources/org/apache/rat/default.xml}
+ XML based configuration file}} that can server as a good example of various definitions.
+
+ It is possible to create new parsers for different configuration formats.  But that task is beyone the 

Review Comment:
   Typo: is beyond the



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@creadur.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org