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.maven.plugins.checkstyle;
20
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
25 import org.apache.commons.lang3.StringUtils;
26
27 /**
28 * Tooling for Checkstyle rules conventions: names, categories.
29 *
30 * @author Hervé Boutemy
31 * @since 2.13
32 */
33 public final class RuleUtil {
34 private RuleUtil() {
35 // hide utility class constructor
36 }
37
38 private static final String CHECKSTYLE_PACKAGE = "com.puppycrawl.tools.checkstyle.checks";
39
40 /**
41 * Get the rule name from an audit event.
42 *
43 * @param event the audit event
44 * @return the rule name, which is the class name without package and removed eventual "Check" suffix
45 */
46 public static String getName(AuditEvent event) {
47 return getName(event.getSourceName());
48 }
49 /**
50 * Get the rule name from an audit event source name.
51 *
52 * @param eventSrcName the audit event source name
53 * @return the rule name, which is the class name without package and removed eventual "Check" suffix
54 */
55 public static String getName(String eventSrcName) {
56 if (eventSrcName == null) {
57 return null;
58 }
59
60 if (eventSrcName.endsWith("Check")) {
61 eventSrcName = eventSrcName.substring(0, eventSrcName.length() - 5);
62 }
63
64 return eventSrcName.substring(eventSrcName.lastIndexOf('.') + 1);
65 }
66
67 /**
68 * Get the rule category from an audit event.
69 *
70 * @param event the audit event
71 * @return the rule category, which is the last package name or "misc" or "extension"
72 */
73 public static String getCategory(AuditEvent event) {
74 return getCategory(event.getSourceName());
75 }
76
77 /**
78 * Get the rule category from an audit event source name.
79 *
80 * @param eventSrcName the audit event source name
81 * @return the rule category, which is the last package name or "misc" or "extension"
82 */
83 public static String getCategory(String eventSrcName) {
84 if (eventSrcName == null) {
85 return null;
86 }
87
88 int end = eventSrcName.lastIndexOf('.');
89 eventSrcName = end == -1 ? eventSrcName : eventSrcName.substring(0, end);
90
91 if (CHECKSTYLE_PACKAGE.equals(eventSrcName)) {
92 return "misc";
93 } else if (!eventSrcName.startsWith(CHECKSTYLE_PACKAGE)) {
94 return "extension";
95 }
96
97 return eventSrcName.substring(eventSrcName.lastIndexOf('.') + 1);
98 }
99
100 public static List<Matcher> parseMatchers(String[] specs) {
101 List<Matcher> matchers = new ArrayList<>();
102 for (String spec : specs) {
103 if (StringUtils.isBlank(spec)) {
104 continue;
105 }
106 spec = spec.trim();
107 Matcher matcher;
108 if (Character.isUpperCase(spec.charAt(0))) {
109 // spec starting with uppercase is a rule name
110 matcher = new RuleMatcher(spec);
111 } else if ("misc".equals(spec)) {
112 // "misc" is a special case
113 matcher = new PackageMatcher(CHECKSTYLE_PACKAGE);
114 } else if ("extension".equals(spec)) {
115 // "extension" is a special case
116 matcher = new ExtensionMatcher();
117 } else if (!spec.contains(".")) {
118 matcher = new PackageMatcher(CHECKSTYLE_PACKAGE + '.' + spec);
119 } else {
120 // by default, spec is a package name
121 matcher = new PackageMatcher(spec);
122 }
123 matchers.add(matcher);
124 }
125 return matchers;
126 }
127
128 /**
129 * Audit event source name matcher.
130 */
131 public interface Matcher {
132 /**
133 * Does the event source name match?
134 * @param eventSrcName the event source name
135 * @return boolean
136 */
137 boolean match(String eventSrcName);
138 }
139
140 private static class RuleMatcher implements Matcher {
141 private final String rule;
142
143 RuleMatcher(String rule) {
144 this.rule = rule;
145 }
146
147 public boolean match(String eventSrcName) {
148 return rule.equals(getName(eventSrcName));
149 }
150 }
151
152 private static class PackageMatcher implements Matcher {
153 private final String packageName;
154
155 PackageMatcher(String packageName) {
156 this.packageName = packageName;
157 }
158
159 public boolean match(String eventSrcName) {
160 return eventSrcName.startsWith(packageName)
161 && !eventSrcName.substring(packageName.length() + 1).contains(".");
162 }
163 }
164
165 /**
166 * An extension does not start with Checkstyle package.
167 */
168 private static class ExtensionMatcher implements Matcher {
169 public boolean match(String eventSrcName) {
170 return !eventSrcName.startsWith(CHECKSTYLE_PACKAGE);
171 }
172 }
173 }