1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.analysis.matchers;
20
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.Set;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.rat.ConfigurationException;
31 import org.apache.rat.analysis.IHeaders;
32 import org.apache.rat.config.parameters.ComponentType;
33 import org.apache.rat.config.parameters.ConfigComponent;
34
35
36
37
38
39
40
41
42
43
44
45
46 public final class SPDXMatcherFactory {
47
48
49
50
51 private static final Map<String, SPDXMatcherFactory.Match> MATCHER_MAP = new HashMap<>();
52
53
54
55
56 public static final SPDXMatcherFactory INSTANCE = new SPDXMatcherFactory();
57
58
59
60
61 static final String LICENSE_IDENTIFIER = "SPDX-License-Identifier:";
62
63
64
65
66
67 private static final Pattern GROUP_SELECTOR = Pattern.compile(".*" + LICENSE_IDENTIFIER + "\\s([A-Za-z0-9\\.\\-]+)");
68
69
70
71
72 private final Set<String> lastMatch;
73
74
75
76
77 private boolean checked;
78
79
80
81
82 private SPDXMatcherFactory() {
83 lastMatch = new HashSet<>();
84 }
85
86
87
88
89 private void reset() {
90 lastMatch.clear();
91 checked = false;
92 }
93
94
95
96
97
98
99
100 public Match create(final String spdxId) {
101 if (StringUtils.isBlank(spdxId)) {
102 throw new ConfigurationException("'SPDX' type matcher requires a name");
103 }
104 Match matcher = MATCHER_MAP.get(spdxId);
105 if (matcher == null) {
106 matcher = new Match(spdxId);
107 MATCHER_MAP.put(spdxId, matcher);
108 }
109 return matcher;
110 }
111
112
113
114
115
116
117
118
119 private boolean check(final String documentText, final Match caller) {
120
121
122
123
124 if (!checked) {
125 checked = true;
126 if (documentText.contains(LICENSE_IDENTIFIER)) {
127 Matcher matcher = GROUP_SELECTOR.matcher(documentText);
128 while (matcher.find()) {
129 lastMatch.add(matcher.group(1));
130 }
131 }
132 }
133
134 return lastMatch.contains(caller.spdxId);
135 }
136
137
138
139
140 @ConfigComponent(type = ComponentType.MATCHER, name = "spdx", desc = "Matches SPDX enclosed license identifier.")
141 public class Match extends AbstractHeaderMatcher {
142
143
144
145 @ConfigComponent(type = ComponentType.PARAMETER, name = "name", desc = "The SPDX identifier string")
146 private final String spdxId;
147
148
149
150
151
152 public String getName() {
153 return spdxId;
154 }
155
156
157
158
159
160
161
162 Match(final String spdxId) {
163 super("SPDX:" + spdxId);
164 Objects.requireNonNull(spdxId, "SpdxId is required");
165 this.spdxId = spdxId;
166 }
167
168 @Override
169 public boolean matches(final IHeaders headers) {
170 return SPDXMatcherFactory.this.check(headers.raw(), this);
171 }
172
173 @Override
174 public void reset() {
175 super.reset();
176 SPDXMatcherFactory.this.reset();
177 }
178 }
179 }