/*
* Sonar PDF Report (Maven plugin)
* Copyright (C) 2010 klicap - ingenieria del puzle
* dev@sonar.codehaus.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.report.pdf;
import java.awt.Color;
import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import org.sonar.report.pdf.entity.FileInfo;
import org.sonar.report.pdf.entity.Project;
import org.sonar.report.pdf.entity.Rule;
import org.sonar.report.pdf.entity.exception.ReportException;
import org.sonar.report.pdf.util.MetricKeys;
import com.lowagie.text.BadElementException;
import com.lowagie.text.ChapterAutoNumber;
import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Image;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.Section;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
public class ExecutivePDFReporter extends PDFReporter {
private URL logo;
private String projectKey;
private String sonarUrl;
private Properties configProperties;
private Properties langProperties;
public ExecutivePDFReporter(URL logo, String projectKey, String sonarUrl, Properties configProperties,
Properties langProperties) {
this.logo = logo;
this.projectKey = projectKey;
this.sonarUrl = sonarUrl;
this.configProperties = configProperties;
this.langProperties = langProperties;
reportType = "executive";
}
@Override
protected URL getLogo() {
return this.logo;
}
@Override
protected String getProjectKey() {
return this.projectKey;
}
@Override
protected String getSonarUrl() {
return this.sonarUrl;
}
@Override
protected Properties getLangProperties() {
return langProperties;
}
@Override
protected Properties getReportProperties() {
return configProperties;
}
@Override
protected void printFrontPage(Document frontPageDocument, PdfWriter frontPageWriter)
throws org.dom4j.DocumentException, ReportException {
try {
URL largeLogo;
if (super.getConfigProperty("front.page.logo").startsWith("http://")) {
largeLogo = new URL(super.getConfigProperty("front.page.logo"));
} else {
largeLogo = this.getClass().getClassLoader().getResource(super.getConfigProperty("front.page.logo"));
}
Image logoImage = Image.getInstance(largeLogo);
logoImage.scaleAbsolute(360, 200);
Rectangle pageSize = frontPageDocument.getPageSize();
logoImage.setAbsolutePosition(Style.FRONTPAGE_LOGO_POSITION_X, Style.FRONTPAGE_LOGO_POSITION_Y);
frontPageDocument.add(logoImage);
PdfPTable title = new PdfPTable(1);
title.getDefaultCell().setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
title.getDefaultCell().setBorder(Rectangle.NO_BORDER);
String projectRow = super.getProject().getName();
String versionRow = super.getProject().getMeasures().getVersion();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String dateRow = df.format(super.getProject().getMeasures().getDate());
String descriptionRow = super.getProject().getDescription();
title.addCell(new Phrase(projectRow, Style.FRONTPAGE_FONT_1));
title.addCell(new Phrase(versionRow, Style.FRONTPAGE_FONT_1));
title.addCell(new Phrase(descriptionRow, Style.FRONTPAGE_FONT_2));
title.addCell(new Phrase(super.getProject().getMeasure(MetricKeys.PROFILE).getDataValue(), Style.FRONTPAGE_FONT_3));
title.addCell(new Phrase(dateRow, Style.FRONTPAGE_FONT_3));
title.setTotalWidth(pageSize.getWidth() - frontPageDocument.leftMargin() - frontPageDocument.rightMargin());
title.writeSelectedRows(0, -1, frontPageDocument.leftMargin(), Style.FRONTPAGE_LOGO_POSITION_Y - 150,
frontPageWriter.getDirectContent());
} catch (IOException e) {
e.printStackTrace();
} catch (BadElementException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
@Override
protected void printPdfBody(Document document) throws DocumentException, IOException, org.dom4j.DocumentException,
ReportException {
Project project = super.getProject();
// Chapter 1: Report Overview (Parent project)
ChapterAutoNumber chapter1 = new ChapterAutoNumber(new Paragraph(project.getName(), Style.CHAPTER_FONT));
chapter1.add(new Paragraph(getTextProperty("main.text.misc.overview"), Style.NORMAL_FONT));
Section section11 = chapter1
.addSection(new Paragraph(getTextProperty("general.report_overview"), Style.TITLE_FONT));
printDashboard(project, section11);
Section section12 = chapter1.addSection(new Paragraph(getTextProperty("general.violations_analysis"),
Style.TITLE_FONT));
printMostViolatedRules(project, section12);
printMostViolatedFiles(project, section12);
printMostComplexFiles(project, section12);
printMostDuplicatedFiles(project, section12);
document.add(chapter1);
Iterator<Project> it = project.getSubprojects().iterator();
while (it.hasNext()) {
Project subproject = it.next();
ChapterAutoNumber chapterN = new ChapterAutoNumber(new Paragraph(subproject.getName(), Style.CHAPTER_FONT));
Section sectionN1 = chapterN.addSection(new Paragraph(getTextProperty("general.report_overview"),
Style.TITLE_FONT));
printDashboard(subproject, sectionN1);
Section sectionN2 = chapterN.addSection(new Paragraph(getTextProperty("general.violations_analysis"),
Style.TITLE_FONT));
printMostViolatedRules(subproject, sectionN2);
printMostViolatedFiles(subproject, sectionN2);
printMostComplexFiles(subproject, sectionN2);
printMostDuplicatedFiles(subproject, sectionN2);
document.add(chapterN);
}
}
protected void printDashboard(Project project, Section section) throws DocumentException {
// Static Analysis
Paragraph staticAnalysis = new Paragraph(getTextProperty("general.static_analysis"), Style.UNDERLINED_FONT);
PdfPTable staticAnalysisTable = new PdfPTable(3);
staticAnalysisTable.getDefaultCell().setBorderColor(Color.WHITE);
PdfPTable linesOfCode = new PdfPTable(1);
Style.noBorderTable(linesOfCode);
linesOfCode.addCell(new Phrase(getTextProperty("general.lines_of_code"), Style.DASHBOARD_TITLE_FONT));
PdfPTable linesOfCodeTendency = new PdfPTable(2);
Style.noBorderTable(linesOfCodeTendency);
linesOfCodeTendency.getDefaultCell().setFixedHeight(Style.TENDENCY_ICONS_HEIGHT);
linesOfCodeTendency.addCell(new Phrase(project.getMeasure(MetricKeys.NCLOC).getFormatValue(),
Style.DASHBOARD_DATA_FONT));
linesOfCodeTendency.addCell(getTendencyImage(project.getMeasure(MetricKeys.NCLOC).getQualitativeTendency(), project
.getMeasure(MetricKeys.NCLOC).getQuantitativeTendency()));
linesOfCode.addCell(linesOfCodeTendency);
linesOfCode.addCell(new Phrase(project.getMeasure(MetricKeys.PACKAGES).getFormatValue() + " packages",
Style.DASHBOARD_DATA_FONT_2));
linesOfCode.addCell(new Phrase(project.getMeasure(MetricKeys.CLASSES).getFormatValue() + " classes",
Style.DASHBOARD_DATA_FONT_2));
linesOfCode.addCell(new Phrase(project.getMeasure(MetricKeys.FUNCTIONS).getFormatValue() + " methods",
Style.DASHBOARD_DATA_FONT_2));
linesOfCode.addCell(new Phrase(project.getMeasure(MetricKeys.DUPLICATED_LINES_DENSITY).getFormatValue()
+ " duplicated lines", Style.DASHBOARD_DATA_FONT_2));
PdfPTable comments = new PdfPTable(1);
Style.noBorderTable(comments);
comments.addCell(new Phrase(getTextProperty("general.comments"), Style.DASHBOARD_TITLE_FONT));
PdfPTable commentsTendency = new PdfPTable(2);
commentsTendency.getDefaultCell().setFixedHeight(Style.TENDENCY_ICONS_HEIGHT);
Style.noBorderTable(commentsTendency);
commentsTendency.addCell(new Phrase(project.getMeasure(MetricKeys.COMMENT_LINES_DENSITY).getFormatValue(),
Style.DASHBOARD_DATA_FONT));
commentsTendency.addCell(getTendencyImage(project.getMeasure(MetricKeys.COMMENT_LINES_DENSITY)
.getQualitativeTendency(), project.getMeasure(MetricKeys.COMMENT_LINES_DENSITY).getQuantitativeTendency()));
comments.addCell(commentsTendency);
comments.addCell(new Phrase(project.getMeasure(MetricKeys.COMMENT_LINES).getFormatValue() + " comment lines",
Style.DASHBOARD_DATA_FONT_2));
PdfPTable complexity = new PdfPTable(1);
Style.noBorderTable(complexity);
complexity.addCell(new Phrase(getTextProperty("general.complexity"), Style.DASHBOARD_TITLE_FONT));
PdfPTable complexityTendency = new PdfPTable(2);
complexityTendency.getDefaultCell().setFixedHeight(Style.TENDENCY_ICONS_HEIGHT);
Style.noBorderTable(complexityTendency);
complexityTendency.addCell(new Phrase(project.getMeasure(MetricKeys.FUNCTION_COMPLEXITY).getFormatValue(),
Style.DASHBOARD_DATA_FONT));
complexityTendency.addCell(getTendencyImage(project.getMeasure(MetricKeys.FUNCTION_COMPLEXITY)
.getQualitativeTendency(), project.getMeasure(MetricKeys.FUNCTION_COMPLEXITY).getQuantitativeTendency()));
complexity.addCell(complexityTendency);
complexity.addCell(new Phrase(project.getMeasure(MetricKeys.CLASS_COMPLEXITY).getFormatValue() + " /class",
Style.DASHBOARD_DATA_FONT_2));
complexity.addCell(new Phrase(project.getMeasure(MetricKeys.COMPLEXITY).getFormatValue() + " decision points",
Style.DASHBOARD_DATA_FONT_2));
staticAnalysisTable.setSpacingBefore(10);
staticAnalysisTable.addCell(linesOfCode);
staticAnalysisTable.addCell(comments);
staticAnalysisTable.addCell(complexity);
staticAnalysisTable.setSpacingAfter(20);
// Dynamic Analysis
Paragraph dynamicAnalysis = new Paragraph(getTextProperty("general.dynamic_analysis"), Style.UNDERLINED_FONT);
PdfPTable dynamicAnalysisTable = new PdfPTable(3);
Style.noBorderTable(dynamicAnalysisTable);
PdfPTable codeCoverage = new PdfPTable(1);
Style.noBorderTable(codeCoverage);
codeCoverage.addCell(new Phrase(getTextProperty("general.code_coverage"), Style.DASHBOARD_TITLE_FONT));
PdfPTable codeCoverageTendency = new PdfPTable(2);
Style.noBorderTable(codeCoverageTendency);
codeCoverageTendency.getDefaultCell().setFixedHeight(Style.TENDENCY_ICONS_HEIGHT);
codeCoverageTendency.addCell(new Phrase(project.getMeasure(MetricKeys.COVERAGE).getFormatValue() + " coverage",
Style.DASHBOARD_DATA_FONT));
codeCoverageTendency.addCell(getTendencyImage(project.getMeasure(MetricKeys.COVERAGE).getQualitativeTendency(),
project.getMeasure(MetricKeys.COVERAGE).getQuantitativeTendency()));
codeCoverage.addCell(codeCoverageTendency);
codeCoverage.addCell(new Phrase(project.getMeasure(MetricKeys.TESTS).getFormatValue() + " tests",
Style.DASHBOARD_DATA_FONT_2));
PdfPTable testSuccess = new PdfPTable(1);
Style.noBorderTable(testSuccess);
testSuccess.addCell(new Phrase(getTextProperty("general.test_success"), Style.DASHBOARD_TITLE_FONT));
PdfPTable testSuccessTendency = new PdfPTable(2);
Style.noBorderTable(testSuccessTendency);
testSuccessTendency.getDefaultCell().setFixedHeight(Style.TENDENCY_ICONS_HEIGHT);
testSuccessTendency.addCell(new Phrase(project.getMeasure(MetricKeys.TEST_SUCCESS_DENSITY).getFormatValue(),
Style.DASHBOARD_DATA_FONT));
testSuccessTendency.addCell(getTendencyImage(project.getMeasure(MetricKeys.TEST_SUCCESS_DENSITY)
.getQualitativeTendency(), project.getMeasure(MetricKeys.TEST_SUCCESS_DENSITY).getQuantitativeTendency()));
testSuccess.addCell(testSuccessTendency);
testSuccess.addCell(new Phrase(project.getMeasure(MetricKeys.TEST_FAILURES).getFormatValue() + " failures",
Style.DASHBOARD_DATA_FONT_2));
testSuccess.addCell(new Phrase(project.getMeasure(MetricKeys.TEST_ERRORS).getFormatValue() + " errors",
Style.DASHBOARD_DATA_FONT_2));
dynamicAnalysisTable.setSpacingBefore(10);
dynamicAnalysisTable.addCell(codeCoverage);
dynamicAnalysisTable.addCell(testSuccess);
dynamicAnalysisTable.addCell("");
dynamicAnalysisTable.setSpacingAfter(20);
Paragraph codingRulesViolations = new Paragraph(getTextProperty("general.coding_rules_violations"),
Style.UNDERLINED_FONT);
PdfPTable codingRulesViolationsTable = new PdfPTable(3);
Style.noBorderTable(codingRulesViolationsTable);
PdfPTable rulesCompliance = new PdfPTable(1);
Style.noBorderTable(rulesCompliance);
rulesCompliance.addCell(new Phrase(getTextProperty("general.rules_compliance"), Style.DASHBOARD_TITLE_FONT));
PdfPTable rulesComplianceTendency = new PdfPTable(2);
Style.noBorderTable(rulesComplianceTendency);
rulesComplianceTendency.getDefaultCell().setFixedHeight(Style.TENDENCY_ICONS_HEIGHT);
rulesComplianceTendency.addCell(new Phrase(project.getMeasure(MetricKeys.VIOLATIONS_DENSITY).getFormatValue(),
Style.DASHBOARD_DATA_FONT));
// Workarround for avoid resizing
Image tendencyRulesResize = getTendencyImage(project.getMeasure(MetricKeys.VIOLATIONS_DENSITY)
.getQualitativeTendency(), project.getMeasure(MetricKeys.VIOLATIONS_DENSITY).getQuantitativeTendency());
tendencyRulesResize.scaleAbsolute(Style.TENDENCY_ICONS_HEIGHT, Style.TENDENCY_ICONS_HEIGHT);
PdfPCell tendencyRulesCell = new PdfPCell(tendencyRulesResize);
tendencyRulesCell.setBorder(0);
rulesComplianceTendency.addCell(tendencyRulesCell);
rulesCompliance.addCell(rulesComplianceTendency);
PdfPTable violations = new PdfPTable(1);
Style.noBorderTable(violations);
violations.addCell(new Phrase(getTextProperty("general.violations"), Style.DASHBOARD_TITLE_FONT));
PdfPTable violationsTendency = new PdfPTable(2);
Style.noBorderTable(violationsTendency);
violationsTendency.getDefaultCell().setFixedHeight(Style.TENDENCY_ICONS_HEIGHT);
violationsTendency.addCell(new Phrase(project.getMeasure(MetricKeys.VIOLATIONS).getFormatValue(),
Style.DASHBOARD_DATA_FONT));
// Workarround for avoid resizing
Image tendencyResize = getTendencyImage(project.getMeasure(MetricKeys.VIOLATIONS).getQualitativeTendency(), project
.getMeasure(MetricKeys.VIOLATIONS).getQuantitativeTendency());
tendencyResize.scaleAbsolute(Style.TENDENCY_ICONS_HEIGHT, Style.TENDENCY_ICONS_HEIGHT);
PdfPCell tendencyCell = new PdfPCell(tendencyResize);
tendencyCell.setBorder(0);
violationsTendency.addCell(tendencyCell);
violations.addCell(violationsTendency);
codingRulesViolationsTable.setSpacingBefore(10);
codingRulesViolationsTable.addCell(rulesCompliance);
codingRulesViolationsTable.addCell(violations);
codingRulesViolationsTable.addCell("");
codingRulesViolationsTable.setSpacingAfter(20);
section.add(Chunk.NEWLINE);
section.add(staticAnalysis);
section.add(staticAnalysisTable);
section.add(dynamicAnalysis);
section.add(dynamicAnalysisTable);
section.add(codingRulesViolations);
section.add(codingRulesViolationsTable);
}
protected void printMostDuplicatedFiles(Project project, Section section) {
List<FileInfo> files = project.getMostDuplicatedFiles();
Iterator<FileInfo> it = files.iterator();
List<String> left = new LinkedList<String>();
List<String> right = new LinkedList<String>();
while (it.hasNext()) {
FileInfo file = it.next();
left.add(file.getName());
right.add(file.getDuplicatedLines());
}
PdfPTable mostDuplicatedFilesTable = Style.createSimpleTable(left, right,
getTextProperty("general.most_duplicated_files"), getTextProperty("general.no_duplicated_files"));
section.add(mostDuplicatedFilesTable);
}
protected void printMostComplexFiles(Project project, Section section) {
List<FileInfo> files = project.getMostComplexFiles();
Iterator<FileInfo> it = files.iterator();
List<String> left = new LinkedList<String>();
List<String> right = new LinkedList<String>();
while (it.hasNext()) {
FileInfo file = it.next();
left.add(file.getName());
right.add(file.getComplexity());
}
PdfPTable mostComplexFilesTable = Style.createSimpleTable(left, right,
getTextProperty("general.most_complex_files"), getTextProperty("general.no_complex_files"));
section.add(mostComplexFilesTable);
}
protected void printMostViolatedRules(Project project, Section section) {
List<Rule> mostViolatedRules = project.getMostViolatedRules();
Iterator<Rule> it = mostViolatedRules.iterator();
List<String> left = new LinkedList<String>();
List<String> right = new LinkedList<String>();
int limit = 0;
while (it.hasNext() && limit < 5) {
Rule rule = it.next();
left.add(rule.getName());
right.add(String.valueOf(rule.getViolationsNumberFormatted()));
limit++;
}
PdfPTable mostViolatedRulesTable = Style.createSimpleTable(left, right,
getTextProperty("general.most_violated_rules"), getTextProperty("general.no_violated_rules"));
section.add(mostViolatedRulesTable);
}
protected void printMostViolatedFiles(Project project, Section section) {
List<FileInfo> files = project.getMostViolatedFiles();
Iterator<FileInfo> it = files.iterator();
List<String> left = new LinkedList<String>();
List<String> right = new LinkedList<String>();
while (it.hasNext()) {
FileInfo file = it.next();
left.add(file.getName());
right.add(file.getViolations());
}
PdfPTable mostViolatedFilesTable = Style.createSimpleTable(left, right,
getTextProperty("general.most_violated_files"), getTextProperty("general.no_violated_files"));
section.add(mostViolatedFilesTable);
}
@Override
protected void printTocTitle(Toc tocDocument) throws com.lowagie.text.DocumentException {
Paragraph tocTitle = new Paragraph(super.getTextProperty("main.table.of.contents"), Style.TOC_TITLE_FONT);
tocTitle.setAlignment(Element.ALIGN_CENTER);
tocDocument.getTocDocument().add(tocTitle);
tocDocument.getTocDocument().add(Chunk.NEWLINE);
}
}