1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.pmd;
20
21 import javax.swing.text.html.HTML.Attribute;
22
23 import java.io.File;
24 import java.util.Collection;
25 import java.util.Locale;
26 import java.util.Map;
27
28 import org.apache.maven.doxia.sink.Sink;
29 import org.apache.maven.doxia.sink.SinkEventAttributes;
30 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
31 import org.apache.maven.plugins.pmd.model.CpdFile;
32 import org.apache.maven.plugins.pmd.model.Duplication;
33 import org.apache.maven.project.MavenProject;
34 import org.apache.maven.reporting.AbstractMavenReportRenderer;
35 import org.codehaus.plexus.i18n.I18N;
36 import org.codehaus.plexus.util.StringUtils;
37
38
39
40
41
42
43
44 public class CpdReportRenderer extends AbstractMavenReportRenderer {
45 private final I18N i18n;
46
47 private final Locale locale;
48
49 private final Map<File, PmdFileInfo> files;
50
51 private final Collection<Duplication> duplications;
52
53 private final boolean aggregate;
54
55 public CpdReportRenderer(
56 Sink sink,
57 I18N i18n,
58 Locale locale,
59 Map<File, PmdFileInfo> files,
60 Collection<Duplication> duplications,
61 boolean aggregate) {
62 super(sink);
63 this.i18n = i18n;
64 this.locale = locale;
65 this.files = files;
66 this.duplications = duplications;
67 this.aggregate = aggregate;
68 }
69
70 @Override
71 public String getTitle() {
72 return getI18nString("title");
73 }
74
75
76
77
78
79 private String getI18nString(String key) {
80 return i18n.getString("cpd-report", locale, "report.cpd." + key);
81 }
82
83 @Override
84 protected void renderBody() {
85 startSection(getTitle());
86
87 sink.paragraph();
88 sink.text(getI18nString("cpdlink") + " ");
89 link("https://pmd.github.io/latest/pmd_userdocs_cpd.html", "CPD");
90 sink.text(" " + AbstractPmdReport.getPmdVersion() + ".");
91 sink.paragraph_();
92
93
94
95 if (!duplications.isEmpty()) {
96 renderDuplications();
97 } else {
98 paragraph(getI18nString("noProblems"));
99 }
100
101
102
103 endSection();
104 }
105
106
107
108
109 private void generateFileLine(CpdFile duplicationMark) {
110
111 String filename = duplicationMark.getPath();
112 File file = new File(filename);
113 PmdFileInfo fileInfo = files.get(file);
114 File sourceDirectory = fileInfo.getSourceDirectory();
115 filename = StringUtils.substring(
116 filename, sourceDirectory.getAbsolutePath().length() + 1);
117 String xrefLocation = fileInfo.getXrefLocation();
118 MavenProject projectFile = fileInfo.getProject();
119 int line = duplicationMark.getLine();
120
121 sink.tableRow();
122 tableCell(filename);
123 if (aggregate) {
124 tableCell(projectFile.getName());
125 }
126 sink.tableCell();
127
128 if (xrefLocation != null) {
129 sink.link(xrefLocation + "/"
130 + filename.replaceAll("\\.java$", ".html").replace('\\', '/') + "#L" + line);
131 }
132 sink.text(String.valueOf(line));
133 if (xrefLocation != null) {
134 sink.link_();
135 }
136
137 sink.tableCell_();
138 sink.tableRow_();
139 }
140
141 private void renderDuplications() {
142 startSection(getI18nString("dupes"));
143
144 for (Duplication duplication : duplications) {
145 String code = duplication.getCodefragment();
146
147 startTable();
148 sink.tableRow();
149 tableHeaderCell(getI18nString("column.file"));
150 if (aggregate) {
151 tableHeaderCell(getI18nString("column.project"));
152 }
153 tableHeaderCell(getI18nString("column.line"));
154 sink.tableRow_();
155
156
157 for (CpdFile mark : duplication.getFiles()) {
158 generateFileLine(mark);
159 }
160
161
162 sink.tableRow();
163
164 int colspan = 2;
165 if (aggregate) {
166 colspan = 3;
167 }
168 SinkEventAttributes att = new SinkEventAttributeSet();
169 att.addAttribute(Attribute.COLSPAN, colspan);
170 sink.tableCell(att);
171 verbatimText(code);
172 sink.tableCell_();
173 sink.tableRow_();
174 endTable();
175 }
176
177 endSection();
178 }
179 }