View Javadoc
1   package org.codehaus.mojo.taglist;
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.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.ResourceBundle;
29  
30  import org.apache.maven.doxia.sink.Sink;
31  import org.codehaus.mojo.taglist.beans.FileReport;
32  import org.codehaus.mojo.taglist.beans.TagReport;
33  
34  /**
35   * Generates the taglist report using Doxia.
36   *
37   * @author <a href="mailto:bellingard.NO-SPAM@gmail.com">Fabrice Bellingard </a>
38   */
39  
40  public class ReportGenerator
41  {
42      /**
43       * The source code cross reference path.
44       */
45      private String xrefLocation;
46  
47      /**
48       * The test code cross reference path.
49       */
50      private String testXrefLocation;
51  
52      /**
53       * The sink used in this Maven build to generated the tag list page.
54       */
55      private Sink sink;
56  
57      /**
58       * The resource bundle used in this Maven build.
59       */
60      private ResourceBundle bundle;
61  
62      /**
63       * The output path of the site.
64       */
65      private File siteOutputDirectory;
66  
67      /**
68       * A list of sorted tag reports.
69       */
70      private List sortedTagReports;
71  
72      /**
73       * Display details for tags that contain zero occurrences.
74       */
75      private boolean showEmptyDetails;
76  
77      /**
78       * Constructor.
79       *
80       * @param report the TagListReport object used in this build.
81       * @param tagReports a collection of tagReports to output.
82       */
83      public ReportGenerator( TagListReport report, Collection tagReports )
84      {
85          sortedTagReports = new ArrayList( tagReports );
86          Collections.sort( sortedTagReports );
87          this.bundle = report.getBundle();
88          this.sink = report.getSink();
89          this.siteOutputDirectory = report.getReportOutputDirectory();
90          this.showEmptyDetails = report.isShowEmptyDetails();
91      }
92  
93      /**
94       * Generates the whole report using each tag reports made during the analysis.
95       */
96      public void generateReport()
97      {
98          sink.head();
99          sink.title();
100         sink.text( bundle.getString( "report.taglist.header" ) );
101         sink.title_();
102         sink.head_();
103 
104         sink.body();
105         sink.section1();
106 
107         sink.sectionTitle1();
108         sink.text( bundle.getString( "report.taglist.mainTitle" ) );
109         sink.sectionTitle1_();
110 
111         // Summary section
112         doSummarySection( sortedTagReports );
113 
114         // Detail section
115         doDetailSection( sortedTagReports );
116 
117         sink.section1_();
118         sink.body_();
119         sink.flush();
120         sink.close();
121     }
122 
123     /**
124      * @param tagReports a collection of tagReports to summarize.
125      */
126     private void doSummarySection( Collection tagReports )
127     {
128         sink.paragraph();
129         sink.text( bundle.getString( "report.taglist.summary.description" ) );
130         sink.paragraph_();
131 
132         sink.table();
133         sink.tableRow();
134         sink.tableHeaderCell();
135         sink.text( bundle.getString( "report.taglist.summary.tag" ) );
136         sink.tableHeaderCell_();
137         sink.tableHeaderCell();
138         sink.text( bundle.getString( "report.taglist.summary.occurrences" ) );
139         sink.tableHeaderCell_();
140         sink.tableHeaderCell();
141         sink.text( bundle.getString( "report.taglist.summary.tagstrings" ) );
142         sink.tableHeaderCell_();
143         sink.tableRow_();
144         for ( Iterator iter = tagReports.iterator(); iter.hasNext(); )
145         {
146             doTagSummary( (TagReport) iter.next() );
147         }
148         sink.table_();
149     }
150 
151     /**
152      * @param tagReport the tagReport to summarize.
153      */
154     private void doTagSummary( TagReport tagReport )
155     {
156         sink.tableRow();
157         sink.tableCell();
158         // Create a hyperlink if the "showEmptyTags" flag is set or the tag contains 1 or more occurrences.
159         if ( showEmptyDetails || tagReport.getTagCount() > 0 )
160         {
161             sink.link( "#" + tagReport.getHTMLSafeLinkName() );
162             sink.text( tagReport.getTagName() );
163             sink.link_();
164         }
165         else
166         {
167             sink.text( tagReport.getTagName() );
168         }
169         sink.tableCell_();
170         sink.tableCell();
171         sink.text( String.valueOf( tagReport.getTagCount() ) );
172         sink.tableCell_();
173         sink.tableCell();
174         String [] tags = tagReport.getTagStrings();
175         if ( tags != null )
176         {
177             // Output each tag string
178             for ( int i = 0; i < tags.length; ++i )
179             {
180                 if ( i > 0 )
181                 {
182                     // Insert comma before each tag except for the first one.
183                     sink.text( ", " );
184                 }
185                 sink.text( tags[i] );
186             }
187         }
188         sink.tableCell_();
189         sink.tableRow_();
190     }
191 
192     /**
193      * @param tagReports a collection of tagReports to be detailed in this section.
194      */
195     private void doDetailSection( Collection tagReports )
196     {
197         sink.paragraph();
198         sink.text( bundle.getString( "report.taglist.detail.description" ) );
199         sink.paragraph_();
200 
201         for ( Iterator iter = tagReports.iterator(); iter.hasNext(); )
202         {
203             doTagDetailedPart( (TagReport) iter.next() );
204         }
205     }
206 
207     /**
208      * @param tagReport to tagReport to detail.
209      */
210     private void doTagDetailedPart( TagReport tagReport )
211     {
212         // Create detailed section only if the "showEmptyTags" flag is set or the tag contains 1 or more occurrences.
213         if ( !showEmptyDetails && tagReport.getTagCount() <= 0 )
214         {
215             return;
216         }
217 
218         sink.section2();
219         sink.sectionTitle2();
220         sink.anchor( tagReport.getHTMLSafeLinkName() );
221         sink.text( tagReport.getTagName() );
222         sink.anchor_();
223         sink.sectionTitle2_();
224         sink.paragraph();
225         sink.bold();
226         sink.text( bundle.getString( "report.taglist.detail.numberOfOccurrences" ) + ' ' + tagReport.getTagCount() );
227         sink.bold_();
228         sink.paragraph_();
229 
230         Collection fileReports = tagReport.getFileReports();
231         List sortedFileReports = new ArrayList( fileReports );
232         Collections.sort( sortedFileReports );
233 
234         // MTAGLIST-38 - sink table before generating each file report in order
235         //               to align the columns correctly.
236         sink.table();
237 
238         for ( Iterator iter = sortedFileReports.iterator(); iter.hasNext(); )
239         {
240             doFileDetailedPart( (FileReport) iter.next() );
241         }
242         sink.table_();
243 
244         sink.section2_();
245     }
246 
247     /**
248      * @param fileReport the FileReport to output for this detailed tag report.
249      */
250     private void doFileDetailedPart( FileReport fileReport )
251     {
252         sink.tableRow();
253         sink.tableHeaderCell();
254         sink.text( fileReport.getClassName() );
255         sink.tableHeaderCell_();
256         sink.tableHeaderCell();
257         sink.text( bundle.getString( "report.taglist.detail.line" ) );
258         sink.tableHeaderCell_();
259         sink.tableRow_();
260         for ( Iterator iter = fileReport.getLineIndexes().iterator(); iter.hasNext(); )
261         {
262             doCommentLine( fileReport, (Integer) iter.next() );
263         }
264     }
265 
266     /**
267      * @param fileReport the FileReport for the current tag's comment.
268      * @param lineNumber the line number of the current tag's comment.
269      */
270     private void doCommentLine( FileReport fileReport, Integer lineNumber )
271     {
272         boolean linked = false;
273         
274         sink.tableRow();
275         sink.tableCell();
276         sink.text( fileReport.getComment( lineNumber ) );
277         sink.tableCell_();
278         sink.tableCell();
279         if ( xrefLocation != null )
280         {
281             String fileLink = xrefLocation + "/" + fileReport.getClassNameWithSlash() + ".html";
282             File xrefFile = new File( siteOutputDirectory, fileLink.substring( 2 ) );
283 
284             // Link only if file exists in xref
285             if ( xrefFile.exists() )
286             {
287                 sink.link( fileLink + "#L" + lineNumber );
288                 linked = true;
289             }
290         }
291         // If the file was not linked to xref and there is a test xref location check it
292         if ( !linked && testXrefLocation != null )
293         {
294             String testFileLink = testXrefLocation + "/" + fileReport.getClassNameWithSlash() + ".html";
295             File testXrefFile = new File( siteOutputDirectory, testFileLink.substring( 2 ) );
296             
297             // Link only if file exists in test xref
298             if ( testXrefFile.exists() )
299             {
300                 sink.link( testFileLink + "#L" + lineNumber );
301                 linked = true;
302             }
303         }
304 
305         sink.text( String.valueOf( lineNumber ) );
306         
307         // Was a xref or test-xref link created?
308         if ( linked )
309         {
310             sink.link_();
311         }
312         sink.tableCell_();
313         sink.tableRow_();
314     }
315 
316     /**
317      * Set the source code cross reference location.
318      *
319      * @param xrefLocation the location of the source code cross reference.
320      */
321     public void setXrefLocation( String xrefLocation )
322     {
323         this.xrefLocation = xrefLocation;
324     }
325 
326     /**
327      * Get the source code cross reference location.
328      *
329      * @return the source code cross reference location.
330      */
331     public String getXrefLocation()
332     {
333         return xrefLocation;
334     }
335 
336     /**
337      * Get the test code cross reference location.
338      *
339      * @return the test code cross reference location.
340      */
341     public String getTestXrefLocation()
342     {
343         return testXrefLocation;
344     }
345 
346     /**
347      * Set the test code cross reference location.
348      *
349      * @param testXrefLocation the location of the test code cross reference.
350      */
351     public void setTestXrefLocation( String testXrefLocation )
352     {
353         this.testXrefLocation = testXrefLocation;
354     }
355 }