View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   */
19  package org.apache.rat;
20  
21  import java.io.File;
22  import java.io.FileFilter;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.io.OutputStreamWriter;
28  import java.io.PrintWriter;
29  import java.net.MalformedURLException;
30  import java.net.URI;
31  import java.net.URL;
32  import java.nio.charset.StandardCharsets;
33  import java.nio.file.Files;
34  import java.util.ArrayList;
35  import java.util.Collection;
36  import java.util.List;
37  import java.util.Objects;
38  import java.util.SortedSet;
39  import java.util.function.Consumer;
40  
41  import org.apache.commons.io.function.IOSupplier;
42  import org.apache.commons.io.output.CloseShieldOutputStream;
43  import org.apache.rat.analysis.IHeaderMatcher;
44  import org.apache.rat.commandline.StyleSheets;
45  import org.apache.rat.config.AddLicenseHeaders;
46  import org.apache.rat.config.exclusion.ExclusionProcessor;
47  import org.apache.rat.config.exclusion.StandardCollection;
48  import org.apache.rat.config.results.ClaimValidator;
49  import org.apache.rat.configuration.builders.AnyBuilder;
50  import org.apache.rat.document.DocumentName;
51  import org.apache.rat.document.DocumentNameMatcher;
52  import org.apache.rat.document.FileDocument;
53  import org.apache.rat.license.ILicense;
54  import org.apache.rat.license.ILicenseFamily;
55  import org.apache.rat.license.LicenseSetFactory;
56  import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
57  import org.apache.rat.report.IReportable;
58  import org.apache.rat.utils.DefaultLog;
59  import org.apache.rat.utils.Log.Level;
60  import org.apache.rat.utils.ReportingSet;
61  import org.apache.rat.walker.FileListWalker;
62  import org.apache.rat.walker.IReportableListWalker;
63  
64  /**
65   * A configuration object is used by the front end to invoke the
66   * {@link Reporter}. The sole purpose of the frontends is to create the
67   * configuration and invoke the {@link Reporter}.
68   */
69  public class ReportConfiguration {
70  
71      /**
72       * The styles of processing for various categories of documents.
73       */
74      public enum Processing {
75          /** List file as present only */
76          NOTIFICATION("List file as present"),
77          /** List all present licenses */
78          PRESENCE("List any licenses found"),
79          /** List all present licenses and unknown licenses */
80          ABSENCE("List licenses found and any unknown licences");
81  
82          /**
83           * Description of the processing
84           */
85          private final String description;
86  
87  
88          Processing(final String description) {
89              this.description = description;
90          }
91  
92          /**
93           * Gets the description of the processing type.
94           * @return the description of the processing type.
95           */
96          public String desc() {
97              return description;
98          }
99      }
100 
101     /** The LicenseSetFactory for the configuration */
102     private final LicenseSetFactory licenseSetFactory;
103 
104     /**
105      * {@code true} if we are adding license headers to the files.
106      */
107     private boolean addingLicenses;
108     /**
109      * {@code true} if we are adding license headers in place (no *.new files)
110      */
111     private boolean addingLicensesForced;
112     /**
113      * The copyright message to add if we are adding headers. Will be null if we are not
114      * adding copyright messages.
115      */
116     private String copyrightMessage;
117     /**
118      * The IOSupplier that provides the output stream to write the report to.
119      */
120     private IOSupplier<OutputStream> out;
121     /**
122      * The IOSupplier that provides the stylesheet to style the XML output.
123      */
124     private IOSupplier<InputStream> styleSheet;
125 
126     /**
127      * A list of files to read file names from.
128      */
129     private final List<File> sources;
130 
131     /**
132      * A list of reportables to process;
133      */
134     private final List<IReportable> reportables;
135 
136     /**
137      * A predicate to test if a path should be included in the processing.
138      */
139     private final ExclusionProcessor exclusionProcessor;
140 
141     /**
142      * The default filter for displaying families.
143      */
144     private LicenseFilter listFamilies;
145     /**
146      * The default filter for displaying licenses.
147      */
148     private LicenseFilter listLicenses;
149     /**
150      * {@code true} if this is a dry run and no processing is to take place.
151      */
152     private boolean dryRun;
153     /**
154      * How to process ARCHIVE document types.
155      */
156     private Processing archiveProcessing;
157     /**
158      * How to process STANDARD document types.
159      */
160     private Processing standardProcessing;
161     /**
162      * The ClaimValidator to validate min/max counts and similar claims.
163      */
164     private final ClaimValidator claimValidator;
165     /**
166      * Constructor
167      */
168     public ReportConfiguration() {
169         licenseSetFactory = new LicenseSetFactory();
170         listFamilies = Defaults.LIST_FAMILIES;
171         listLicenses = Defaults.LIST_LICENSES;
172         dryRun = false;
173         exclusionProcessor = new ExclusionProcessor();
174         claimValidator = new ClaimValidator();
175         sources = new ArrayList<>();
176         reportables = new ArrayList<>();
177     }
178 
179     /**
180      * Report the excluded files to the appendable object.
181      * @param appendable the appendable object to write to.
182      */
183     public void reportExclusions(final Appendable appendable) {
184         try {
185             exclusionProcessor.reportExclusions(appendable);
186         } catch (IOException e) {
187             DefaultLog.getInstance().warn("Unable to report exclusions", e);
188         }
189     }
190 
191     /**
192      * Adds a file as a source of files to scan.
193      * The file must be a text file that lists files to be included.
194      * File within the file must be in linux format with a
195      * "/" file separator.
196      * @param file the file to process.
197      */
198     public void addSource(final File file) {
199         notNull(file, "File may not be null.");
200         sources.add(file);
201     }
202 
203     private void notNull(final Object o, final String msg) {
204         if (o == null) {
205             throw new ConfigurationException(msg);
206         }
207     }
208 
209     /**
210      * Adds a Reportable as a source of files to scan.
211      * @param reportable the reportable to process.
212      */
213     public void addSource(final IReportable reportable) {
214         notNull(reportable, "Reportable may not be null.");
215         reportables.add(reportable);
216     }
217 
218     /**
219      * Returns {@code true} if the configuration has any sources defined.
220      * @return {@code true} if the configuration has any sources defined.
221      */
222     public boolean hasSource() {
223         return !reportables.isEmpty() || !sources.isEmpty();
224     }
225 
226     /**
227      * Gets a builder initialized with any files specified as sources.
228      * @return a configured builder.
229      */
230     public IReportableListWalker.Builder getSources() {
231         DocumentName name = DocumentName.builder(new File(".")).build();
232         IReportableListWalker.Builder builder = IReportableListWalker.builder(name);
233         sources.forEach(file -> builder.addReportable(new FileListWalker(new FileDocument(file, DocumentNameMatcher.MATCHES_ALL))));
234         reportables.forEach(builder::addReportable);
235         return builder;
236     }
237 
238     /**
239      * Gets the matcher that matches generated text.
240      * @return the matcher that matches generated text.
241      */
242     public IHeaderMatcher getGeneratedMatcher() {
243         return new AnyBuilder().setResource("/org/apache/rat/generation-keywords.txt").build();
244     }
245 
246     /**
247      * Retrieves the archive processing type.
248      * @return The archive processing type.
249      */
250     public Processing getArchiveProcessing() {
251         return archiveProcessing == null ? Defaults.ARCHIVE_PROCESSING : archiveProcessing;
252     }
253 
254     /**
255      * Sets the archive processing type. If not set will default to NOTIFICATION.
256      * @param archiveProcessing the type of processing archives should have.
257      */
258     public void setArchiveProcessing(final Processing archiveProcessing) {
259         this.archiveProcessing = archiveProcessing;
260     }
261 
262     /**
263      * Retrieves the archive processing type.
264      * @return The archive processing type.
265      */
266     public Processing getStandardProcessing() {
267         return standardProcessing == null ? Defaults.STANDARD_PROCESSING : standardProcessing;
268     }
269 
270     /**
271      * Sets the archive processing type. If not set will default to NOTIFICATION.
272      * @param standardProcessing the type of processing archives should have.
273      */
274     public void setStandardProcessing(final Processing standardProcessing) {
275         this.standardProcessing = standardProcessing;
276     }
277 
278     /**
279      * Set the log level for reporting collisions in the set of license families.
280      * <p>NOTE: should be set before licenses or license families are added.</p>
281      * @param level The log level to use.
282      */
283     public void logFamilyCollisions(final Level level) {
284         licenseSetFactory.logFamilyCollisions(level);
285     }
286 
287     /**
288      * Sets the reporting option for duplicate license families.
289      * @param state The ReportingSet.Option to use for reporting.
290      */
291     public void familyDuplicateOption(final ReportingSet.Options state) {
292         licenseSetFactory.familyDuplicateOption(state);
293     }
294 
295     /**
296      * Sets the log level for reporting license collisions.
297      * @param level The log level.
298      */
299     public void logLicenseCollisions(final Level level) {
300         licenseSetFactory.logLicenseCollisions(level);
301     }
302 
303     /**
304      * Sets the reporting option for duplicate licenses.
305      * @param state the ReportingSt.Option to use for reporting.
306      */
307     public void licenseDuplicateOption(final ReportingSet.Options state) {
308         licenseSetFactory.licenseDuplicateOption(state);
309     }
310 
311     /**
312      * Set the level of license families that should be output in the XML document.
313      * @param filter the license families to list.
314      */
315     public void listFamilies(final LicenseFilter filter) {
316         listFamilies = filter;
317     }
318 
319     /**
320      * Return the current filter that determines which families will be output in the XML document.
321      * @return the filter that defines the families to list.
322      */
323     public LicenseFilter listFamilies() {
324         return listFamilies;
325     }
326 
327     /**
328      * Set the level of licenses that should be output in the XML document.
329      * @param filter the licenses to list.
330      */
331     public void listLicenses(final LicenseFilter filter) {
332         listLicenses = filter;
333     }
334 
335     /**
336      * Gets the selected license filter.
337      * @return the filter to limit license display.
338      */
339     public LicenseFilter listLicenses() {
340         return listLicenses;
341     }
342 
343     /**
344      * Sets the dry run flag.
345      * @param state the state for the dry run flag.
346      */
347     public void setDryRun(final boolean state) {
348         dryRun = state;
349     }
350 
351     /**
352      * Returns the state of the dry run flag.
353      * @return the state of the dry run flag.
354      */
355     public boolean isDryRun() {
356         return dryRun;
357     }
358 
359     /**
360      * Excludes a StandardCollection of patterns.
361      * @param collection the StandardCollection to exclude.
362      * @see ExclusionProcessor#addExcludedCollection(StandardCollection)
363      */
364     public void addExcludedCollection(final StandardCollection collection) {
365         exclusionProcessor.addExcludedCollection(collection);
366     }
367 
368     /**
369      * Excludes the file processor defined in the StandardCollection.
370      * @param collection the StandardCollection to exclude.
371      * @see ExclusionProcessor#addFileProcessor(StandardCollection)
372      */
373     public void addExcludedFileProcessor(final StandardCollection collection) {
374         exclusionProcessor.addFileProcessor(collection);
375     }
376 
377     /**
378      * Excludes files that match a FileFilter.
379      * @param fileFilter the file filter to match.
380      */
381     public void addExcludedFilter(final FileFilter fileFilter) {
382         exclusionProcessor.addExcludedMatcher(new DocumentNameMatcher(fileFilter));
383     }
384 
385     /**
386      * Excludes files that match a DocumentNameMatcher.
387      * @param matcher the DocumentNameMatcher to match.
388      */
389     public void addExcludedMatcher(final DocumentNameMatcher matcher) {
390         exclusionProcessor.addExcludedMatcher(matcher);
391     }
392 
393     /**
394      * Excludes files that match the pattern.
395      *
396      * @param patterns the collection of patterns to exclude.
397      * @see ExclusionProcessor#addIncludedPatterns(Iterable)
398      */
399     public void addExcludedPatterns(final Iterable<String> patterns) {
400         exclusionProcessor.addExcludedPatterns(patterns);
401     }
402 
403     /**
404      * Adds the patterns from the standard collection as included patterns.
405      * @param collection the standard collection to include.
406      */
407     public void addIncludedCollection(final StandardCollection collection) {
408         exclusionProcessor.addIncludedCollection(collection);
409     }
410 
411     /**
412      * Adds the fileFilter to filter files that should be included, this overrides any
413      * exclusion of the same files.
414      * @param fileFilter the filter to identify files that should be included.
415      */
416     public void addIncludedFilter(final FileFilter fileFilter) {
417         exclusionProcessor.addIncludedMatcher(new DocumentNameMatcher(fileFilter));
418     }
419 
420     /**
421      * Add file patterns that are to be included. These patterns override any exclusion of
422      * the same files.
423      * @param patterns The iterable of Strings containing the patterns.
424      */
425     public void addIncludedPatterns(final Iterable<String> patterns) {
426         exclusionProcessor.addIncludedPatterns(patterns);
427     }
428 
429     /**
430      * Get the DocumentNameMatcher that excludes files found in the directory tree..
431      * @param baseDir the DocumentName for the base directory.
432      * @return the DocumentNameMatcher for the base directory.
433      */
434     public DocumentNameMatcher getDocumentExcluder(final DocumentName baseDir) {
435         return exclusionProcessor.getNameMatcher(baseDir);
436     }
437 
438     /**
439      * Gets the IOSupplier with the style sheet.
440      * @return the Supplier of the InputStream that is the XSLT style sheet to style
441      * the report with.
442      */
443     public IOSupplier<InputStream> getStyleSheet() {
444         return styleSheet;
445     }
446 
447     /**
448      * Sets the style sheet for custom processing. The IOSupplier may be called
449      * multiple times, so the input stream must be able to be opened and closed
450      * multiple times.
451      * @param styleSheet the XSLT style sheet to style the report with.
452      */
453     public void setStyleSheet(final IOSupplier<InputStream> styleSheet) {
454         this.styleSheet = styleSheet;
455     }
456 
457     /**
458      * Adds the licenses and approved licenses from the defaults object to the
459      * configuration. <em>Side effect:</em> if the report should be styled and no
460      * style sheet has been set the plain stylesheet from the defaults will be used.
461      * @param defaults The defaults to set.
462      */
463     public void setFrom(final Defaults defaults) {
464         licenseSetFactory.add(defaults.getLicenseSetFactory());
465         if (getStyleSheet() == null) {
466             setStyleSheet(StyleSheets.PLAIN.getStyleSheet());
467         }
468         defaults.getStandardExclusion().forEach(this::addExcludedCollection);
469     }
470 
471     /**
472      * Sets the style sheet.
473      * @param styleSheet the XSLT style sheet file to style the report with.
474      */
475     public void setStyleSheet(final File styleSheet) {
476         Objects.requireNonNull(styleSheet, "styleSheet file should not be null");
477         setStyleSheet(styleSheet.toURI());
478     }
479 
480     /**
481      * Sets the style sheet for custom processing. The stylesheet may be opened
482      * multiple times so the URI must be capable of being opened multiple times.
483      * @param styleSheet the URI of the XSLT style sheet to style the report with.
484      */
485     public void setStyleSheet(final URI styleSheet) {
486         Objects.requireNonNull(styleSheet, "Stylesheet file must not be null");
487         try {
488             setStyleSheet(styleSheet.toURL());
489         } catch (MalformedURLException e) {
490             throw new ConfigurationException("Unable to process stylesheet", e);
491         }
492     }
493 
494     /**
495      * Sets the style sheet for custom processing. The stylesheet may be opened
496      * multiple times so the URL must be capable of being opened multiple times.
497      * @param styleSheet the URL of the XSLT style sheet to style the report with.
498      */
499     public void setStyleSheet(final URL styleSheet) {
500         Objects.requireNonNull(styleSheet, "Stylesheet file must not be null");
501         setStyleSheet(styleSheet::openStream);
502     }
503 
504     /**
505      * Sets the supplier for the output stream. The supplier may be called multiple
506      * times to provide the stream. Suppliers should prepare streams that are
507      * appended to and that can be closed. If an {@code OutputStream} should not be
508      * closed consider wrapping it in a {@code CloseShieldOutputStream}
509      * @param out The OutputStream supplier that provides the output stream to write
510      * the report to. A null value will use System.out.
511      * @see CloseShieldOutputStream
512      */
513     public void setOut(final IOSupplier<OutputStream> out) {
514         this.out = out;
515     }
516 
517     /**
518      * Sets the OutputStream supplier to use the specified file. The file may be
519      * opened and closed several times. File is deleted first and then may be
520      * repeatedly opened in append mode.
521      * @see #setOut(IOSupplier)
522      * @param file The file to create the supplier with.
523      */
524     public void setOut(final File file) {
525         Objects.requireNonNull(file, "output file should not be null");
526         if (file.exists()) {
527             try {
528                 Files.delete(file.toPath());
529             } catch (IOException e) {
530                 DefaultLog.getInstance().warn("Unable to delete file: " + file);
531             }
532         }
533         File parent = file.getParentFile();
534         if (!parent.mkdirs() && !parent.isDirectory()) {
535             DefaultLog.getInstance().warn("Unable to create directory: " + file.getParentFile());
536         }
537         setOut(() -> new FileOutputStream(file, true));
538     }
539 
540     /**
541      * Returns the output stream supplier. If no stream has been set returns a
542      * supplier for System.out.
543      * @return The supplier of the output stream to write the report to.
544      */
545     public IOSupplier<OutputStream> getOutput() {
546         return out == null ? () -> CloseShieldOutputStream.wrap(System.out) : out;
547     }
548 
549     /**
550      * Gets a PrintWriter that wraps the output stream.
551      * @return A supplier for a PrintWriter that wraps the output stream.
552      * @see #getOutput()
553      */
554     public IOSupplier<PrintWriter> getWriter() {
555         return () -> new PrintWriter(new OutputStreamWriter(getOutput().get(), StandardCharsets.UTF_8));
556     }
557 
558     /**
559      * Adds a license to the list of licenses. Does not add the license to the list
560      * of approved licenses.
561      * @param license The license to add to the list of licenses.
562      */
563     public void addLicense(final ILicense license) {
564         licenseSetFactory.addLicense(license);
565     }
566 
567     /**
568      * Adds a license to the list of licenses. Does not add the license to the list
569      * of approved licenses.
570      * @param builder The license builder to build and add to the list of licenses.
571      * @return The ILicense implementation that was added.
572      */
573     public ILicense addLicense(final ILicense.Builder builder) {
574         return licenseSetFactory.addLicense(builder);
575     }
576 
577     /**
578      * Adds multiple licenses to the list of licenses. Does not add the licenses to
579      * the list of approved licenses.
580      * @param licenses The licenses to add.
581      */
582     public void addLicenses(final Collection<ILicense> licenses) {
583         licenseSetFactory.addLicenses(licenses);
584     }
585 
586     /**
587      * Adds a license family to the list of families. Does not add the family to the
588      * list of approved licenses.
589      * @param family The license family to add to the list of license families.
590      */
591     public void addFamily(final ILicenseFamily family) {
592        licenseSetFactory.addFamily(family);
593     }
594 
595     /**
596      * Adds a license family to the list of families. Does not add the family to the
597      * list of approved licenses.
598      * @param builder The licenseFamily.Builder to build and add to the list of
599      * licenses.
600      */
601     public void addFamily(final ILicenseFamily.Builder builder) {
602         licenseSetFactory.addFamily(builder);
603     }
604 
605     /**
606      * Adds multiple families to the list of license families. Does not add the
607      * licenses to the list of approved licenses.
608      * @param families The license families to add.
609      */
610     public void addFamilies(final Collection<ILicenseFamily> families) {
611         families.forEach(this::addApprovedLicenseCategory);
612     }
613 
614     /**
615      * Adds an ILicenseFamily to the list of approved licenses.
616      * @param approvedILicenseFamily the LicenseFamily to add.
617      */
618     public void addApprovedLicenseCategory(final ILicenseFamily approvedILicenseFamily) {
619         addApprovedLicenseCategory(approvedILicenseFamily.getFamilyCategory());
620     }
621 
622     /**
623      * Adds a license family category (id) to the list of approved licenses
624      * @param familyCategory the category to add.
625      */
626     public void addApprovedLicenseCategory(final String familyCategory) {
627         licenseSetFactory.approveLicenseCategory(familyCategory);
628     }
629 
630     /**
631      * Adds a collection of license family categories to the set of approved license
632      * names.
633      * @param approvedLicenseCategories set of approved license categories.
634      */
635     public void addApprovedLicenseCategories(final Collection<String> approvedLicenseCategories) {
636         approvedLicenseCategories.forEach(this::addApprovedLicenseCategory);
637     }
638 
639     /**
640      * Adds a license family category to the list of approved licenses. <em>Once a
641      * license has been removed from the approved list it cannot be re-added</em>
642      * @param familyCategory the category to add.
643      */
644     public void removeApprovedLicenseCategory(final String familyCategory) {
645         licenseSetFactory.removeLicenseCategory(ILicenseFamily.makeCategory(familyCategory));
646     }
647 
648     /**
649      * Removes a license family category from the list of approved licenses.
650      * <em>Once a license has been removed from the approved list it cannot be
651      * re-added</em>
652      * @param familyCategory the family category to remove.
653      */
654     public void removeApprovedLicenseCategories(final Collection<String> familyCategory) {
655         familyCategory.forEach(this::removeApprovedLicenseCategory);
656     }
657 
658     /**
659      * Gets the SortedSet of approved license categories. <em>Once a license has
660      * been removed from the approved list it cannot be re-added</em>
661      * @param filter The LicenseFilter to filter the categories by.
662      * @return the Sorted set of approved license categories.
663      */
664     public SortedSet<String> getLicenseCategories(final LicenseFilter filter) {
665         return licenseSetFactory.getLicenseCategories(filter);
666     }
667 
668     /**
669      * Gets the SortedSet of approved license categories. <em>Once a license has
670      * been removed from the approved list it cannot be re-added</em>
671      * @param filter The LicenseFilter to filter the licenses by.
672      * @return the Sorted set of approved license categories.
673      */
674     public SortedSet<ILicense> getLicenses(final LicenseFilter filter) {
675         return licenseSetFactory.getLicenses(filter);
676     }
677 
678     /**
679      * Gets the SortedSet of approved license categories. <em>Once a license has
680      * been removed from the approved list it cannot be re-added</em>
681      * @param filter The LicenseFilter to filter the licenses by.
682      * @return the Sorted set of approved license categories.
683      */
684     public SortedSet<String> getLicenseIds(final LicenseFilter filter) {
685         return licenseSetFactory.getLicenseIds(filter);
686     }
687 
688     /**
689      * Adds an ILicenseFamily to the list of approved licenses.
690      * @param approvedLicense the License to add.
691      */
692     public void addApprovedLicenseId(final ILicense approvedLicense) {
693         addApprovedLicenseId(approvedLicense.getId());
694     }
695 
696     /**
697      * Adds a license family category (id) to the list of approved licenses
698      * @param licenseId the license id to add.
699      */
700     public void addApprovedLicenseId(final String licenseId) {
701         licenseSetFactory.approveLicenseId(licenseId);
702     }
703 
704     /**
705      * Adds a collection of license family categories to the set of approved license
706      * names.
707      * @param approvedLicenseIds set of approved license IDs.
708      */
709     public void addApprovedLicenseIds(final Collection<String> approvedLicenseIds) {
710         approvedLicenseIds.forEach(this::addApprovedLicenseId);
711     }
712 
713     /**
714      * Adds a license family category to the list of approved licenses. <em>Once a
715      * license has been removed from the approved list it cannot be re-added</em>
716      * @param licenseId the license ID to add.
717      */
718     public void removeApprovedLicenseId(final String licenseId) {
719         licenseSetFactory.removeLicenseId(licenseId);
720     }
721 
722     /**
723      * Removes a license family category from the list of approved licenses.
724      * <em>Once a license has been removed from the approved list it cannot be
725      * re-added</em>
726      * @param licenseIds the license IDs to remove.
727      */
728     public void removeApprovedLicenseIds(final Collection<String> licenseIds) {
729         licenseIds.forEach(this::removeApprovedLicenseId);
730     }
731 
732     /**
733      * Returns the optional license copyright being added if RAT is adding headers.
734      * This value is ignored, if no license headers are added.
735      * @return the optional copyright message.
736      * @see #isAddingLicenses()
737      */
738     public String getCopyrightMessage() {
739         return copyrightMessage;
740     }
741 
742     /**
743      * Sets the optional copyright message used if RAT is adding license headers.
744      * This value is ignored, if no license headers are added.
745      * @param copyrightMessage message to set.
746      * @see #isAddingLicenses()
747      */
748     public void setCopyrightMessage(final String copyrightMessage) {
749         this.copyrightMessage = copyrightMessage;
750     }
751 
752     /**
753      * Gets the flag that determines if license headers are "forced" overwriting existing files.
754      * This value is ignored if RAT is not adding licenses.
755      * @return {@code true} if RAT is forcing the adding license headers.
756      * @see #isAddingLicenses()
757      */
758     public boolean isAddingLicensesForced() {
759         return addingLicensesForced;
760     }
761 
762     /**
763      * Gets the flag that determines if license headers should be added if missing.
764      * @return whether RAT should add missing license headers.
765      * @see #isAddingLicensesForced()
766      * @see #getCopyrightMessage()
767      */
768     public boolean isAddingLicenses() {
769         return addingLicenses;
770     }
771 
772     /**
773      * Sets whether RAT should enable, disable, or force the adding of license
774      * headers.
775      * @param addLicenseHeaders enables/disables or forces adding of licenses
776      * headers.
777      * @see #isAddingLicenses()
778      * @see #setCopyrightMessage(String)
779      */
780     public void setAddLicenseHeaders(final AddLicenseHeaders addLicenseHeaders) {
781         addingLicenses = false;
782         addingLicensesForced = false;
783         switch (addLicenseHeaders) {
784         case FALSE:
785             // do nothing
786             break;
787         case FORCED:
788             addingLicensesForced = true;
789             addingLicenses = true;
790             break;
791         case TRUE:
792             addingLicenses = true;
793             break;
794         }
795     }
796 
797     /**
798      * Gets a sorted set of ILicenseFamily objects based on {@code filter}. if
799      * filter is set:
800      * <ul>
801      * <li>{@code all} - All licenses families will be returned.</li>
802      * <li>{@code approved} - Only approved license families will be returned</li>
803      * <li>{@code none} - No license families will be returned</li>
804      * </ul>
805      * @param filter The license filter.
806      * @return The set of defined licenses.
807      */
808     public SortedSet<ILicenseFamily> getLicenseFamilies(final LicenseFilter filter) {
809         return licenseSetFactory.getLicenseFamilies(filter);
810     }
811 
812     /**
813      * Gets the ClaimValidator for the configuration.
814      * @return the ClaimValidator.
815      */
816     public ClaimValidator getClaimValidator() {
817         return claimValidator;
818     }
819 
820     /**
821      * Gets the enclosed LicenseSetFactory.
822      * @return the license set factory.
823      */
824     public LicenseSetFactory getLicenseSetFactory() {
825         return licenseSetFactory;
826     }
827 
828     /**
829      * Validates that the configuration is valid.
830      * @param logger String consumer to log warning messages to.
831      * @throws ConfigurationException on configuration error.
832      */
833     public void validate(final Consumer<String> logger) {
834         if (!hasSource()) {
835             String msg = "At least one source must be specified";
836             logger.accept(msg);
837             throw new ConfigurationException(msg);
838         }
839         if (licenseSetFactory.getLicenses(LicenseFilter.ALL).isEmpty()) {
840             String msg = "You must specify at least one license";
841             logger.accept(msg);
842             throw new ConfigurationException(msg);
843         }
844     }
845 }