franta-hg@128: /** franta-hg@128: * SQL-DK franta-hg@128: * Copyright © 2014 František Kučera (frantovo.cz) franta-hg@128: * franta-hg@128: * This program is free software: you can redistribute it and/or modify franta-hg@128: * it under the terms of the GNU General Public License as published by franta-hg@128: * the Free Software Foundation, either version 3 of the License, or franta-hg@128: * (at your option) any later version. franta-hg@128: * franta-hg@128: * This program is distributed in the hope that it will be useful, franta-hg@128: * but WITHOUT ANY WARRANTY; without even the implied warranty of franta-hg@128: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the franta-hg@128: * GNU General Public License for more details. franta-hg@128: * franta-hg@128: * You should have received a copy of the GNU General Public License franta-hg@128: * along with this program. If not, see . franta-hg@128: */ franta-hg@128: package info.globalcode.sql.dk.formatting; franta-hg@128: franta-hg@134: import info.globalcode.sql.dk.Constants; franta-hg@134: import info.globalcode.sql.dk.NamedParameter; franta-hg@134: import info.globalcode.sql.dk.Parameter; franta-hg@134: import info.globalcode.sql.dk.Xmlns; franta-hg@134: import info.globalcode.sql.dk.configuration.DatabaseDefinition; franta-hg@134: import info.globalcode.sql.dk.configuration.Properties; franta-hg@134: import info.globalcode.sql.dk.configuration.Property; franta-hg@134: import static info.globalcode.sql.dk.formatting.AbstractXmlFormatter.qname; franta-hg@135: import java.util.Date; franta-hg@134: import java.util.HashMap; franta-hg@134: import java.util.List; franta-hg@134: import java.util.Map; franta-hg@135: import java.util.Scanner; franta-hg@134: import javax.xml.namespace.QName; franta-hg@134: franta-hg@128: /** franta-hg@128: * franta-hg@128: * @author Ing. František Kučera (frantovo.cz) franta-hg@128: */ franta-hg@128: public class XhtmlFormatter extends AbstractXmlFormatter { franta-hg@128: franta-hg@128: public static final String NAME = "xhtml"; // bash-completion:formatter franta-hg@135: private static final String CSS_FILE = "info/globalcode/sql/dk/formatter/XhtmlFormatter.css"; franta-hg@134: private int resultSetCounter = 0; franta-hg@134: private int updatesResultCounter = 0; franta-hg@128: franta-hg@128: public XhtmlFormatter(FormatterContext formatterContext) { franta-hg@134: super(addDefaults(formatterContext)); franta-hg@134: } franta-hg@134: franta-hg@134: /** franta-hg@134: * Do not indent text – preserve whitespace for pre elements franta-hg@134: */ franta-hg@134: private static FormatterContext addDefaults(FormatterContext formatterContext) { franta-hg@134: Properties defaults = new Properties(1); franta-hg@134: defaults.add(new Property(PROPERTY_INDENT_TEXT, "false")); franta-hg@134: formatterContext.getProperties().setLastDefaults(defaults); franta-hg@134: return formatterContext; franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeStartBatch() { franta-hg@134: super.writeStartBatch(); franta-hg@134: printStartDocument(); franta-hg@134: Map attributes = new HashMap<>(1); franta-hg@134: attributes.put(qname("xmlns"), Xmlns.XHTML); franta-hg@134: printStartElement(qname("html"), attributes); franta-hg@134: franta-hg@134: printStartElement(qname("head")); franta-hg@134: printTextElement(qname("title"), null, Constants.PROGRAM_NAME + ": batch results"); franta-hg@135: printCss(); franta-hg@134: printEndElement(); franta-hg@134: franta-hg@134: printStartElement(qname("body")); franta-hg@134: } franta-hg@134: franta-hg@135: private void printCss() { franta-hg@135: franta-hg@135: try (Scanner css = new Scanner(getClass().getClassLoader().getResourceAsStream(CSS_FILE))) { franta-hg@135: Map attributes = new HashMap<>(1); franta-hg@135: attributes.put(qname("type"), "text/css"); franta-hg@135: printStartElement(qname("style"), attributes); franta-hg@135: while (css.hasNext()) { franta-hg@135: printText(css.nextLine(), true); franta-hg@135: } franta-hg@135: printEndElement(); franta-hg@135: } franta-hg@135: } franta-hg@135: franta-hg@134: @Override franta-hg@134: public void writeEndBatch() { franta-hg@134: super.writeEndBatch(); franta-hg@134: printEndElement(); franta-hg@134: printEndElement(); franta-hg@134: printEndDocument(); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeStartDatabase(DatabaseDefinition databaseDefinition) { franta-hg@134: super.writeStartDatabase(databaseDefinition); franta-hg@134: printTextElement(qname("h1"), null, "Database: " + databaseDefinition.getName()); franta-hg@135: franta-hg@135: printStartElement(qname("p")); franta-hg@135: printText("This is XHTML output of batch executed at: ", true); franta-hg@135: printText(new Date().toString(), true); franta-hg@135: printEndElement(); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeQuery(String sql) { franta-hg@134: super.writeQuery(sql); franta-hg@134: printTextElement(qname("h3"), null, "SQL:"); franta-hg@134: printTextElement(qname("pre"), null, sql); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeParameters(List parameters) { franta-hg@134: super.writeParameters(parameters); franta-hg@134: franta-hg@134: if (parameters == null || parameters.isEmpty()) { franta-hg@134: printTextElement(qname("p"), null, "(this query has no parameters)"); franta-hg@134: } else { franta-hg@134: printTextElement(qname("h3"), null, "Parameters:"); franta-hg@134: franta-hg@134: printStartElement(qname("table")); franta-hg@134: franta-hg@135: printStartElement(qname("thead")); franta-hg@134: printStartElement(qname("tr")); franta-hg@135: printTextElement(qname("td"), null, "id"); franta-hg@134: printTextElement(qname("td"), null, "type"); franta-hg@134: printTextElement(qname("td"), null, "value"); franta-hg@134: printEndElement(); franta-hg@134: printEndElement(); franta-hg@134: franta-hg@134: printStartElement(qname("tbody")); franta-hg@134: for (int i = 0; i < parameters.size(); i++) { franta-hg@134: Parameter p = parameters.get(i); franta-hg@134: printStartElement(qname("tr")); franta-hg@134: String numberOrName; franta-hg@134: if (p instanceof NamedParameter) { franta-hg@134: numberOrName = ((NamedParameter) p).getName(); franta-hg@134: } else { franta-hg@134: numberOrName = String.valueOf(i + 1); franta-hg@134: } franta-hg@134: printTextElement(qname("td"), null, numberOrName); franta-hg@134: printTextElement(qname("td"), null, p.getType().name()); franta-hg@135: printTableData(p.getValue()); franta-hg@134: printEndElement(); franta-hg@134: } franta-hg@134: printEndElement(); franta-hg@134: franta-hg@134: printEndElement(); franta-hg@134: } franta-hg@134: } franta-hg@134: franta-hg@135: private void printTableData(Object value) { franta-hg@135: Map attributes = new HashMap<>(1); franta-hg@135: if (value instanceof Number || value instanceof Boolean) { franta-hg@135: attributes.put(qname("class"), "number"); franta-hg@135: } franta-hg@135: printTextElement(qname("td"), attributes, String.valueOf(value)); franta-hg@135: } franta-hg@135: franta-hg@134: @Override franta-hg@134: public void writeColumnsHeader(ColumnsHeader header) { franta-hg@134: super.writeColumnsHeader(header); franta-hg@134: printTextElement(qname("h3"), null, "Data:"); franta-hg@134: printStartElement(qname("table")); franta-hg@135: printStartElement(qname("thead")); franta-hg@134: printStartElement(qname("tr")); franta-hg@134: for (ColumnDescriptor cd : header.getColumnDescriptors()) { franta-hg@134: // TODO: type franta-hg@134: printTextElement(qname("td"), null, cd.getLabel()); franta-hg@134: } franta-hg@134: printEndElement(); franta-hg@134: printEndElement(); franta-hg@134: franta-hg@134: printStartElement(qname("tbody")); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeStartRow() { franta-hg@134: super.writeStartRow(); franta-hg@134: printStartElement(qname("tr")); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeColumnValue(Object value) { franta-hg@134: super.writeColumnValue(value); franta-hg@135: printTableData(value); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeEndRow() { franta-hg@134: super.writeEndRow(); franta-hg@134: printEndElement(); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeStartResultSet() { franta-hg@134: super.writeStartResultSet(); franta-hg@134: resultSetCounter++; franta-hg@135: printEmptyElement(qname("hr"), null); franta-hg@135: printTextElement(qname("h2"), null, "Result set #" + resultSetCounter); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeEndResultSet() { franta-hg@134: super.writeEndResultSet(); franta-hg@134: printEndElement(); franta-hg@134: printEndElement(); franta-hg@135: franta-hg@135: printTextElement(qname("p"), null, "Record count: " + getCurrentRowCount()); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeStartUpdatesResult() { franta-hg@134: super.writeStartUpdatesResult(); franta-hg@134: updatesResultCounter++; franta-hg@135: printEmptyElement(qname("hr"), null); franta-hg@135: printTextElement(qname("h2"), null, "Updates result #" + updatesResultCounter); franta-hg@134: } franta-hg@134: franta-hg@134: @Override franta-hg@134: public void writeUpdatedRowsCount(int updatedRowsCount) { franta-hg@134: super.writeUpdatedRowsCount(updatedRowsCount); franta-hg@134: printTextElement(qname("p"), null, "Updated rows: " + updatedRowsCount); franta-hg@134: } franta-hg@128: }