package org.codehaus.mojo.taglist; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ResourceBundle; import org.codehaus.doxia.sink.Sink; import org.codehaus.mojo.taglist.beans.FileReport; import org.codehaus.mojo.taglist.beans.TagReport; /** * Generates the taglist report using Doxia. * * @author <a href="mailto:bellingard.NO-SPAM@gmail.com">Fabrice Bellingard </a> */ public class ReportGenerator { /** * The source code cross reference path. */ private String xrefLocation; /** * The test code cross reference path. */ private String testXrefLocation; /** * The sink used in this Maven build to generated the tag list page. */ private Sink sink; /** * The resource bundle used in this Maven build. */ private ResourceBundle bundle; /** * The output path of the site. */ private File siteOutputDirectory; /** * A list of sorted tag reports. */ private List sortedTagReports; /** * Display details for tags that contain zero occurrences. */ private boolean showEmptyDetails; /** * Constructor. * * @param report the TagListReport object used in this build. * @param tagReports a collection of tagReports to output. */ public ReportGenerator( TagListReport report, Collection tagReports ) { sortedTagReports = new ArrayList( tagReports ); Collections.sort( sortedTagReports ); this.bundle = report.getBundle(); this.sink = report.getSink(); this.siteOutputDirectory = report.getReportOutputDirectory(); this.showEmptyDetails = report.isShowEmptyDetails(); } /** * Generates the whole report using each tag reports made during the analysis. */ public void generateReport() { sink.head(); sink.title(); sink.text( bundle.getString( "report.taglist.header" ) ); sink.title_(); sink.head_(); sink.body(); sink.section1(); sink.sectionTitle1(); sink.text( bundle.getString( "report.taglist.mainTitle" ) ); sink.sectionTitle1_(); // Summary section doSummarySection( sortedTagReports ); // Detail section doDetailSection( sortedTagReports ); sink.section1_(); sink.body_(); sink.flush(); sink.close(); } /** * @param tagReports a collection of tagReports to summarize. */ private void doSummarySection( Collection tagReports ) { sink.paragraph(); sink.text( bundle.getString( "report.taglist.summary.description" ) ); sink.paragraph_(); sink.table(); sink.tableRow(); sink.tableHeaderCell(); sink.text( bundle.getString( "report.taglist.summary.tag" ) ); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text( bundle.getString( "report.taglist.summary.occurrences" ) ); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text( bundle.getString( "report.taglist.summary.tagstrings" ) ); sink.tableHeaderCell_(); sink.tableRow_(); for ( Iterator iter = tagReports.iterator(); iter.hasNext(); ) { doTagSummary( (TagReport) iter.next() ); } sink.table_(); } /** * @param tagReport the tagReport to summarize. */ private void doTagSummary( TagReport tagReport ) { sink.tableRow(); sink.tableCell(); // Create a hyperlink if the "showEmptyTags" flag is set or the tag contains 1 or more occurrences. if ( showEmptyDetails || tagReport.getTagCount() > 0 ) { sink.link( "#" + tagReport.getHTMLSafeLinkName() ); sink.text( tagReport.getTagName() ); sink.link_(); } else { sink.text( tagReport.getTagName() ); } sink.tableCell_(); sink.tableCell(); sink.text( String.valueOf( tagReport.getTagCount() ) ); sink.tableCell_(); sink.tableCell(); String [] tags = tagReport.getTagStrings(); if ( tags != null ) { // Output each tag string for ( int i = 0; i < tags.length; ++i ) { if ( i > 0 ) { // Insert comma before each tag except for the first one. sink.text( ", " ); } sink.text( tags[i] ); } } sink.tableCell_(); sink.tableRow_(); } /** * @param tagReports a collection of tagReports to be detailed in this section. */ private void doDetailSection( Collection tagReports ) { sink.paragraph(); sink.text( bundle.getString( "report.taglist.detail.description" ) ); sink.paragraph_(); for ( Iterator iter = tagReports.iterator(); iter.hasNext(); ) { doTagDetailedPart( (TagReport) iter.next() ); } } /** * @param tagReport to tagReport to detail. */ private void doTagDetailedPart( TagReport tagReport ) { // Create detailed section only if the "showEmptyTags" flag is set or the tag contains 1 or more occurrences. if ( !showEmptyDetails && tagReport.getTagCount() <= 0 ) { return; } sink.section2(); sink.sectionTitle2(); sink.anchor( tagReport.getHTMLSafeLinkName() ); sink.text( tagReport.getTagName() ); sink.anchor_(); sink.sectionTitle2_(); sink.paragraph(); sink.bold(); sink.text( bundle.getString( "report.taglist.detail.numberOfOccurrences" ) + ' ' + tagReport.getTagCount() ); sink.bold_(); sink.paragraph_(); Collection fileReports = tagReport.getFileReports(); List sortedFileReports = new ArrayList( fileReports ); Collections.sort( sortedFileReports ); // MTAGLIST-38 - sink table before generating each file report in order // to align the columns correctly. sink.table(); for ( Iterator iter = sortedFileReports.iterator(); iter.hasNext(); ) { doFileDetailedPart( (FileReport) iter.next() ); } sink.table_(); sink.section2_(); } /** * @param fileReport the FileReport to output for this detailed tag report. */ private void doFileDetailedPart( FileReport fileReport ) { sink.tableRow(); sink.tableHeaderCell(); sink.text( fileReport.getClassName() ); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text( bundle.getString( "report.taglist.detail.line" ) ); sink.tableHeaderCell_(); sink.tableRow_(); for ( Iterator iter = fileReport.getLineIndexes().iterator(); iter.hasNext(); ) { doCommentLine( fileReport, (Integer) iter.next() ); } } /** * @param fileReport the FileReport for the current tag's comment. * @param lineNumber the line number of the current tag's comment. */ private void doCommentLine( FileReport fileReport, Integer lineNumber ) { boolean linked = false; sink.tableRow(); sink.tableCell(); sink.text( fileReport.getComment( lineNumber ) ); sink.tableCell_(); sink.tableCell(); if ( xrefLocation != null ) { String fileLink = xrefLocation + "/" + fileReport.getClassNameWithSlash() + ".html"; File xrefFile = new File( siteOutputDirectory, fileLink.substring( 2 ) ); // Link only if file exists in xref if ( xrefFile.exists() ) { sink.link( fileLink + "#" + lineNumber ); linked = true; } } // If the file was not linked to xref and there is a test xref location check it if ( !linked && testXrefLocation != null ) { String testFileLink = testXrefLocation + "/" + fileReport.getClassNameWithSlash() + ".html"; File testXrefFile = new File( siteOutputDirectory, testFileLink.substring( 2 ) ); // Link only if file exists in test xref if ( testXrefFile.exists() ) { sink.link( testFileLink + "#" + lineNumber ); linked = true; } } sink.text( String.valueOf( lineNumber ) ); // Was a xref or test-xref link created? if ( linked ) { sink.link_(); } sink.tableCell_(); sink.tableRow_(); } /** * Set the source code cross reference location. * * @param xrefLocation the location of the source code cross reference. */ public void setXrefLocation( String xrefLocation ) { this.xrefLocation = xrefLocation; } /** * Get the source code cross reference location. * * @return the source code cross reference location. */ public String getXrefLocation() { return xrefLocation; } /** * Get the test code cross reference location. * * @return the test code cross reference location. */ public String getTestXrefLocation() { return testXrefLocation; } /** * Set the test code cross reference location. * * @param testXrefLocation the location of the test code cross reference. */ public void setTestXrefLocation( String testXrefLocation ) { this.testXrefLocation = testXrefLocation; } }