View Javadoc
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 }