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
20 package org.apache.rat.report.claim;
21
22 import java.util.ArrayList;
23 import java.util.Comparator;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.concurrent.ConcurrentHashMap;
27
28 import org.apache.commons.lang3.StringUtils;
29 import org.apache.rat.api.Document;
30
31 /**
32 * This class provides a numerical overview about
33 * the report.
34 */
35 public class ClaimStatistic {
36 // keep the counter types in alphabetical order
37 /** The counter types */
38 public enum Counter {
39 /** count of approved files */
40 APPROVED("A count of approved licenses.", -1, 0),
41 /** count of archive files */
42 ARCHIVES("A count of archive files.", -1, 0),
43 /** count of binary files */
44 BINARIES("A count of binary files.", -1, 0),
45 /** count of distinct document types */
46 DOCUMENT_TYPES("A count of distinct document types.", -1, 1),
47 /** count of generated/ignored files */
48 IGNORED("A count of ignored files.", -1, 0),
49 /** count of license categories */
50 LICENSE_CATEGORIES("A count of distinct license categories.", -1, 1),
51 /** count of distinct license names */
52 LICENSE_NAMES("A count of distinct license names.", -1, 1),
53 /** count of note files */
54 NOTICES("A count of notice files.", -1, 0),
55 /** count of standard files */
56 STANDARDS("A count of standard files.", -1, 1),
57 /** count of unapproved files */
58 UNAPPROVED("A count of unapproved licenses.", 0, 0),
59 /** count of unknown files */
60 UNKNOWN("A count of unknown file types.", -1, 0);
61
62 /** The description of the counter */
63 private final String description;
64 /** The default max value for the counter */
65 private final int defaultMaxValue;
66 /** The default minimum value for the counter */
67 private final int defaultMinValue;
68
69 Counter(final String description, final int defaultMaxValue, final int defaultMinValue) {
70 this.description = description;
71 this.defaultMaxValue = defaultMaxValue;
72 this.defaultMinValue = defaultMinValue;
73 }
74
75 /**
76 * Gets the description of the counter.
77 * @return The description of the counter.
78 */
79 public String getDescription() {
80 return description;
81 }
82
83 /**
84 * Gets the default maximum value for the counter.
85 * @return the default maximum value for the counter.
86 */
87 public int getDefaultMaxValue() {
88 return defaultMaxValue;
89 }
90 /**
91 * Gets the default minimum value for the counter.
92 * @return the default maximum value for the counter.
93 */
94 public int getDefaultMinValue() {
95 return defaultMinValue;
96 }
97
98 /**
99 * Display name is capitalized and any underscores are replaced by spaces.
100 * @return displayName of the counter, capitalized and without underscores.
101 */
102 public String displayName() {
103 return StringUtils.capitalize(name().replaceAll("_", " ").toLowerCase(Locale.ROOT));
104 }
105 }
106
107 /** Count of license family name to counter */
108 private final ConcurrentHashMap<String, IntCounter> licenseNameMap = new ConcurrentHashMap<>();
109 /** Map of license family category to counter */
110 private final ConcurrentHashMap<String, IntCounter> licenseFamilyCategoryMap = new ConcurrentHashMap<>();
111 /** Map of document type to counter */
112 private final ConcurrentHashMap<Document.Type, IntCounter> documentTypeMap = new ConcurrentHashMap<>();
113 /** Map of counter type to value */
114 private final ConcurrentHashMap<ClaimStatistic.Counter, IntCounter> counterMap = new ConcurrentHashMap<>();
115
116 /**
117 * Converts null counter to 0.
118 *
119 * @param counter the Counter to retrieve the value from.
120 * @return 0 if counter is {@code null} or counter value otherwise.
121 */
122 private int getValue(final IntCounter counter) {
123 return counter == null ? 0 : counter.value();
124 }
125
126 /**
127 * Returns the counts for the counter.
128 * @param counter the counter to get the value for.
129 * @return the number times the counter type was seen.
130 */
131 public int getCounter(final Counter counter) {
132 return getValue(counterMap.get(counter));
133 }
134
135 /**
136 * Increments the counts for the counter.
137 * @param counter the counter to increment.
138 * @param value the value to increment the counter by.
139 */
140 public void incCounter(final Counter counter, final int value) {
141 counterMap.compute(counter, (k, v) -> v == null ? new IntCounter().increment(value) : v.increment(value));
142 }
143
144 /**
145 * Gets the counts for the Document.Type.
146 * @param documentType the Document.Type to get the counter for.
147 * @return the number times the Document.Type was seen.
148 */
149 public int getCounter(final Document.Type documentType) {
150 return getValue(documentTypeMap.get(documentType));
151 }
152
153 /**
154 * Gets the list of Document.Types seen in the run.
155 * @return the list of Document.Types seen in the run.
156 */
157 public List<Document.Type> getDocumentTypes() {
158 List<Document.Type> result = new ArrayList<>(documentTypeMap.keySet());
159 result.sort(Comparator.comparing(Enum::name));
160 return result;
161 }
162
163 /**
164 * Increments the number of times the Document.Type was seen.
165 * @param documentType the Document.Type to increment.
166 * @param value the value to increment the counter by.
167 */
168 public void incCounter(final Document.Type documentType, final int value) {
169 documentTypeMap.compute(documentType, (k, v) -> updateCounter(Counter.DOCUMENT_TYPES, v, value));
170 switch (documentType) {
171 case STANDARD:
172 incCounter(Counter.STANDARDS, value);
173 break;
174 case ARCHIVE:
175 incCounter(Counter.ARCHIVES, value);
176 break;
177 case BINARY:
178 incCounter(Counter.BINARIES, value);
179 break;
180 case NOTICE:
181 incCounter(Counter.NOTICES, value);
182 break;
183 case UNKNOWN:
184 incCounter(Counter.UNKNOWN, value);
185 break;
186 case IGNORED:
187 incCounter(Counter.IGNORED, value);
188 break;
189 }
190 }
191
192 /**
193 * Gets the counts for the license category.
194 * @param licenseFamilyCategory the license family category to get the count for.
195 * @return the number of times the license family category was seen.
196 */
197 public int getLicenseCategoryCount(final String licenseFamilyCategory) {
198 return getValue(licenseFamilyCategoryMap.get(licenseFamilyCategory));
199 }
200
201 /**
202 * Gets the counts for the license name.
203 * @param licenseName the license name to get the count for.
204 * @return the number of times the license family category was seen.
205 */
206 public int getLicenseNameCount(final String licenseName) {
207 return getValue(licenseNameMap.get(licenseName));
208 }
209
210 /**
211 * Updates the intCounter with the value and if the intCounter was null creates a new one and registers the
212 * creation as a counter type.
213 * @param counter the Type of the counter.
214 * @param intCounter the IntCounter to update. May be null.
215 * @param value the value to add to the int counter.
216 * @return the intCounter if it was not {@code null}, a new IntCounter otherwise.
217 */
218 private IntCounter updateCounter(final Counter counter, final IntCounter intCounter, final int value) {
219 if (intCounter == null) {
220 incCounter(counter, 1);
221 return new IntCounter().increment(value);
222 } else {
223 return intCounter.increment(value);
224 }
225 }
226
227 /**
228 * Increments the number of times a license family category was seen.
229 * @param licenseFamilyCategory the License family category to increment.
230 * @param value the value to increment the count by.
231 */
232 public void incLicenseCategoryCount(final String licenseFamilyCategory, final int value) {
233 licenseFamilyCategoryMap.compute(licenseFamilyCategory, (k, v) -> updateCounter(Counter.LICENSE_CATEGORIES, v, value));
234 }
235
236 /**
237 * Gets the set of license family categories that were seen.
238 * @return A set of license family categories.
239 */
240 public List<String> getLicenseFamilyCategories() {
241 List<String> result = new ArrayList<>(licenseFamilyCategoryMap.keySet());
242 result.sort(String::compareTo);
243 return result;
244 }
245
246 /**
247 * Gets the license names sorted by name.
248 * @return sorted list of license names.
249 */
250 public List<String> getLicenseNames() {
251 List<String> result = new ArrayList<>(licenseNameMap.keySet());
252 result.sort(String::compareTo);
253 return result;
254 }
255
256 /**
257 * Increments the license family name count.
258 * @param licenseName the license name to increment.
259 * @param value the value to increment the count by.
260 */
261 public void incLicenseNameCount(final String licenseName, final int value) {
262 licenseNameMap.compute(licenseName, (k, v) -> updateCounter(Counter.LICENSE_NAMES, v, value));
263 }
264
265 /**
266 * A class that wraps an int and allows easy increment and retrieval.
267 */
268 static class IntCounter {
269 /**
270 * The value of the counter
271 */
272 private int value;
273
274 /**
275 * Increment the count.
276 * @param count the count to increment by (can be negative).
277 * @return this.
278 */
279 public IntCounter increment(final int count) {
280 value += count;
281 return this;
282 }
283
284 /**
285 * Retrieves the count.
286 * @return the count contained by this counter.
287 */
288 public int value() {
289 return value;
290 }
291 }
292 }