Package com.google.visualization.datasource.render

Source Code of com.google.visualization.datasource.render.HtmlRenderer

// Copyright 2009 Google Inc.
//
// Licensed 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.

package com.google.visualization.datasource.render;

import com.google.visualization.datasource.base.ReasonType;
import com.google.visualization.datasource.base.ResponseStatus;
import com.google.visualization.datasource.base.StatusType;
import com.google.visualization.datasource.base.Warning;
import com.google.visualization.datasource.datatable.ColumnDescription;
import com.google.visualization.datasource.datatable.DataTable;
import com.google.visualization.datasource.datatable.TableCell;
import com.google.visualization.datasource.datatable.TableRow;
import com.google.visualization.datasource.datatable.ValueFormatter;
import com.google.visualization.datasource.datatable.value.BooleanValue;
import com.google.visualization.datasource.datatable.value.ValueType;

import com.ibm.icu.util.ULocale;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.StringWriter;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

/**
* Takes a data table and returns an html string.
*
* @author Nimrod T.
*/
public class HtmlRenderer {
 
  /**
   * Log.
   */
  private static final Log log = LogFactory.getLog("HtmlRenderer")

  /**
   * Private constructor.
   */
  private HtmlRenderer() {}

  /**
   * Pattern for matching against <a> tags with hrefs.
   * Used in sanitizeDetailedMessage.
   */
  private static final Pattern DETAILED_MESSAGE_A_TAG_REGEXP = Pattern.compile(
      "([^<]*<a(( )*target=\"_blank\")*(( )*target='_blank')*"
      + "(( )*href=\"[^\"]*\")*(( )*href='[^']*')*>[^<]*</a>)+[^<]*");

  /**
   * Pattern for matching against "javascript:".
   * Used in sanitizeDetailedMessage.
   */
  private static final Pattern BAD_JAVASCRIPT_REGEXP = Pattern.compile("javascript(( )*):");

  /**
   * Generates an HTML string representation of a data table.
   *
   * @param dataTable The data table to render.
   * @param locale The locale. If null, uses the default from
   *     {@code LocaleUtil#getDefaultLocale}.
   *
   * @return The char sequence with the html string.
   */
  public static CharSequence renderDataTable(DataTable dataTable, ULocale locale) {
    // Create an xml document with head and an empty body.
    Document document = createDocument();
    Element bodyElement = appendHeadAndBody(document);

    // Populate the xml document.
    Element tableElement = document.createElement("table");
    bodyElement.appendChild(tableElement);
    tableElement.setAttribute("border", "1");
    tableElement.setAttribute("cellpadding", "2");
    tableElement.setAttribute("cellspacing", "0");

    // Labels tr element.
    List<ColumnDescription> columnDescriptions = dataTable.getColumnDescriptions();
    Element trElement = document.createElement("tr");
    trElement.setAttribute("style", "font-weight: bold; background-color: #aaa;");
    for (ColumnDescription columnDescription : columnDescriptions) {
      Element tdElement = document.createElement("td");
      tdElement.setTextContent(columnDescription.getLabel());
      trElement.appendChild(tdElement);
    }
    tableElement.appendChild(trElement);

    Map<ValueType, ValueFormatter> formatters = ValueFormatter.createDefaultFormatters(locale);
    // Table tr elements.
    int rowCount = 0;
    for (TableRow row : dataTable.getRows()) {
      rowCount++;
      trElement = document.createElement("tr");
      String backgroundColor = (rowCount % 2 != 0) ? "#f0f0f0" : "#ffffff";
      trElement.setAttribute("style", "background-color: " + backgroundColor);

      List<TableCell> cells = row.getCells();
      for (int c = 0; c < cells.size(); c++) {
        ValueType valueType = columnDescriptions.get(c).getType();
        TableCell cell = cells.get(c);
        String cellFormattedText = cell.getFormattedValue();
        if (cellFormattedText == null) {
          cellFormattedText = formatters.get(cell.getType()).format(cell.getValue());
        }

        Element tdElement = document.createElement("td");
        if (cell.isNull()) {
          tdElement.setTextContent("\u00a0");
        } else {
          switch (valueType) {
            case NUMBER:
              tdElement.setAttribute("align", "right");
              tdElement.setTextContent(cellFormattedText);
              break;
            case BOOLEAN:
              BooleanValue booleanValue = (BooleanValue) cell.getValue();
              tdElement.setAttribute("align", "center");
              if (booleanValue.getValue()) {
                tdElement.setTextContent("\u2714"); // Check mark.
              } else {
                tdElement.setTextContent("\u2717"); // X mark.
              }
              break;
            default:
              if (StringUtils.isEmpty(cellFormattedText)) {
                tdElement.setTextContent("\u00a0"); // nbsp.
              } else {
                tdElement.setTextContent(cellFormattedText);
              }
          }
        }
        trElement.appendChild(tdElement);
      }
      tableElement.appendChild(trElement);
    }
    bodyElement.appendChild(tableElement);

    // Warnings:
    for (Warning warning : dataTable.getWarnings()) {
      bodyElement.appendChild(document.createElement("br"));
      bodyElement.appendChild(document.createElement("br"));
      Element messageElement = document.createElement("div");
      messageElement.setTextContent(warning.getReasonType().getMessageForReasonType() + ". " +
          warning.getMessage());
      bodyElement.appendChild(messageElement);
    }

    return transformDocumentToHtmlString(document);
  }

  /**
   * Transforms a document to a valid html string.
   *
   * @param document The document to transform
   *
   * @return A string representation of a valid html.
   */
  private static String transformDocumentToHtmlString(Document document) {
    // Generate a CharSequence from the xml document.
    Transformer transformer = null;
    try {
      transformer = TransformerFactory.newInstance().newTransformer();
    } catch (TransformerConfigurationException e) {
      log.error("Couldn't create a transformer", e);
      throw new RuntimeException("Couldn't create a transformer. This should never happen.", e);
    }
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD HTML 4.01//EN");
    transformer.setOutputProperty(OutputKeys.METHOD, "html");
    transformer.setOutputProperty(OutputKeys.VERSION, "4.01");
   
    DOMSource source = new DOMSource(document);
    Writer writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    try {
      transformer.transform(source, result);
    } catch (TransformerException e) {
      log.error("Couldn't transform", e);
      throw new RuntimeException("Couldn't transform. This should never happen.", e);
    }

    return writer.toString();
  }

  /**
   * Sanitizes the html in the detailedMessage, to allow only href inside &lt;a&gt; tags.
   *
   * @param detailedMessage The detailedMessage.
   *
   * @return The sanitized detailedMessage.
   */
  static String sanitizeDetailedMessage(String detailedMessage) {
    if (StringUtils.isEmpty(detailedMessage)) {
      return "";
    }

    if (DETAILED_MESSAGE_A_TAG_REGEXP.matcher(detailedMessage).matches()
        && (!BAD_JAVASCRIPT_REGEXP.matcher(detailedMessage).find())) {
      // No need to escape.
      return detailedMessage;
    } else {
      // Need to html escape.
      return EscapeUtil.htmlEscape(detailedMessage);
    }
  }

  /**
   * Renders a simple html for the given responseStatus.
   *
   * @param responseStatus The response message.
   *
   * @return A simple html for the given responseStatus.
   */
  public static CharSequence renderHtmlError(ResponseStatus responseStatus) {
    // Get the responseStatus details.
    StatusType status = responseStatus.getStatusType();
    ReasonType reason = responseStatus.getReasonType();
    String detailedMessage = responseStatus.getDescription();

    // Create an xml document with head and an empty body.
    Document document = createDocument();
    Element bodyElement = appendHeadAndBody(document);

    // Populate the xml document.
    Element oopsElement = document.createElement("h3");
    oopsElement.setTextContent("Oops, an error occured.");
    bodyElement.appendChild(oopsElement);

    if (status != null) {
      String text = "Status: " + status.lowerCaseString();
      appendSimpleText(document, bodyElement, text);
    }

    if (reason != null) {
      String text = "Reason: " + reason.getMessageForReasonType(null);
      appendSimpleText(document, bodyElement, text);
    }

    if (detailedMessage != null) {
      String text = "Description: " + sanitizeDetailedMessage(detailedMessage);
      appendSimpleText(document, bodyElement, text);
    }

    return transformDocumentToHtmlString(document);
  }

  /**
   * Creates a document element.
   *
   * @return A document element.
   */
  private static Document createDocument() {
    DocumentBuilder documentBuilder = null;
    try {
      documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    } catch (ParserConfigurationException e) {
      log.error("Couldn't create a document builder", e);
      throw new RuntimeException(
          "Couldn't create a document builder. This should never happen.", e);
    }
    Document document = documentBuilder.newDocument();
    return document;
  }

  /**
   * Appends &lt;html&gt;, &lt;head&gt;, &lt;title&gt;, and &lt;body&gt; elements to the document.
   *
   * @param document The containing document.
   *
   * @return The &lt;body&gt; element.
   */
  private static Element appendHeadAndBody(Document document) {
    Element htmlElement = document.createElement("html");
    document.appendChild(htmlElement);
    Element headElement = document.createElement("head");
    htmlElement.appendChild(headElement);
    Element titleElement = document.createElement("title");
    titleElement.setTextContent("Google Visualization");
    headElement.appendChild(titleElement);
    Element bodyElement = document.createElement("body");
    htmlElement.appendChild(bodyElement);
    return bodyElement;
  }

  /**
   * Appends a simple text line to the body of the document.
   *
   * @param document The containing document.
   * @param bodyElement The body of the document.
   * @param text The text to append.
   */
  private static void appendSimpleText(Document document, Element bodyElement, String text) {
    Element statusElement = document.createElement("div");
    statusElement.setTextContent(text);
    bodyElement.appendChild(statusElement);
  }
}
TOP

Related Classes of com.google.visualization.datasource.render.HtmlRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.