View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.renderers;
5   
6   import java.io.IOException;
7   import java.io.Writer;
8   import java.text.SimpleDateFormat;
9   import java.util.Date;
10  import java.util.Iterator;
11  
12  import net.sourceforge.pmd.PMD;
13  import net.sourceforge.pmd.Report;
14  import net.sourceforge.pmd.RuleViolation;
15  import net.sourceforge.pmd.lang.rule.properties.StringProperty;
16  import net.sourceforge.pmd.util.StringUtil;
17  
18  /**
19   * Renderer to XML format.
20   */
21  public class XMLRenderer extends AbstractIncrementingRenderer {
22  
23      public static final String NAME = "xml";
24  
25      public static final StringProperty ENCODING = new StringProperty("encoding", "XML encoding format, defaults to UTF-8.", "UTF-8", 0);
26  
27      public XMLRenderer() {
28  		super(NAME, "XML format.");
29  		definePropertyDescriptor(ENCODING);
30      }
31  
32      public XMLRenderer(String encoding) {
33  	this();
34  	setProperty(ENCODING, encoding);
35      }
36  
37      public String defaultFileExtension() { return "xml"; }
38      
39      /**
40       * {@inheritDoc}
41       */
42      @Override
43      public void start() throws IOException {
44  		String encoding = getProperty(ENCODING);
45  
46  		Writer writer = getWriter();
47  		StringBuilder buf = new StringBuilder(500);
48  		buf.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>").append(PMD.EOL);
49  		createVersionAttr(buf);
50  		createTimestampAttr(buf);
51  		// FIXME: elapsed time not available until the end of the processing
52  		//buf.append(createTimeElapsedAttr(report));
53  		buf.append('>').append(PMD.EOL);
54  		writer.write(buf.toString());
55      }
56  
57      /**
58       * {@inheritDoc}
59       */
60      @Override
61      public void renderFileViolations(Iterator<RuleViolation> violations) throws IOException {
62  		Writer writer = getWriter();
63  		StringBuilder buf = new StringBuilder(500);
64  		String filename = null;
65  	
66  		// rule violations
67  		while (violations.hasNext()) {
68  		    buf.setLength(0);
69  		    RuleViolation rv = violations.next();
70  		    if (!rv.getFilename().equals(filename)) { // New File
71  			if (filename != null) {// Not first file ?
72  			    buf.append("</file>").append(PMD.EOL);
73  			}
74  			filename = rv.getFilename();
75  			buf.append("<file name=\"");
76  			StringUtil.appendXmlEscaped(buf, filename);
77  			buf.append("\">").append(PMD.EOL);
78  		    }
79  	
80  		    buf.append("<violation beginline=\"").append(rv.getBeginLine());
81  		    buf.append("\" endline=\"").append(rv.getEndLine());
82  		    buf.append("\" begincolumn=\"").append(rv.getBeginColumn());
83  		    buf.append("\" endcolumn=\"").append(rv.getEndColumn());
84  		    buf.append("\" rule=\"");
85  		    StringUtil.appendXmlEscaped(buf, rv.getRule().getName());
86  		    buf.append("\" ruleset=\"");
87  		    StringUtil.appendXmlEscaped(buf, rv.getRule().getRuleSetName());
88  		    buf.append('"');
89  		    maybeAdd("package", rv.getPackageName(), buf);
90  		    maybeAdd("class", rv.getClassName(), buf);
91  		    maybeAdd("method", rv.getMethodName(), buf);
92  		    maybeAdd("variable", rv.getVariableName(), buf);
93  		    maybeAdd("externalInfoUrl", rv.getRule().getExternalInfoUrl(), buf);
94  		    buf.append(" priority=\"");
95  		    buf.append(rv.getRule().getPriority().getPriority());
96  		    buf.append("\">").append(PMD.EOL);
97  		    StringUtil.appendXmlEscaped(buf, rv.getDescription());
98  	
99  		    buf.append(PMD.EOL);
100 		    buf.append("</violation>");
101 		    buf.append(PMD.EOL);
102 		    writer.write(buf.toString());
103 		}
104 		if (filename != null) { // Not first file ?
105 		    writer.write("</file>");
106 		    writer.write(PMD.EOL);
107 		}
108     }
109 
110     /**
111      * {@inheritDoc}
112      */
113     @Override
114     public void end() throws IOException {
115 		Writer writer = getWriter();
116 		StringBuilder buf = new StringBuilder(500);
117 		// errors
118 		for (Report.ProcessingError pe : errors) {
119 		    buf.setLength(0);
120 		    buf.append("<error ").append("filename=\"");
121 		    StringUtil.appendXmlEscaped(buf, pe.getFile());
122 		    buf.append("\" msg=\"");
123 		    StringUtil.appendXmlEscaped(buf, pe.getMsg());
124 		    buf.append("\"/>").append(PMD.EOL);
125 		    writer.write(buf.toString());
126 		}
127 	
128 		// suppressed violations
129 		if (showSuppressedViolations) {
130 		    for (Report.SuppressedViolation s : suppressed) {
131 			buf.setLength(0);
132 			buf.append("<suppressedviolation ").append("filename=\"");
133 			StringUtil.appendXmlEscaped(buf, s.getRuleViolation().getFilename());
134 			buf.append("\" suppressiontype=\"");
135 			StringUtil.appendXmlEscaped(buf, s.suppressedByNOPMD() ? "nopmd" : "annotation");
136 			buf.append("\" msg=\"");
137 			StringUtil.appendXmlEscaped(buf, s.getRuleViolation().getDescription());
138 			buf.append("\" usermsg=\"");
139 			StringUtil.appendXmlEscaped(buf, s.getUserMessage() == null ? "" : s.getUserMessage());
140 			buf.append("\"/>").append(PMD.EOL);
141 			writer.write(buf.toString());
142 		    }
143 		}
144 	
145 		writer.write("</pmd>" + PMD.EOL);
146     }
147 
148     private void maybeAdd(String attr, String value, StringBuilder buf) {
149 		if (value != null && value.length() > 0) {
150 		    buf.append(' ').append(attr).append("=\"");
151 		    StringUtil.appendXmlEscaped(buf, value);
152 		    buf.append('"');
153 		}
154     }
155 
156     private void createVersionAttr(StringBuilder buffer) {
157     	buffer.append("<pmd version=\"").append(PMD.VERSION).append('"');
158     }
159 
160     private void createTimestampAttr(StringBuilder buffer) {
161 		buffer.append(" timestamp=\"").append(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").format(new Date()))
162 			.append('"');
163     }
164 
165     // FIXME: elapsed time not available until the end of the processing
166     /*
167     private String createTimeElapsedAttr(Report rpt) {
168         Report.ReadableDuration d = new Report.ReadableDuration(rpt.getElapsedTimeInMillis());
169         return " elapsedTime=\"" + d.getTime() + "\"";
170     }
171     */
172 }