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.IOException;
23  import java.io.InputStream;
24  import java.util.ArrayList;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.regex.Pattern;
29  
30  import javax.xml.XMLConstants;
31  import javax.xml.parsers.DocumentBuilder;
32  import javax.xml.parsers.DocumentBuilderFactory;
33  import javax.xml.parsers.ParserConfigurationException;
34  
35  import org.reflections.Reflections;
36  import org.reflections.scanners.Scanners;
37  import org.w3c.dom.Document;
38  import org.w3c.dom.Element;
39  import org.w3c.dom.NodeList;
40  import org.xml.sax.SAXException;
41  
42  
43  
44  
45  
46  public final class XmlMetaReader {
47  
48      
49      private static final String XML_TAG_NAME = "name";
50  
51      
52      private static final String XML_TAG_DESCRIPTION = "description";
53  
54      
55  
56  
57      private XmlMetaReader() {
58      }
59  
60      
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73      public static List<ModuleDetails> readAllModulesIncludingThirdPartyIfAny(
74              String... thirdPartyPackages) {
75          final Set<String> standardModuleFileNames = new Reflections(
76                  "com.puppycrawl.tools.checkstyle.meta", Scanners.Resources)
77                  .getResources(Pattern.compile(".*\\.xml"));
78          final Set<String> allMetadataSources = new HashSet<>(standardModuleFileNames);
79          for (String packageName : thirdPartyPackages) {
80              final Set<String> thirdPartyModuleFileNames =
81                      new Reflections(packageName, Scanners.Resources)
82                              .getResources(Pattern.compile(".*checkstylemeta-.*\\.xml"));
83              allMetadataSources.addAll(thirdPartyModuleFileNames);
84          }
85  
86          final List<ModuleDetails> result = new ArrayList<>(allMetadataSources.size());
87          for (String fileName : allMetadataSources) {
88              final ModuleType moduleType;
89              if (fileName.endsWith("FileFilter.xml")) {
90                  moduleType = ModuleType.FILEFILTER;
91              }
92              else if (fileName.endsWith("Filter.xml")) {
93                  moduleType = ModuleType.FILTER;
94              }
95              else {
96                  moduleType = ModuleType.CHECK;
97              }
98              final ModuleDetails moduleDetails;
99              try {
100                 moduleDetails = read(XmlMetaReader.class.getResourceAsStream("/" + fileName),
101                         moduleType);
102             }
103             catch (ParserConfigurationException | IOException | SAXException exc) {
104                 throw new IllegalStateException("Problem to read all modules including third "
105                         + "party if any. Problem detected at file: " + fileName, exc);
106             }
107             result.add(moduleDetails);
108         }
109 
110         return result;
111     }
112 
113     
114 
115 
116 
117 
118 
119 
120 
121 
122 
123     public static ModuleDetails read(InputStream moduleMetadataStream, ModuleType moduleType)
124             throws ParserConfigurationException, IOException, SAXException {
125         ModuleDetails result = null;
126         if (moduleType != null) {
127             final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
128             factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
129             factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
130             final DocumentBuilder builder = factory.newDocumentBuilder();
131             final Document document = builder.parse(moduleMetadataStream);
132             final Element root = document.getDocumentElement();
133             final Element element = getDirectChildsByTag(root, "module").get(0);
134             final Element module = getDirectChildsByTag(element, moduleType.getLabel()).get(0);
135             result = new ModuleDetails();
136 
137             result.setModuleType(moduleType);
138             populateModule(module, result);
139         }
140         return result;
141     }
142 
143     
144 
145 
146 
147 
148 
149     private static void populateModule(Element mod, ModuleDetails moduleDetails) {
150         moduleDetails.setName(getAttributeValue(mod, XML_TAG_NAME));
151         moduleDetails.setFullQualifiedName(getAttributeValue(mod, "fully-qualified-name"));
152         moduleDetails.setParent(getAttributeValue(mod, "parent"));
153         moduleDetails.setDescription(getDirectChildsByTag(mod, XML_TAG_DESCRIPTION).get(0)
154                 .getFirstChild().getNodeValue());
155         final List<Element> properties = getDirectChildsByTag(mod, "properties");
156         if (!properties.isEmpty()) {
157             final List<ModulePropertyDetails> modulePropertyDetailsList =
158                     createProperties(properties.get(0));
159             moduleDetails.addToProperties(modulePropertyDetailsList);
160         }
161         final List<String> messageKeys =
162                 getListContentByAttribute(mod,
163                         "message-keys", "message-key", "key");
164         if (messageKeys != null) {
165             moduleDetails.addToViolationMessages(messageKeys);
166         }
167     }
168 
169     
170 
171 
172 
173 
174 
175     private static List<ModulePropertyDetails> createProperties(Element properties) {
176         final NodeList propertyList = properties.getElementsByTagName("property");
177         final int propertyListLength = propertyList.getLength();
178         final List<ModulePropertyDetails> result = new ArrayList<>(propertyListLength);
179         for (int i = 0; i < propertyListLength; i++) {
180             final ModulePropertyDetails propertyDetails = new ModulePropertyDetails();
181             final Element prop = (Element) propertyList.item(i);
182             propertyDetails.setName(getAttributeValue(prop, XML_TAG_NAME));
183             propertyDetails.setType(getAttributeValue(prop, "type"));
184             final String defaultValueTag = "default-value";
185             if (prop.hasAttribute(defaultValueTag)) {
186                 propertyDetails.setDefaultValue(getAttributeValue(prop, defaultValueTag));
187             }
188             final String validationTypeTag = "validation-type";
189             if (prop.hasAttribute(validationTypeTag)) {
190                 propertyDetails.setValidationType(getAttributeValue(prop, validationTypeTag));
191             }
192             propertyDetails.setDescription(getDirectChildsByTag(prop, XML_TAG_DESCRIPTION)
193                     .get(0).getFirstChild().getNodeValue());
194             result.add(propertyDetails);
195         }
196         return result;
197     }
198 
199     
200 
201 
202 
203 
204 
205 
206 
207 
208     private static List<String> getListContentByAttribute(Element element, String listParent,
209                                                          String listOption, String attribute) {
210         final List<Element> children = getDirectChildsByTag(element, listParent);
211         List<String> result = null;
212         if (!children.isEmpty()) {
213             final NodeList nodeList = children.get(0).getElementsByTagName(listOption);
214             final int nodeListLength = nodeList.getLength();
215             final List<String> listContent = new ArrayList<>(nodeListLength);
216             for (int j = 0; j < nodeListLength; j++) {
217                 listContent.add(getAttributeValue((Element) nodeList.item(j), attribute));
218             }
219             result = listContent;
220         }
221         return result;
222     }
223 
224     
225 
226 
227 
228 
229 
230 
231     private static List<Element> getDirectChildsByTag(Element element, String sTagName) {
232         final NodeList children = element.getElementsByTagName(sTagName);
233         final List<Element> res = new ArrayList<>();
234         for (int i = 0; i < children.getLength(); i++) {
235             if (children.item(i).getParentNode().equals(element)) {
236                 res.add((Element) children.item(i));
237             }
238         }
239         return res;
240     }
241 
242     
243 
244 
245 
246 
247 
248 
249     private static String getAttributeValue(Element element, String attribute) {
250         return element.getAttributes().getNamedItem(attribute).getNodeValue();
251     }
252 
253 }