1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.meta;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.lang.reflect.Field;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.stream.Stream;
33
34 import javax.xml.parsers.ParserConfigurationException;
35 import javax.xml.transform.TransformerException;
36
37 import org.apache.maven.doxia.macro.MacroExecutionException;
38
39 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
40 import com.puppycrawl.tools.checkstyle.site.JavadocScraperResultUtil;
41 import com.puppycrawl.tools.checkstyle.site.ModuleJavadocParsingUtil;
42 import com.puppycrawl.tools.checkstyle.site.PropertyDetails;
43 import com.puppycrawl.tools.checkstyle.site.SiteUtil;
44
45
46 public final class MetadataGeneratorUtil {
47
48
49 private MetadataGeneratorUtil() {
50 }
51
52
53
54
55
56
57
58
59
60 public static void generate(String path, String... moduleFolders)
61 throws IOException, CheckstyleException {
62 final List<File> modulesToProcess =
63 getTargetFiles(path, moduleFolders);
64
65 try {
66 for (File file : modulesToProcess) {
67 final String fileName = file.getName();
68
69 if (fileName.startsWith("Abstract")
70 && !"AbstractClassNameCheck.java".equals(fileName)) {
71 continue;
72 }
73
74 final ModuleDetails moduleDetails = getModuleDetails(file);
75 writeMetadataFile(moduleDetails);
76 }
77 }
78 catch (MacroExecutionException macroException) {
79 throw new CheckstyleException("Failed to execute macro", macroException);
80 }
81 }
82
83
84
85
86
87
88
89
90 private static ModuleDetails getModuleDetails(File file) throws MacroExecutionException {
91 final String moduleName = SiteUtil.FINAL_CHECK.matcher(SiteUtil.getModuleName(file))
92 .replaceAll("");
93
94 final Object instance = SiteUtil.getModuleInstance(moduleName);
95 final Class<?> clss = instance.getClass();
96 final String fullyQualifiedName = clss.getName();
97
98 final String parentModule = SiteUtil.getParentModule(clss);
99 final Object parentModuleInstance = SiteUtil.getModuleInstance(parentModule);
100 final String parentModuleString = parentModuleInstance.getClass().getName();
101
102 final ModuleType moduleType = getModuleType(moduleName);
103
104 final Set<String> messageKeys = SiteUtil.getMessageKeys(clss);
105
106 final String className = SiteUtil.getModuleName(file);
107 final Set<String> properties = SiteUtil.getPropertiesForDocumentation(clss, instance);
108 final Map<String, PropertyDetails> scrapedPropertyDetails = SiteUtil
109 .buildPropertyDetails(properties, className, file.toPath(), instance);
110 String description = JavadocScraperResultUtil.getModuleDescription();
111
112 final String notes = JavadocScraperResultUtil.getModuleNotes();
113 if (!notes.isEmpty()) {
114 description = description + "\n\n " + notes;
115 }
116
117 final List<ModulePropertyDetails> propertiesDetails = getPropertiesDetails(
118 scrapedPropertyDetails.values(), className, instance);
119
120 return new ModuleDetails(moduleName, fullyQualifiedName, parentModuleString,
121 description, moduleType, propertiesDetails, new ArrayList<>(messageKeys));
122 }
123
124
125
126
127
128
129
130 private static ModuleType getModuleType(String moduleName) {
131 final ModuleType result;
132 if (moduleName.endsWith("FileFilter")) {
133 result = ModuleType.FILEFILTER;
134 }
135 else if (moduleName.endsWith("Filter")) {
136 result = ModuleType.FILTER;
137 }
138 else {
139 result = ModuleType.CHECK;
140 }
141 return result;
142 }
143
144
145
146
147
148
149
150
151
152
153 private static List<ModulePropertyDetails> getPropertiesDetails(
154 Collection<PropertyDetails> propertiesDetails,
155 String className, Object instance)
156 throws MacroExecutionException {
157 final List<ModulePropertyDetails> result = new ArrayList<>(propertiesDetails.size());
158 for (PropertyDetails details : propertiesDetails) {
159 final String property = details.getName();
160 final String description = details.getDescription();
161 final Field propertyField = SiteUtil.getField(instance.getClass(), property);
162
163 final String type = SiteUtil.getType(propertyField, property, className, instance);
164
165 final String defaultValue = getPropertyDefaultValue(details);
166 final String validationType = getValidationType(property, propertyField);
167
168 result.add(new ModulePropertyDetails(property, type, defaultValue,
169 validationType, description));
170 }
171 return result;
172 }
173
174
175
176
177
178
179
180 private static String getPropertyDefaultValue(PropertyDetails details) {
181 final String defaultValue;
182 if (details.getDefaultValueTokens().isEmpty()) {
183 final String raw = details.getDefaultValue();
184 if ("{}".equals(raw)) {
185 defaultValue = "";
186 }
187 else {
188 defaultValue = raw;
189 }
190 }
191 else {
192 defaultValue = String.join(SiteUtil.COMMA, details.getDefaultValueTokens());
193 }
194 return defaultValue;
195 }
196
197
198
199
200
201
202
203 private static void writeMetadataFile(ModuleDetails moduleDetails)
204 throws CheckstyleException {
205 try {
206 XmlMetaWriter.write(moduleDetails);
207 }
208 catch (TransformerException | ParserConfigurationException example) {
209 throw new CheckstyleException(
210 "Failed to write metadata into XML file for module: "
211 + moduleDetails.getName(), example);
212 }
213 }
214
215
216
217
218
219
220
221
222 private static String getValidationType(String propertyName, Field propertyField) {
223 final String validationType;
224 if (SiteUtil.TOKENS.equals(propertyName) || SiteUtil.JAVADOC_TOKENS.equals(propertyName)) {
225 validationType = "tokenSet";
226 }
227 else if (propertyField != null
228 && ModuleJavadocParsingUtil.isPropertySpecialTokenProp(propertyField)) {
229 validationType = "tokenTypesSet";
230 }
231 else {
232 validationType = null;
233 }
234 return validationType;
235 }
236
237
238
239
240
241
242
243
244
245 private static List<File> getTargetFiles(String path, String... moduleFolders)
246 throws IOException {
247 final List<File> validFiles = new ArrayList<>();
248 for (String folder : moduleFolders) {
249 try (Stream<Path> files = Files.walk(Path.of(path + "/" + folder))) {
250 validFiles.addAll(
251 files.map(Path::toFile)
252 .filter(file -> {
253 final String fileName = file.getName();
254 return fileName.endsWith("SuppressWarningsHolder.java")
255 || fileName.endsWith("Check.java")
256 || fileName.endsWith("Filter.java");
257 })
258 .toList());
259 }
260 }
261
262 return validFiles;
263 }
264 }