View Javadoc

1   package org.apache.maven.plugin.pmd;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.util.Iterator;
24  import java.util.Map;
25  import java.util.ResourceBundle;
26  
27  import net.sourceforge.pmd.cpd.Match;
28  import net.sourceforge.pmd.cpd.TokenEntry;
29  
30  import org.apache.maven.doxia.sink.Sink;
31  import org.apache.maven.project.MavenProject;
32  import org.codehaus.plexus.util.StringUtils;
33  
34  /**
35   * Class that generated the CPD report.
36   *
37   * @author mperham
38   * @version $Id: CpdReportGenerator.html 816696 2012-05-08 15:19:20Z hboutemy $
39   */
40  public class CpdReportGenerator
41  {
42      private Sink sink;
43  
44      private Map<File, PmdFileInfo> fileMap;
45  
46      private ResourceBundle bundle;
47  
48      private boolean aggregate;
49  
50      public CpdReportGenerator( Sink sink, Map<File, PmdFileInfo> fileMap, ResourceBundle bundle, boolean aggregate )
51      {
52          this.sink = sink;
53          this.fileMap = fileMap;
54          this.bundle = bundle;
55          this.aggregate = aggregate;
56      }
57  
58      /**
59       * Method that returns the title of the CPD Report
60       *
61       * @return a String that contains the title
62       */
63      private String getTitle()
64      {
65          return bundle.getString( "report.cpd.title" );
66      }
67  
68      /**
69       * Method that generates the start of the CPD report.
70       */
71      public void beginDocument()
72      {
73          sink.head();
74          sink.title();
75          sink.text( getTitle() );
76          sink.title_();
77          sink.head_();
78  
79          sink.body();
80  
81          sink.section1();
82          sink.sectionTitle1();
83          sink.text( getTitle() );
84          sink.sectionTitle1_();
85  
86          sink.paragraph();
87          sink.text( bundle.getString( "report.cpd.cpdlink" ) + " " );
88          sink.link( "http://pmd.sourceforge.net/cpd.html" );
89          sink.text( "CPD" );
90          sink.link_();
91          sink.text( " " + AbstractPmdReport.getPmdVersion() + "." );
92          sink.paragraph_();
93  
94          sink.section1_();
95  
96          // TODO overall summary
97  
98          sink.section1();
99          sink.sectionTitle1();
100         sink.text( bundle.getString( "report.cpd.dupes" ) );
101         sink.sectionTitle1_();
102 
103         // TODO files summary
104     }
105 
106     /**
107      * Method that generates a line of CPD report according to a TokenEntry.
108      */
109     private void generateFileLine( TokenEntry tokenEntry )
110     {
111         // Get information for report generation
112         String filename = tokenEntry.getTokenSrcID();
113         File file = new File( filename );
114         PmdFileInfo fileInfo = fileMap.get( file );
115         File sourceDirectory = fileInfo.getSourceDirectory();
116         filename = StringUtils.substring( filename, sourceDirectory.getAbsolutePath().length() + 1 );
117         String xrefLocation = fileInfo.getXrefLocation();
118         MavenProject projectFile = fileInfo.getProject();
119         int line = tokenEntry.getBeginLine();
120 
121         sink.tableRow();
122         sink.tableCell();
123         sink.text( filename );
124         sink.tableCell_();
125         if ( aggregate )
126         {
127             sink.tableCell();
128             sink.text( projectFile.getName() );
129             sink.tableCell_();
130         }
131         sink.tableCell();
132 
133         if ( xrefLocation != null )
134         {
135             sink.link( xrefLocation + "/" + filename.replaceAll( "\\.java$", ".html" ).replace( '\\', '/' )
136                     + "#" + line );
137         }
138         sink.text( String.valueOf( line ) );
139         if ( xrefLocation != null )
140         {
141             sink.link_();
142         }
143 
144         sink.tableCell_();
145         sink.tableRow_();
146     }
147 
148     /**
149      * Method that generates the contents of the CPD report
150      *
151      * @param matches
152      */
153     @SuppressWarnings( "deprecation" )
154     public void generate( Iterator<Match> matches )
155     {
156         beginDocument();
157 
158         if ( !matches.hasNext() )
159         {
160             sink.paragraph();
161             sink.text( bundle.getString( "report.cpd.noProblems" ) );
162             sink.paragraph_();
163         }
164 
165         while ( matches.hasNext() )
166         {
167             Match match = matches.next();
168             
169             String code = match.getSourceCodeSlice();
170             
171             sink.table();
172             sink.tableRow();
173             sink.tableHeaderCell();
174             sink.text( bundle.getString( "report.cpd.column.file" ) );
175             sink.tableHeaderCell_();
176             if ( aggregate )
177             {
178                 sink.tableHeaderCell();
179                 sink.text( bundle.getString( "report.cpd.column.project" ) );
180                 sink.tableHeaderCell_();
181             }
182             sink.tableHeaderCell();
183             sink.text( bundle.getString( "report.cpd.column.line" ) );
184             sink.tableHeaderCell_();
185             sink.tableRow_();
186 
187             // Iterating on every token entry
188             for ( Iterator<TokenEntry> occurrences = match.iterator(); occurrences.hasNext(); )
189             {
190 
191                 TokenEntry mark = occurrences.next();
192                 generateFileLine( mark );
193             }
194            
195             // Source snippet
196             sink.tableRow();
197 
198 
199             int colspan = 2;
200             if ( aggregate )
201             {
202                 ++colspan;
203             }
204             // TODO Cleaner way to do this?
205             sink.rawText( "<td colspan='" + colspan + "'>" );
206             sink.verbatim( false );
207             sink.text( code );
208             sink.verbatim_();
209             sink.rawText( "</td>" );
210             sink.tableRow_();
211             sink.table_();
212         }
213 
214         sink.section1_();
215         sink.body_();
216         sink.flush();
217         sink.close();
218     }
219 }