RuleSetWriter xref

View Javadoc
1 /**
2  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html 
3  */
4 package net.sourceforge.pmd;
5 
6 import java.io.OutputStream;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 
12 import javax.xml.parsers.DocumentBuilder;
13 import javax.xml.parsers.DocumentBuilderFactory;
14 import javax.xml.parsers.FactoryConfigurationError;
15 import javax.xml.parsers.ParserConfigurationException;
16 import javax.xml.transform.OutputKeys;
17 import javax.xml.transform.Transformer;
18 import javax.xml.transform.TransformerException;
19 import javax.xml.transform.TransformerFactory;
20 import javax.xml.transform.dom.DOMSource;
21 import javax.xml.transform.stream.StreamResult;
22 
23 import net.sourceforge.pmd.lang.Language;
24 import net.sourceforge.pmd.lang.LanguageVersion;
25 import net.sourceforge.pmd.lang.rule.ImmutableLanguage;
26 import net.sourceforge.pmd.lang.rule.RuleReference;
27 import net.sourceforge.pmd.lang.rule.XPathRule;
28 import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper;
29 import net.sourceforge.pmd.lang.rule.properties.factories.PropertyDescriptorUtil;
30 
31 import org.apache.commons.io.IOUtils;
32 import org.w3c.dom.CDATASection;
33 import org.w3c.dom.DOMException;
34 import org.w3c.dom.Document;
35 import org.w3c.dom.Element;
36 import org.w3c.dom.Text;
37 
38 /**
39  * This class represents a way to serialize a RuleSet to an XML configuration file.
40  */
41 public class RuleSetWriter {
42 	
43 public static final String RULESET_NS_URI = "http://pmd.sourceforge.net/ruleset/2.0.0";
44 
45 	private final OutputStream outputStream;
46 private Document document;
47 private Set<String> ruleSetFileNames;
48 
49 public RuleSetWriter(OutputStream outputStream) {
50 		this.outputStream = outputStream;
51 }
52 
53 public void close() {
54 	IOUtils.closeQuietly(outputStream);
55 }
56 
57 public void write(RuleSet ruleSet) {
58 		try {
59 		 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
60 		 documentBuilderFactory.setNamespaceAware(true);
61 		 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
62 		 document = documentBuilder.newDocument();
63 		 ruleSetFileNames = new HashSet<String>();
64 	
65 		 Element ruleSetElement = createRuleSetElement(ruleSet);
66 		 document.appendChild(ruleSetElement);
67 	
68 		 TransformerFactory transformerFactory = TransformerFactory.newInstance();
69 		 try {
70 		 	transformerFactory.setAttribute("indent-number", 3);
71 		 	} catch (IllegalArgumentException iae) {
72 		 		//ignore it, specific to one parser
73 		 	}
74 		 Transformer transformer = transformerFactory.newTransformer();
75 		 transformer.setOutputProperty(OutputKeys.METHOD, "xml");
76 		 // This is as close to pretty printing as we'll get using standard Java APIs.
77 		 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
78 		 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
79 		 transformer.transform(new DOMSource(document), new StreamResult(outputStream));
80 		} catch (DOMException e) {
81 		 throw new RuntimeException(e);
82 		} catch (FactoryConfigurationError e) {
83 		 throw new RuntimeException(e);
84 		} catch (ParserConfigurationException e) {
85 		 throw new RuntimeException(e);
86 		} catch (TransformerException e) {
87 		 throw new RuntimeException(e);
88 		}
89 }
90 
91 private Element createRuleSetElement(RuleSet ruleSet) {
92 	Element ruleSetElement = document.createElementNS(RULESET_NS_URI, "ruleset");
93 	ruleSetElement.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
94 		ruleSetElement.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", RULESET_NS_URI + " http://pmd.sourceforge.net/ruleset_2_0_0.xsd");
95 		ruleSetElement.setAttribute("name", ruleSet.getName());
96 	
97 		Element descriptionElement = createDescriptionElement(ruleSet.getDescription());
98 		ruleSetElement.appendChild(descriptionElement);
99 	
100 		for (String excludePattern : ruleSet.getExcludePatterns()) {
101 		 Element excludePatternElement = createExcludePatternElement(excludePattern);
102 		 ruleSetElement.appendChild(excludePatternElement);
103 		}
104 		for (String includePattern : ruleSet.getIncludePatterns()) {
105 		 Element includePatternElement = createIncludePatternElement(includePattern);
106 		 ruleSetElement.appendChild(includePatternElement);
107 		}
108 		for (Rule rule : ruleSet.getRules()) {
109 		 Element ruleElement = createRuleElement(rule);
110 		 if (ruleElement != null) {
111 			ruleSetElement.appendChild(ruleElement);
112 		 }
113 	}
114 
115 	return ruleSetElement;
116 }
117 
118 private Element createDescriptionElement(String description) {
119 	return createTextElement("description", description);
120 }
121 
122 private Element createExcludePatternElement(String excludePattern) {
123 	return createTextElement("exclude-pattern", excludePattern);
124 }
125 
126 private Element createIncludePatternElement(String includePattern) {
127 	return createTextElement("include-pattern", includePattern);
128 }
129 
130 private Element createRuleElement() {
131 	return document.createElementNS(RULESET_NS_URI, "rule");
132 }
133 
134 private Element createExcludeElement(String exclude) {
135 Element element = document.createElementNS(RULESET_NS_URI, "exclude");
136 element.setAttribute("name", exclude);
137 return element;
138 }
139 
140 private Element createExampleElement(String example) {
141 	return createCDATASectionElement("example", example);
142 }
143 
144 private Element createPriorityElement(RulePriority priority) {
145 	return createTextElement("priority", String.valueOf(priority.getPriority()));
146 }
147 
148 private Element createPropertiesElement() {
149 	return document.createElementNS(RULESET_NS_URI, "properties");
150 }
151 
152 private Element createRuleElement(Rule rule) {
153 		if (rule instanceof RuleReference) {
154 		 RuleReference ruleReference = (RuleReference) rule;
155 		 RuleSetReference ruleSetReference = ruleReference.getRuleSetReference();
156 		 if (ruleSetReference.isAllRules()) {
157 			if (!ruleSetFileNames.contains(ruleSetReference.getRuleSetFileName())) {
158 			 ruleSetFileNames.add(ruleSetReference.getRuleSetFileName());
159 			 Element ruleSetReferenceElement = createRuleSetReferenceElement(ruleSetReference);
160 			 return ruleSetReferenceElement;
161 			} else {
162 			 return null;
163 			}
164 		 } else {
165 			Language language = ruleReference.getOverriddenLanguage();
166 			LanguageVersion minimumLanguageVersion = ruleReference.getOverriddenMinimumLanguageVersion();
167 			LanguageVersion maximumLanguageVersion = ruleReference.getOverriddenMaximumLanguageVersion();
168 			Boolean deprecated = ruleReference.isOverriddenDeprecated();
169 			String name = ruleReference.getOverriddenName();
170 			String ref = ruleReference.getRuleSetReference().getRuleSetFileName() + "/" + ruleReference.getName();
171 			String message = ruleReference.getOverriddenMessage();
172 			String externalInfoUrl = ruleReference.getOverriddenExternalInfoUrl();
173 			String description = ruleReference.getOverriddenDescription();
174 			RulePriority priority = ruleReference.getOverriddenPriority();
175 			List<PropertyDescriptor<?>> propertyDescriptors = ruleReference.getOverriddenPropertyDescriptors();
176 			Map<PropertyDescriptor<?>, Object> propertiesByPropertyDescriptor = ruleReference.getOverriddenPropertiesByPropertyDescriptor();
177 			List<String> examples = ruleReference.getOverriddenExamples();
178 			
179 			return createSingleRuleElement(language, minimumLanguageVersion, maximumLanguageVersion, deprecated,
180 				name, null, ref, message, externalInfoUrl, null, null, null, description, priority,
181 				propertyDescriptors, propertiesByPropertyDescriptor, examples);
182 		 }
183 		} else {
184 		 return createSingleRuleElement(rule instanceof ImmutableLanguage ? null : rule.getLanguage(), 
185 		 	rule.getMinimumLanguageVersion(), rule.getMaximumLanguageVersion(), rule.isDeprecated(),
186 			 rule.getName(), rule.getSince(), null, rule.getMessage(), rule.getExternalInfoUrl(),
187 			 rule.getRuleClass(), rule.usesDFA(), rule.usesTypeResolution(), rule.getDescription(), 
188 			 rule.getPriority(), rule.getPropertyDescriptors(), rule.getPropertiesByPropertyDescriptor(),
189 			 rule.getExamples());
190 		}
191 }
192 
193 private void setIfNonNull(Object value, Element target, String id) {
194 	if (value != null) {
195 		target.setAttribute(id, value.toString());
196 	}
197 }
198 
199 private Element createSingleRuleElement(Language language, LanguageVersion minimumLanguageVersion,
200 	 LanguageVersion maximumLanguageVersion, Boolean deprecated, String name, String since, String ref,
201 	 String message, String externalInfoUrl, String clazz, Boolean dfa, Boolean typeResolution,
202 	 String description, RulePriority priority, List<PropertyDescriptor<?>> propertyDescriptors,
203 	 Map<PropertyDescriptor<?>, Object> propertiesByPropertyDescriptor, List<String> examples) {
204 		Element ruleElement = createRuleElement();
205 		if (language != null) {
206 		 ruleElement.setAttribute("language", language.getTerseName());
207 		}
208 		if (minimumLanguageVersion != null) {
209 		 ruleElement.setAttribute("minimumLanguageVersion", minimumLanguageVersion.getVersion());
210 		}
211 		if (maximumLanguageVersion != null) {
212 		 ruleElement.setAttribute("maximumLanguageVersion", maximumLanguageVersion.getVersion());
213 		}
214 		
215 		setIfNonNull(deprecated, 	 ruleElement, 	"deprecated");
216 		setIfNonNull(name, 			 ruleElement, 	"name");
217 		setIfNonNull(since, 		 ruleElement, 	"since");
218 		setIfNonNull(ref, 			 ruleElement,	"ref");
219 		setIfNonNull(message, 		 ruleElement, 	"message");
220 		setIfNonNull(clazz, 		 ruleElement, 	"class");
221 		setIfNonNull(externalInfoUrl, ruleElement, "externalInfoUrl");
222 		setIfNonNull(dfa, 			 ruleElement, "dfa");
223 		setIfNonNull(typeResolution, ruleElement, "typeResolution");
224 	
225 		if (description != null) {
226 		 Element descriptionElement = createDescriptionElement(description);
227 		 ruleElement.appendChild(descriptionElement);
228 		}
229 		if (priority != null) {
230 		 Element priorityElement = createPriorityElement(priority);
231 		 ruleElement.appendChild(priorityElement);
232 		}
233 		Element propertiesElement = createPropertiesElement(propertyDescriptors, propertiesByPropertyDescriptor);
234 		if (propertiesElement != null) {
235 		 ruleElement.appendChild(propertiesElement);
236 		}
237 		if (examples != null) {
238 		 for (String example : examples) {
239 			Element exampleElement = createExampleElement(example);
240 			ruleElement.appendChild(exampleElement);
241 		 }
242 		}
243 		return ruleElement;
244 }
245 
246 private Element createRuleSetReferenceElement(RuleSetReference ruleSetReference) {
247 		Element ruleSetReferenceElement = createRuleElement();
248 		ruleSetReferenceElement.setAttribute("ref", ruleSetReference.getRuleSetFileName());
249 		for (String exclude : ruleSetReference.getExcludes()) {
250 		 Element excludeElement = createExcludeElement(exclude);
251 		 ruleSetReferenceElement.appendChild(excludeElement);
252 		}
253 		return ruleSetReferenceElement;
254 }
255 
256 @SuppressWarnings("PMD.CompareObjectsWithEquals")
257 private Element createPropertiesElement(List<PropertyDescriptor<?>> propertyDescriptors, Map<PropertyDescriptor<?>, Object> propertiesByPropertyDescriptor) {
258 
259 		Element propertiesElement = null;
260 		if (propertyDescriptors != null) {
261 		 
262 		 for (PropertyDescriptor<?> propertyDescriptor : propertyDescriptors) {		// For each provided PropertyDescriptor
263 			
264 			if (propertyDescriptor instanceof PropertyDescriptorWrapper) {				// Any wrapper property needs to go out as a definition.
265 			 if (propertiesElement == null) {
266 			 	propertiesElement = createPropertiesElement();
267 			 }
268 			 
269 			 Element propertyElement = createPropertyDefinitionElementBR(((PropertyDescriptorWrapper<?>) propertyDescriptor).getPropertyDescriptor());
270 			 propertiesElement.appendChild(propertyElement);
271 			} else {			 
272 			 if (propertiesByPropertyDescriptor != null) {		// Otherwise, any property which has a value different than the default needs to go out as a value.
273 				Object defaultValue = propertyDescriptor.defaultValue();
274 				Object value = propertiesByPropertyDescriptor.get(propertyDescriptor);
275 				if (value != defaultValue && (value == null || !value.equals(defaultValue))) {
276 				 if (propertiesElement == null) {
277 				 	propertiesElement = createPropertiesElement();
278 				 }
279 				 
280 				 Element propertyElement = createPropertyValueElement(propertyDescriptor, value);
281 				 propertiesElement.appendChild(propertyElement);
282 					}
283 			 }
284 			}
285 		}
286 	}
287 
288 	if (propertiesByPropertyDescriptor != null) {
289 	 // Then, for each PropertyDescriptor not explicitly provided
290 	 for (Map.Entry<PropertyDescriptor<?>, Object> entry : propertiesByPropertyDescriptor.entrySet()) {
291 		// If not explicitly given...
292 		PropertyDescriptor<?> propertyDescriptor = entry.getKey();
293 		if (!propertyDescriptors.contains(propertyDescriptor)) {
294 		 // Otherwise, any property which has a value different than the
295 		 // default needs to go out as a value.
296 		 Object defaultValue = propertyDescriptor.defaultValue();
297 		 Object value = entry.getValue();
298 		 if (value != defaultValue && (value == null || !value.equals(defaultValue))) {
299 			if (propertiesElement == null) {
300 			 propertiesElement = createPropertiesElement();
301 			}
302 			Element propertyElement = createPropertyValueElement(propertyDescriptor, value);
303 			propertiesElement.appendChild(propertyElement);
304 		 }
305 		}
306 	 }
307 	}
308 	return propertiesElement;
309 }
310 
311 private Element createPropertyValueElement(PropertyDescriptor propertyDescriptor, Object value) {
312 		Element propertyElement = document.createElementNS(RULESET_NS_URI, "property");
313 		propertyElement.setAttribute("name", propertyDescriptor.name());
314 		String valueString = propertyDescriptor.asDelimitedString(value);
315 		if (XPathRule.XPATH_DESCRIPTOR.equals(propertyDescriptor)) {
316 		 Element valueElement = createCDATASectionElement("value", valueString);
317 		 propertyElement.appendChild(valueElement);
318 		} else {
319 		 propertyElement.setAttribute("value", valueString);
320 		}
321 	
322 		return propertyElement;
323 }
324 
325 //	private Element createPropertyDefinitionElement(PropertyDescriptor<?> propertyDescriptor) {
326 //		Element propertyElement = createPropertyValueElement(propertyDescriptor, propertyDescriptor.defaultValue());
327 //		
328 //		propertyElement.setAttribute("description", propertyDescriptor.description());
329 //		String type = PropertyDescriptorFactory.getPropertyDescriptorType(propertyDescriptor);
330 //		propertyElement.setAttribute("type", type);
331 //		
332 //		if (propertyDescriptor.isMultiValue()) {
333 //			propertyElement.setAttribute("delimiter", String.valueOf(propertyDescriptor.multiValueDelimiter()));
334 //		}
335 //		
336 //		if (propertyDescriptor instanceof AbstractNumericProperty) {
337 //			propertyElement.setAttribute("min", String.valueOf(((AbstractNumericProperty<?>) propertyDescriptor).lowerLimit()));
338 //			propertyElement.setAttribute("max", String.valueOf(((AbstractNumericProperty<?>) propertyDescriptor).upperLimit()));
339 //		}
340 //
341 //		return propertyElement;
342 // }
343 	
344 	private Element createPropertyDefinitionElementBR(PropertyDescriptor<?> propertyDescriptor) {
345 		
346 		final Element propertyElement = createPropertyValueElement(propertyDescriptor, propertyDescriptor.defaultValue());
347 		propertyElement.setAttribute(PropertyDescriptorFields.TYPE, PropertyDescriptorUtil.typeIdFor(propertyDescriptor.type()));
348 		
349 		Map<String, String> propertyValuesById = propertyDescriptor.attributeValuesById();
350 		for (Map.Entry<String, String> entry : propertyValuesById.entrySet()) {
351 			propertyElement.setAttribute(entry.getKey(), entry.getValue());
352 		}
353 		
354 		return propertyElement;
355 }
356 
357 private Element createTextElement(String name, String value) {
358 		Element element = document.createElementNS(RULESET_NS_URI, name);
359 		Text text = document.createTextNode(value);
360 		element.appendChild(text);
361 		return element;
362 }
363 
364 private Element createCDATASectionElement(String name, String value) {
365 		Element element = document.createElementNS(RULESET_NS_URI, name);
366 		CDATASection cdataSection = document.createCDATASection(value);
367 		element.appendChild(cdataSection);
368 		return element;
369 }
370 }

AltStyle によって変換されたページ (->オリジナル) /