public void renderHtml(HtmlWriter out, HtmlPage contextPage) {

    if (this.dataProvider != null) {
      synchronized (this.beanList) {
        this.beanList.clear();
        Object[] newValues = this.dataProvider.getRows();
        for (Object o : newValues) {
          this.beanList.add(o);
        }
      }
    }

    out.append("<table><thead>");
    for (Iterator propertyNameIterator = this.propertyNameList.iterator();
        propertyNameIterator.hasNext(); ) {
      String propertyName = (String) propertyNameIterator.next();
      out.append("<th>" + this.getColumnHeader(propertyName) + "</th>");
    }
    out.append("</tr></thead><tbody>");

    for (Iterator objectIterator = this.beanList.iterator(); objectIterator.hasNext(); ) {
      out.append("<tr>");
      Object nextBean = (Object) objectIterator.next();

      try {
        Map getMethodMap = this.findAvailableGetters(nextBean);

        for (Iterator propertyNameIterator = this.propertyNameList.iterator();
            propertyNameIterator.hasNext(); ) {
          String propertyName = (String) propertyNameIterator.next();
          out.append("<td>");
          try {
            Method getter = (Method) getMethodMap.get(propertyName);
            if (getter == null) {
              String msg =
                  "Bean of " + nextBean + " does not have a property named " + propertyName;
              throw new RuntimeException(msg);
            }
            Object value = getter.invoke(nextBean, (Object[]) new String[0]);

            this.formatValue(propertyName, value, out, contextPage);

          } catch (Exception e) {
            out.append("<span class=\"error\">n/a</span>");
            out.writeStacktrace(e, true);
          }
          out.append("</td>");
        }
      } catch (Exception e) {
        out.append("<td colspan=\"" + propertyNameList.size() + "\">");
        out.append("<span class=\"error\">n/a</span>");
        out.writeStacktrace(e, true);

        out.append("</td>");
      }
      out.append("</tr>");
    }

    out.append("</tbody></table>");
  }
 private void formatValue(
     String propertyName, Object value, HtmlWriter out, HtmlPage contextPage) {
   // TODO implement custom formatting for columns
   if (value == null) {
     out.write("n/a");
     return;
   }
   try {
     CellRenderer renderer = this.propertyCellRendererMap.get(propertyName);
     if (renderer == null) {
       renderer = DEFAULT_RENDERER;
     }
     renderer.renderCellContent(value, out, contextPage);
   } catch (Exception e) {
     out.write("n/a");
     out.writeStacktrace(e, true);
   }
 }