package com.ikokoon.serenity.hudson.source; import java.io.BufferedWriter; import java.io.IOException; import java.text.MessageFormat; import com.ikokoon.serenity.model.Class; import com.ikokoon.serenity.model.Line; import com.ikokoon.serenity.model.Method; import de.java2html.Version; import de.java2html.converter.JavaSource2HTMLConverter; import de.java2html.javasource.JavaSource; import de.java2html.javasource.JavaSourceIterator; import de.java2html.javasource.JavaSourceRun; import de.java2html.javasource.JavaSourceType; import de.java2html.options.HorizontalAlignment; import de.java2html.options.IHorizontalAlignmentVisitor; import de.java2html.options.JavaSourceConversionOptions; import de.java2html.options.JavaSourceStyleEntry; import de.java2html.options.JavaSourceStyleTable; import de.java2html.util.HtmlUtilities; import de.java2html.util.StringHolder; /** * This class just extends the Java2HTML converter and adds a background colour where the lines were executed. Unfortunately most of the interesting * methods were private so there is a lot of copy and paste, pity, se la vie. * * @author Michael Couck * @since 09.12.09 * @version 01.00 */ public class JavaSource2HTMLConverterExt extends JavaSource2HTMLConverter { // private static Logger LOGGER = Logger.getLogger(JavaSource2HTMLConverterExt.class); public boolean java2HtmlHomepageLinkEnabled = false; private final String HTML_BLOCK_HEADER = "\n\n<!-- ======================================================== -->\n" + "<!-- = Java Sourcecode to HTML automatically converted code = -->\n<!-- = " + Version.getJava2HtmlConverterTitle() + " " + Version.getBuildDate() + " by Markus Gebhard markus@jave.de = -->\n" + "<!-- = Further information: http://www.java2html.de = -->\n" + "<div align=\"{0}\" class=\"java\">\n" + "<table border=\"{1}\" cellpadding=\"3\" " + "cellspacing=\"0\" bgcolor=\"{2}\">\n"; private Class<?, ?> klass; private String STYLE = "style=\"background-color: #C7D6D7;\""; // private String blue = "#C7D6D7;"; // private String yellow = "#FBF4B7"; // private String pink = "#FBC6C6"; // private String blue = "#C7D6D7"; private int lineCifferCount; public JavaSource2HTMLConverterExt(Class<?, ?> klass) { super(); this.klass = klass; } public void convert(JavaSource source, JavaSourceConversionOptions options, BufferedWriter writer) throws IOException { if (source == null) { throw new IllegalStateException("Trying to write out converted code without having source set."); } String alignValue = getHtmlAlignValue(options.getHorizontalAlignment()); String bgcolorValue = options.getStyleTable().get(JavaSourceType.BACKGROUND).getHtmlColor(); String borderValue = (options.isShowTableBorder()) ? "2" : "0"; writer.write(MessageFormat.format(HTML_BLOCK_HEADER, new Object[] { alignValue, borderValue, bgcolorValue })); if ((options.isShowFileName()) && (source.getFileName() != null)) { writeFileName(source, writer); } writer.write(" <tr>"); writer.newLine(); writeSourceCode(source, options, writer); writer.write(" </tr>"); writer.newLine(); if ((options.isShowJava2HtmlLink()) || (java2HtmlHomepageLinkEnabled)) { writer .write(" <!-- start Java2Html link -->\n <tr>\n <td align=\"right\">\n<small>\n<a href=\"http://www.java2html.de\" target=\"_blank\">Java2html</a>\n</small>\n </td>\n </tr>\n <!-- end Java2Html link -->\n"); } writer .write("</table>\n</div>\n<!-- = END of automatically generated HTML code = -->\n<!-- ======================================================== -->\n\n"); } private String getHtmlAlignValue(HorizontalAlignment alignment) { final StringHolder stringHolder = new StringHolder(); alignment.accept(new IHorizontalAlignmentVisitor() { public void visitLeftAlignment(HorizontalAlignment horizontalAlignment) { stringHolder.setValue("left"); } public void visitRightAlignment(HorizontalAlignment horizontalAlignment) { stringHolder.setValue("right"); } public void visitCenterAlignment(HorizontalAlignment horizontalAlignment) { stringHolder.setValue("center"); } }); return stringHolder.getValue(); } private void writeFileName(JavaSource source, BufferedWriter writer) throws IOException { writer.write(" <!-- start headline -->\n <tr>\n <td colspan=\"2\">\n <center><font size=\"+2\">\n <code><b>\n"); writer.write(source.getFileName()); writer.newLine(); writer.write(" </b></code>\n </font></center>\n </td>\n </tr>\n <!-- end headline -->\n"); } private void writeSourceCode(JavaSource source, JavaSourceConversionOptions options, BufferedWriter writer) throws IOException { writer.write(" <!-- start source code -->\n <td nowrap=\"nowrap\" valign=\"top\" align=\"left\">\n <code>\n"); this.lineCifferCount = String.valueOf(source.getLineCount()).length(); JavaSourceIterator iterator = source.getIterator(); int lineNumber = 1; while (iterator.hasNext()) { JavaSourceRun run = iterator.getNext(); if (run.isAtStartOfLine()) { if (options.isAddLineAnchors()) { writeLineAnchorStart(options, writer, lineNumber); } if (options.isShowLineNumbers()) { writeLineNumber(options, writer, lineNumber); } if (options.isAddLineAnchors()) { writeLineAnchorEnd(writer); } ++lineNumber; } toHTML(options.getStyleTable(), run, writer, lineNumber); if ((run.isAtEndOfLine()) && (iterator.hasNext())) { writer.write("<br />"); writer.newLine(); } } writer.write("</code>\n \n </td>\n <!-- end source code -->\n"); } private void writeLineAnchorEnd(BufferedWriter writer) throws IOException { writer.write("</a>"); } private void writeLineAnchorStart(JavaSourceConversionOptions options, BufferedWriter writer, int lineNumber) throws IOException { writer.write("<a name=\""); writer.write(options.getLineAnchorPrefix() + lineNumber); writer.write("\">"); } private void writeLineNumber(JavaSourceConversionOptions options, BufferedWriter writer, int lineNo) throws IOException { JavaSourceStyleEntry styleEntry = options.getStyleTable().get(JavaSourceType.LINE_NUMBERS); writeStyleStart(writer, styleEntry, -1); String lineNumber = String.valueOf(lineNo); int cifferCount = this.lineCifferCount - lineNumber.length(); while (cifferCount > 0) { writer.write(48); --cifferCount; } writer.write(lineNumber); writeStyleEnd(writer, styleEntry); writer.write(" "); } private void toHTML(JavaSourceStyleTable styleTable, JavaSourceRun run, BufferedWriter writer, int lineNumber) throws IOException { JavaSourceStyleEntry style = styleTable.get(run.getType()); writeStyleStart(writer, style, lineNumber); String t = HtmlUtilities.encode(run.getCode(), "\n "); for (int i = 0; i < t.length(); ++i) { char ch = t.charAt(i); if (ch == ' ') { writer.write(" "); } else { writer.write(ch); } } writeStyleEnd(writer, style); } private void writeStyleStart(BufferedWriter writer, JavaSourceStyleEntry style, int lineNumber) throws IOException { if (getCovered(this.klass, lineNumber - 1)) { writer.write("<font color=\"" + style.getHtmlColor() + "\" " + STYLE + ">"); } else { writer.write("<font color=\"" + style.getHtmlColor() + "\">"); } if (style.isBold()) { writer.write("<b>"); } if (style.isItalic()) { writer.write("<i>"); } } private void writeStyleEnd(BufferedWriter writer, JavaSourceStyleEntry style) throws IOException { if (style.isItalic()) { writer.write("</i>"); } if (style.isBold()) { writer.write("</b>"); } writer.write("</font>"); } private boolean getCovered(Class<?, ?> klass, double lineNumber) { for (Method<?, ?> method : klass.getChildren()) { // LOGGER.warn("Method : " + method); // LOGGER.warn("Children : " + method.getChildren()); for (Line<?, ?> line : method.getChildren()) { // LOGGER.warn("Line : " + line + ", line number : " + line.getNumber() + ", number : " + lineNumber); if (line.getNumber() == lineNumber) { boolean lineCovered = line.getCounter() > 0; if (lineCovered) { // LOGGER.warn("Line covered : " + lineCovered); } return lineCovered; } } } for (Class<?, ?> innerKlass : klass.getInnerClasses()) { boolean covered = getCovered(innerKlass, lineNumber); if (covered) { // LOGGER.warn("Covered : " + covered); return true; } } return false; } }