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