1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.config.exclusion;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.Set;
27 import java.util.TreeSet;
28 import java.util.stream.Collectors;
29
30 import org.apache.rat.document.DocumentName;
31 import org.apache.rat.document.DocumentNameMatcher;
32 import org.apache.rat.utils.DefaultLog;
33 import org.apache.rat.utils.ExtendedIterator;
34
35 import static java.lang.String.format;
36
37
38
39
40
41 public class ExclusionProcessor {
42
43 private final Set<String> excludedPatterns;
44
45 private final List<DocumentNameMatcher> excludedPaths;
46
47 private final Set<String> includedPatterns;
48
49 private final List<DocumentNameMatcher> includedPaths;
50
51
52
53
54 private final Set<StandardCollection> fileProcessors;
55
56 private final Set<StandardCollection> includedCollections;
57
58 private final Set<StandardCollection> excludedCollections;
59
60 private DocumentNameMatcher lastMatcher;
61
62 private DocumentName lastMatcherBaseDir;
63
64
65
66
67 public ExclusionProcessor() {
68 excludedPatterns = new HashSet<>();
69 excludedPaths = new ArrayList<>();
70 includedPatterns = new HashSet<>();
71 includedPaths = new ArrayList<>();
72 fileProcessors = new HashSet<>();
73 includedCollections = new HashSet<>();
74 excludedCollections = new HashSet<>();
75 }
76
77
78 private void resetLastMatcher() {
79 lastMatcher = null;
80 lastMatcherBaseDir = null;
81 }
82
83
84
85
86
87
88 public ExclusionProcessor addIncludedPatterns(final Iterable<String> patterns) {
89 DefaultLog.getInstance().debug(format("Including patterns: %s", String.join(", ", patterns)));
90 patterns.forEach(includedPatterns::add);
91 resetLastMatcher();
92 return this;
93 }
94
95
96
97
98
99
100 public ExclusionProcessor addIncludedMatcher(final DocumentNameMatcher matcher) {
101 if (matcher != null) {
102 includedPaths.add(matcher);
103 resetLastMatcher();
104 }
105 return this;
106 }
107
108
109
110
111
112
113 public ExclusionProcessor addFileProcessor(final StandardCollection collection) {
114 if (collection != null) {
115 DefaultLog.getInstance().debug(format("Processing exclude file from %s.", collection));
116 fileProcessors.add(collection);
117 resetLastMatcher();
118 }
119 return this;
120 }
121
122
123
124
125
126
127 public ExclusionProcessor addIncludedCollection(final StandardCollection collection) {
128 if (collection != null) {
129 DefaultLog.getInstance().debug(format("Including %s collection.", collection));
130 includedCollections.add(collection);
131 resetLastMatcher();
132 }
133 return this;
134 }
135
136
137
138
139
140
141 public ExclusionProcessor addExcludedPatterns(final Iterable<String> patterns) {
142 DefaultLog.getInstance().debug(format("Excluding patterns: %s", String.join(", ", patterns)));
143 patterns.forEach(excludedPatterns::add);
144 resetLastMatcher();
145 return this;
146 }
147
148
149
150
151
152
153 public ExclusionProcessor addExcludedMatcher(final DocumentNameMatcher matcher) {
154 if (matcher != null) {
155 excludedPaths.add(matcher);
156 resetLastMatcher();
157 }
158 return this;
159 }
160
161
162
163
164
165 public void reportExclusions(final Appendable appendable) throws IOException {
166 appendable.append(format("Excluding patterns: %s%n", String.join(", ", excludedPatterns)));
167 appendable.append(format("Including patterns: %s%n", String.join(", ", includedPatterns)));
168 for (StandardCollection sc : excludedCollections) {
169 appendable.append(format("Excluding %s collection.%n", sc.name()));
170 }
171 for (StandardCollection sc : includedCollections) {
172 appendable.append(format("Including %s collection.%n", sc.name()));
173 }
174 for (StandardCollection sc : fileProcessors) {
175 appendable.append(format("Processing exclude file from %s.%n", sc.name()));
176 }
177 }
178
179
180
181
182
183
184
185 public ExclusionProcessor addExcludedCollection(final StandardCollection collection) {
186 if (collection != null) {
187 DefaultLog.getInstance().debug(format("Excluding %s collection.", collection));
188 excludedCollections.add(collection);
189 resetLastMatcher();
190 }
191 return this;
192 }
193
194
195
196
197
198
199
200 public DocumentNameMatcher getNameMatcher(final DocumentName basedir) {
201
202
203
204 if (lastMatcher == null || !basedir.equals(lastMatcherBaseDir)) {
205 lastMatcherBaseDir = basedir;
206
207
208 final List<MatcherSet> matchers = extractFileProcessors(basedir);
209 final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder();
210 DocumentName.Builder nameBuilder = DocumentName.builder(basedir).setBaseName(basedir);
211 extractPatterns(nameBuilder, fromCommandLine);
212 extractCollectionPatterns(nameBuilder, fromCommandLine);
213 extractCollectionMatchers(fromCommandLine);
214 extractPaths(fromCommandLine);
215 matchers.add(fromCommandLine.build());
216
217 lastMatcher = MatcherSet.merge(matchers).createMatcher();
218 DefaultLog.getInstance().debug(format("Created matcher set for %s%n%s", basedir.getName(),
219 lastMatcher));
220 }
221 return lastMatcher;
222 }
223
224
225
226
227
228
229 private List<MatcherSet> extractFileProcessors(final DocumentName basedir) {
230 final List<MatcherSet> fileProcessorList = new ArrayList<>();
231 for (StandardCollection sc : fileProcessors) {
232 ExtendedIterator<List<MatcherSet>> iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir));
233 if (iter.hasNext()) {
234 iter.forEachRemaining(fileProcessorList::addAll);
235 } else {
236 DefaultLog.getInstance().debug(String.format("%s does not have a fileProcessor.", sc));
237 }
238 }
239 return fileProcessorList;
240 }
241
242
243
244
245
246
247
248
249 private String preparePattern(final DocumentName documentName, final String pattern) {
250 return ExclusionUtils.qualifyPattern(documentName,
251 ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator()));
252 }
253
254
255
256
257
258
259 private void extractPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) {
260 DocumentName name = nameBuilder.setName("Patterns").build();
261 if (!excludedPatterns.isEmpty()) {
262 matcherBuilder.addExcluded(name, excludedPatterns.stream()
263 .map(s -> preparePattern(name, s))
264 .collect(Collectors.toSet()));
265 }
266 if (!includedPatterns.isEmpty()) {
267 matcherBuilder.addIncluded(name, includedPatterns.stream()
268 .map(s -> preparePattern(name, s)).collect(Collectors.toSet()));
269 }
270 }
271
272
273
274
275
276
277 private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) {
278 final Set<String> incl = new TreeSet<>();
279 final Set<String> excl = new TreeSet<>();
280 for (StandardCollection sc : includedCollections) {
281 Set<String> patterns = sc.patterns();
282 if (patterns.isEmpty()) {
283 DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for inclusion.", sc));
284 } else {
285 MatcherSet.Builder.segregateList(incl, excl, sc.patterns());
286 }
287 }
288 for (StandardCollection sc : excludedCollections) {
289 Set<String> patterns = sc.patterns();
290 if (patterns.isEmpty()) {
291 DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for exclusion.", sc));
292 } else {
293 MatcherSet.Builder.segregateList(excl, incl, sc.patterns());
294 }
295 }
296 DocumentName name = nameBuilder.setName("Collections").build();
297 matcherBuilder
298 .addExcluded(name, excl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet()))
299 .addIncluded(name, incl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet()));
300 }
301
302
303
304
305
306 private void extractCollectionMatchers(final MatcherSet.Builder matcherBuilder) {
307 ExtendedIterator.create(includedCollections.iterator())
308 .map(StandardCollection::staticDocumentNameMatcher)
309 .filter(Objects::nonNull)
310 .forEachRemaining(matcherBuilder::addIncluded);
311
312 ExtendedIterator.create(excludedCollections.iterator())
313 .map(StandardCollection::staticDocumentNameMatcher)
314 .filter(Objects::nonNull)
315 .forEachRemaining(matcherBuilder::addExcluded);
316 }
317
318
319
320
321
322 private void extractPaths(final MatcherSet.Builder matcherBuilder) {
323 if (!includedPaths.isEmpty()) {
324 for (DocumentNameMatcher matcher : includedPaths) {
325 DefaultLog.getInstance().debug(format("Including path matcher %s", matcher));
326 matcherBuilder.addIncluded(matcher);
327 }
328 }
329 if (!excludedPaths.isEmpty()) {
330 for (DocumentNameMatcher matcher : excludedPaths) {
331 DefaultLog.getInstance().debug(format("Excluding path matcher %s", matcher));
332 matcherBuilder.addExcluded(matcher);
333 }
334 }
335 }
336
337 }