View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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   * Class that generated the CPD report.
40   *
41   * @author mperham
42   * @version $Id$
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       * @param key The key.
77       * @return The translated string.
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          // TODO overall summary
94  
95          if (!duplications.isEmpty()) {
96              renderDuplications();
97          } else {
98              paragraph(getI18nString("noProblems"));
99          }
100 
101         // TODO files summary
102 
103         endSection();
104     }
105 
106     /**
107      * Method that generates a line of CPD report according to a TokenEntry.
108      */
109     private void generateFileLine(CpdFile duplicationMark) {
110         // Get information for report generation
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             // Iterating on every token entry
157             for (CpdFile mark : duplication.getFiles()) {
158                 generateFileLine(mark);
159             }
160 
161             // Source snippet
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 }