1
2
3
4 package net.sourceforge.pmd;
5
6 import java.io.File;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.net.HttpURLConnection;
10 import java.net.URL;
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import net.sourceforge.pmd.util.ResourceLoader;
15 import net.sourceforge.pmd.util.StringUtil;
16
17 import org.apache.commons.io.IOUtils;
18 import org.apache.commons.lang3.StringUtils;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 public class RuleSetReferenceId {
86 private final boolean external;
87 private final String ruleSetFileName;
88 private final boolean allRules;
89 private final String ruleName;
90 private final RuleSetReferenceId externalRuleSetReferenceId;
91
92
93
94
95
96
97
98 public RuleSetReferenceId(final String id) {
99
100 this(id, null);
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 public RuleSetReferenceId(final String id, final RuleSetReferenceId externalRuleSetReferenceId) {
119
120 if (externalRuleSetReferenceId != null && !externalRuleSetReferenceId.isExternal()) {
121 throw new IllegalArgumentException("Cannot pair with non-external <" + externalRuleSetReferenceId + ">.");
122 }
123
124 if (id != null && id.indexOf(',') >= 0) {
125 throw new IllegalArgumentException("A single RuleSetReferenceId cannot contain ',' (comma) characters: "
126 + id);
127 }
128
129
130
131
132 if (isValidUrl(id)) {
133
134 external = true;
135 ruleSetFileName = StringUtils.strip(id);
136 allRules = true;
137 ruleName = null;
138 } else if (isFullRuleSetName(id)) {
139
140 external = true;
141 ruleSetFileName = id;
142 allRules = true;
143 ruleName = null;
144 } else {
145 String tempRuleName = getRuleName(id);
146 String tempRuleSetFileName = tempRuleName != null && id != null ? id.substring(0, id.length()
147 - tempRuleName.length() - 1) : id;
148
149 if (isValidUrl(tempRuleSetFileName)) {
150
151
152 external = true;
153 ruleSetFileName = StringUtils.strip(tempRuleSetFileName);
154 ruleName = StringUtils.strip(tempRuleName);
155 allRules = tempRuleName == null;
156 } else if (isHttpUrl(id)) {
157
158
159
160 external = true;
161 ruleSetFileName = StringUtils.strip(id);
162 allRules = true;
163 ruleName = null;
164 } else if (isFullRuleSetName(tempRuleSetFileName)) {
165
166
167 external = true;
168 ruleSetFileName = tempRuleSetFileName;
169 ruleName = tempRuleName;
170 allRules = tempRuleName == null;
171 } else {
172
173 String builtinRuleSet = resolveBuiltInRuleset(tempRuleSetFileName);
174 if (checkRulesetExists(builtinRuleSet)) {
175 external = true;
176 ruleSetFileName = builtinRuleSet;
177 ruleName = tempRuleName;
178 allRules = tempRuleName == null;
179 } else {
180
181
182
183
184
185
186
187
188
189
190
191
192
193 if (tempRuleSetFileName == null || tempRuleSetFileName.contains(File.separator)) {
194 external = true;
195 ruleSetFileName = id;
196 ruleName = null;
197 allRules = true;
198 } else {
199 external = externalRuleSetReferenceId != null ? externalRuleSetReferenceId.isExternal() : false;
200 ruleSetFileName = externalRuleSetReferenceId != null ? externalRuleSetReferenceId
201 .getRuleSetFileName() : null;
202 ruleName = id;
203 allRules = false;
204 }
205 }
206 }
207 }
208
209 if (this.external && this.ruleName != null && !this.ruleName.equals(id) && externalRuleSetReferenceId != null) {
210 throw new IllegalArgumentException("Cannot pair external <" + this + "> with external <"
211 + externalRuleSetReferenceId + ">.");
212 }
213 this.externalRuleSetReferenceId = externalRuleSetReferenceId;
214 }
215
216
217
218
219
220
221
222
223 private boolean checkRulesetExists(String name) {
224 boolean resourceFound = false;
225 if (name != null) {
226 try {
227 InputStream resource = ResourceLoader.loadResourceAsStream(name,
228 RuleSetReferenceId.class.getClassLoader());
229 if (resource != null) {
230 resourceFound = true;
231 IOUtils.closeQuietly(resource);
232 }
233 } catch (RuleSetNotFoundException e) {
234 resourceFound = false;
235 }
236 }
237 return resourceFound;
238 }
239
240
241
242
243
244
245
246
247
248 private String resolveBuiltInRuleset(final String name) {
249 String result = null;
250 if (name != null) {
251
252 int index = name.indexOf('-');
253 if (index >= 0) {
254
255 result = "rulesets/" + name.substring(0, index) + "/" + name.substring(index + 1) + ".xml";
256 } else {
257
258 if (name.matches("[0-9]+.*")) {
259 result = "rulesets/releases/" + name + ".xml";
260 } else {
261
262 result = name;
263 }
264 }
265 }
266 return result;
267 }
268
269
270
271
272
273
274
275
276
277 private String getRuleName(final String rulesetName) {
278 String result = null;
279 if (rulesetName != null) {
280
281
282 final int separatorIndex = Math.max(rulesetName.lastIndexOf('/'), rulesetName.lastIndexOf('\\'));
283 if (separatorIndex >= 0 && separatorIndex != rulesetName.length() - 1) {
284 result = rulesetName.substring(separatorIndex + 1);
285 }
286 }
287 return result;
288 }
289
290 private static boolean isHttpUrl(String name) {
291
292 if (name == null) {
293 return false;
294 }
295
296 name = StringUtils.strip(name);
297 if (name.startsWith("http://") || name.startsWith("https://")) {
298 return true;
299 }
300
301 return false;
302 }
303
304 private static boolean isValidUrl(String name) {
305 if (isHttpUrl(name)) {
306 String url = StringUtils.strip(name);
307 try {
308 HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
309 connection.setRequestMethod("HEAD");
310 connection.setConnectTimeout(ResourceLoader.TIMEOUT);
311 connection.setReadTimeout(ResourceLoader.TIMEOUT);
312 int responseCode = connection.getResponseCode();
313 if (responseCode == 200) {
314 return true;
315 }
316 } catch (IOException e) {
317 return false;
318 }
319 }
320 return false;
321 }
322
323 private static boolean isFullRuleSetName(String name) {
324
325 return name != null && name.endsWith(".xml");
326 }
327
328
329
330
331
332
333
334
335 public static List<RuleSetReferenceId> parse(String referenceString) {
336 List<RuleSetReferenceId> references = new ArrayList<RuleSetReferenceId>();
337 if (referenceString != null && referenceString.trim().length() > 0) {
338
339 if (referenceString.indexOf(',') == -1) {
340 references.add(new RuleSetReferenceId(referenceString));
341 } else {
342 for (String name : referenceString.split(",")) {
343 references.add(new RuleSetReferenceId(name.trim()));
344 }
345 }
346 }
347 return references;
348 }
349
350
351
352
353
354
355
356 public boolean isExternal() {
357 return external;
358 }
359
360
361
362
363
364
365
366 public boolean isAllRules() {
367 return allRules;
368 }
369
370
371
372
373
374
375
376 public String getRuleSetFileName() {
377 return ruleSetFileName;
378 }
379
380
381
382
383
384
385 public String getRuleName() {
386 return ruleName;
387 }
388
389
390
391
392
393
394
395
396
397
398
399
400 public InputStream getInputStream(ClassLoader classLoader) throws RuleSetNotFoundException {
401 if (externalRuleSetReferenceId == null) {
402 InputStream in = StringUtil.isEmpty(ruleSetFileName) ? null : ResourceLoader.loadResourceAsStream(
403 ruleSetFileName, classLoader);
404 if (in == null) {
405 throw new RuleSetNotFoundException("Can't find resource '" + ruleSetFileName + "' for rule '"
406 + ruleName + "'" + ". Make sure the resource is a valid file or URL and is on the CLASSPATH. "
407 + "Here's the current classpath: " + System.getProperty("java.class.path"));
408 }
409 return in;
410 } else {
411 return externalRuleSetReferenceId.getInputStream(classLoader);
412 }
413 }
414
415
416
417
418
419
420
421
422
423 public String toString() {
424 if (ruleSetFileName != null) {
425 if (allRules) {
426 return ruleSetFileName;
427 } else {
428 return ruleSetFileName + "/" + ruleName;
429 }
430
431 } else {
432 if (allRules) {
433 return "anonymous all Rule";
434 } else {
435 return ruleName;
436 }
437 }
438 }
439 }