Java tutorial
/** * Copyright (c) 2011 Martin Geisse * * This file is distributed under the terms of the MIT license. */ package name.martingeisse.reporting.renderer; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.List; import java.util.Stack; import name.martingeisse.reporting.definition.nestedtable.NestedTableRow; import name.martingeisse.reporting.definition.nestedtable.NestedTableTable; import name.martingeisse.reporting.document.ChartBlock; import name.martingeisse.reporting.document.Document; import name.martingeisse.reporting.document.FormattedCompoundInlineItem; import name.martingeisse.reporting.document.IBlockItem; import name.martingeisse.reporting.document.IInlineItem; import name.martingeisse.reporting.document.NestedTable; import name.martingeisse.reporting.document.Paragraph; import name.martingeisse.reporting.document.Section; import name.martingeisse.reporting.document.Table; import name.martingeisse.reporting.document.TextInlineItem; import org.apache.commons.io.IOUtils; import org.jfree.chart.ChartUtilities; /** * TODO: document me * */ public class HtmlRenderer { /** * the outputFile */ private File outputFile; /** * the out */ private PrintWriter out; /** * the sectionStack */ private Stack<Section> sectionStack; /** * the resourceCounter */ private int resourceCounter; /** * Constructor. */ public HtmlRenderer() { } /** * Renders the specified document. * @param document the document to render * @param outputFile the output file to write to */ public void render(Document document, File outputFile) { try { this.outputFile = outputFile; this.out = new PrintWriter(outputFile, "utf-8"); this.sectionStack = new Stack<Section>(); this.resourceCounter = 0; render(document); this.out.flush(); this.out.close(); this.out = null; this.outputFile = outputFile; this.sectionStack = null; } catch (IOException e) { throw new RuntimeException(e); } } /** * @param document */ private void render(Document document) { out.println("<html><head>"); out.println(" <style type=\"text/css\">"); printFromClasspathResource(HtmlRenderer.class, "style.css"); out.println(" </style>"); out.println("</head><body>"); render(document.getRootSection()); out.println("</body></html>"); } /** * @param c * @param name */ private void printFromClasspathResource(Class<?> c, String name) { try { InputStream s = c.getResourceAsStream(name); IOUtils.copy(s, out, "utf-8"); s.close(); } catch (IOException e) { throw new RuntimeException(e); } } /** * @param section */ private void render(Section section) { sectionStack.push(section); renderTitle(section); renderDirectContents(section); renderSubsections(section); sectionStack.pop(); } /** * @param section */ private void renderTitle(Section section) { int headlineNesting = (sectionStack.size() > 6 ? 6 : sectionStack.size()); out.write("<h" + headlineNesting + ">"); Section previousStackElement = null; for (Section stackElement : sectionStack) { if (previousStackElement == null) { previousStackElement = stackElement; continue; } else { int index = previousStackElement.getSubsections().indexOf(stackElement); out.print(1 + index); out.write('.'); previousStackElement = stackElement; } } out.print(" "); printEscaped(section.getTitle()); out.write("</h" + headlineNesting + ">"); } /** * @param section */ private void renderDirectContents(Section section) { renderBlockItems(section.getDirectContents().getSubItems()); } /** * @param section */ private void renderSubsections(Section section) { for (Section subsection : section.getSubsections()) { render(subsection); } } /** * @param s */ private void printEscaped(String s) { out.print(s.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """) .replace("'", "'")); } /** * @param section */ private void renderBlockItems(List<IBlockItem> blockItems) { for (IBlockItem item : blockItems) { renderBlockItem(item); } } /** * @param section */ private void renderBlockItem(IBlockItem blockItem) { if (blockItem instanceof Paragraph) { Paragraph paragraph = (Paragraph) blockItem; renderInlineItem(paragraph.getContents()); } else if (blockItem instanceof Table) { Table table = (Table) blockItem; render(table); } else if (blockItem instanceof NestedTable) { NestedTable nestedTable = (NestedTable) blockItem; render(nestedTable); } else if (blockItem instanceof ChartBlock) { ChartBlock chartBlock = (ChartBlock) blockItem; render(chartBlock); } else { throw new RuntimeException("cannot render block item: " + blockItem); } } /** * @param section */ private void renderInlineItems(List<IInlineItem> inlineItems) { for (IInlineItem item : inlineItems) { renderInlineItem(item); } } /** * @param item */ private void renderInlineItem(IInlineItem item) { if (item instanceof FormattedCompoundInlineItem) { FormattedCompoundInlineItem formattedCompoundInlineItem = (FormattedCompoundInlineItem) item; out.print("<" + formattedCompoundInlineItem.getFormattingInstruction().getHtmlElement() + ">"); renderInlineItems(formattedCompoundInlineItem.getSubItems()); out.print("</" + formattedCompoundInlineItem.getFormattingInstruction().getHtmlElement() + ">"); } else if (item instanceof TextInlineItem) { TextInlineItem textInlineItem = (TextInlineItem) item; printEscaped(textInlineItem.getText()); } else { throw new RuntimeException("cannot render inline item: " + item); } } /** * @param table */ private void render(Table table) { out.print("<table>"); if (table.getCaption() != null) { out.print("<caption align=\"bottom\">"); printEscaped(table.getCaption()); out.print("</caption>"); } out.print("<tr class=\"odd\">"); for (String fieldName : table.getFieldNames()) { out.print("<th>"); printEscaped(fieldName); out.print("</th>"); } out.print("</tr>"); boolean even = true; for (String[] row : table.getRows()) { out.print("<tr class=\"" + (even ? "even" : "odd") + "\">"); for (String value : row) { out.print("<td>"); printEscaped(value); out.print("</td>"); } out.print("</tr>"); even = !even; } out.print("</table>"); } /** * @param chartBlock */ private void render(ChartBlock chartBlock) { File imageFile = allocateResource("chart-$.png"); out.print("<div><img src=\"" + imageFile.getName() + "\" /></div>"); try { ChartUtilities.saveChartAsPNG(imageFile, chartBlock.getChart(), 1000, 600); } catch (IOException e) { throw new RuntimeException(e); } } /** * @param nameTemplate * @return */ private File allocateResource(String nameTemplate) { int id = resourceCounter; resourceCounter++; return new File(outputFile.getParent(), nameTemplate.replace("$", "" + id)); } /** * @param table */ private void render(NestedTable table) { renderNestedTable(table.getData().getRootTable(), table.getCaption()); } private void renderNestedTable(NestedTableTable table, String caption) { int colspan = table.getColumnNames().size(); out.print("<table>"); if (caption != null) { out.print("<caption align=\"bottom\">"); printEscaped(caption); out.print("</caption>"); } if (table.getTitle() != null) { out.print("<tr class=\"header\">"); out.print("<th colspan=\"" + colspan + "\">"); printEscaped(table.getTitle()); out.print("</th>"); out.print("</tr>"); } out.print("<tr class=\"header\">"); for (String fieldName : table.getColumnNames()) { out.print("<th>"); printEscaped(fieldName); out.print("</th>"); } out.print("</tr>"); boolean even = true; for (NestedTableRow row : table.getRows()) { out.print("<tr class=\"" + (even ? "even" : "odd") + "\">"); for (String value : row.getValues()) { out.print("<td>"); printEscaped(value); out.print("</td>"); } out.print("</tr>"); for (NestedTableTable subtable : row.getSubtables()) { if (!subtable.getRows().isEmpty()) { out.print("<tr class=\"" + (even ? "even" : "odd") + "\">"); out.print("<td colspan=\"" + colspan + "\" class=\"subtableCell\">"); renderNestedTable(subtable, null); out.print("</td>"); out.print("</tr>"); } } even = !even; } out.print("</table>"); } }