blob: 4590a8b7f062c2a7c7a4a6b88b42a78a81c2e258 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.accumulo.monitor.util;
import java.util.ArrayList;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.apache.accumulo.monitor.servlets.BasicServlet;
import org.apache.accumulo.monitor.util.celltypes.CellType;
import org.apache.accumulo.monitor.util.celltypes.StringType;
public class Table {
private String tableName;
private String caption;
private String captionclass;
private String subcaption;
private ArrayList<TableColumn<?>> columns;
private ArrayList<TableRow> rows;
private boolean hasBegunAddingRows = false;
public Table(String tableName, String caption) {
this(tableName, caption, null);
}
public Table(String tableName, String caption, String captionClass) {
this.tableName = tableName;
this.caption = caption;
this.captionclass = captionClass;
this.subcaption = null;
this.columns = new ArrayList<>();
this.rows = new ArrayList<>();
}
public synchronized void setSubCaption(String subcaption) {
this.subcaption = subcaption;
}
public synchronized <T> void addColumn(TableColumn<T> column) {
if (hasBegunAddingRows)
throw new IllegalStateException("Cannot add more columns newServer rows have been added");
columns.add(column);
}
private synchronized <T> void addColumn(String title, CellType<T> type, String legend,
boolean sortable) {
if (type == null)
type = new StringType<>();
type.setSortable(sortable);
addColumn(new TableColumn<>(title, type, legend));
}
public synchronized <T> void addUnsortableColumn(String title, CellType<T> type, String legend) {
addColumn(title, type, legend, false);
}
public synchronized <T> void addSortableColumn(String title, CellType<T> type, String legend) {
addColumn(title, type, legend, true);
}
public synchronized void addUnsortableColumn(String title) {
addUnsortableColumn(title, null, null);
}
public synchronized void addSortableColumn(String title) {
addSortableColumn(title, null, null);
}
public synchronized TableRow prepareRow() {
hasBegunAddingRows = true;
return new TableRow(columns.size());
}
public synchronized void addRow(TableRow row) {
hasBegunAddingRows = true;
if (columns.size() != row.size())
throw new IllegalStateException("Row must be the same size as the columns");
rows.add(row);
}
public synchronized void addRow(Object... cells) {
TableRow row = prepareRow();
if (cells.length != columns.size())
throw new IllegalArgumentException("Argument length not equal to the number of columns");
for (Object cell : cells)
row.add(cell);
addRow(row);
}
public synchronized void generate(HttpServletRequest req, StringBuilder sb) {
String page = req.getRequestURI();
if (columns.isEmpty())
throw new IllegalStateException("No columns in table");
for (TableRow row : rows)
if (row.size() != columns.size())
throw new RuntimeException("Each row must have the same number of columns");
boolean sortAscending = !"false".equals(BasicServlet.getCookieValue(req, "tableSort."
+ BasicServlet.encode(page) + "." + BasicServlet.encode(tableName) + "." + "sortAsc"));
int sortCol = -1; // set to first sortable column by default
int numLegends = 0;
for (int i = 0; i < columns.size(); ++i) {
TableColumn<?> col = columns.get(i);
if (sortCol < 0 && col.getCellType().isSortable())
sortCol = i;
if (col.getLegend() != null && !col.getLegend().isEmpty())
++numLegends;
}
// only get cookie if there is a possibility that it is sortable
if (sortCol >= 0) {
String sortColStr = BasicServlet.getCookieValue(req, "tableSort." + BasicServlet.encode(page)
+ "." + BasicServlet.encode(tableName) + "." + "sortCol");
if (sortColStr != null) {
try {
int col = Integer.parseInt(sortColStr);
// only bother if specified column is sortable
if (!(col < 0 || sortCol >= columns.size())
&& columns.get(col).getCellType().isSortable())
sortCol = col;
} catch (NumberFormatException e) {
// ignore improperly formatted user cookie
}
}
}
boolean showLegend = false;
if (numLegends > 0) {
String showStr = BasicServlet.getCookieValue(req, "tableLegend." + BasicServlet.encode(page)
+ "." + BasicServlet.encode(tableName) + "." + "show");
showLegend = showStr != null && Boolean.parseBoolean(showStr);
}
sb.append("<div>\n");
sb.append("<a name='").append(tableName).append("'>&nbsp;</a>\n");
sb.append("<table id='").append(tableName).append("' class='sortable'>\n");
sb.append("<caption");
if (captionclass != null && !captionclass.isEmpty())
sb.append(" class='").append(captionclass).append("'");
sb.append(">\n");
if (caption != null && !caption.isEmpty())
sb.append("<span class='table-caption'>").append(caption).append("</span><br />\n");
if (subcaption != null && !subcaption.isEmpty())
sb.append("<span class='table-subcaption'>").append(subcaption).append("</span><br />\n");
String redir = BasicServlet.currentPage(req);
if (numLegends > 0) {
String legendUrl = String.format("/op?action=toggleLegend&redir=%s&page=%s&table=%s&show=%s",
redir, page, tableName, !showLegend);
sb.append("<a href='").append(legendUrl).append("'>").append(showLegend ? "Hide" : "Show")
.append("&nbsp;Legend</a>\n");
if (showLegend)
sb.append("<div class='left show'><dl>\n");
}
for (int i = 0; i < columns.size(); ++i) {
TableColumn<?> col = columns.get(i);
String title = col.getTitle();
if (rows.size() > 1 && col.getCellType().isSortable()) {
String url = String.format("/op?action=sortTable&redir=%s&page=%s&table=%s&%s=%s", redir,
page, tableName, sortCol == i ? "asc" : "col", sortCol == i ? !sortAscending : i);
String img = "";
if (sortCol == i)
img = String.format("&nbsp;<img width='10px' height='10px' src='/web/%s.gif' alt='%s' />",
sortAscending ? "up" : "down", !sortAscending ? "^" : "v");
col.setTitle(String.format("<a href='%s'>%s%s</a>", url, title, img));
}
String legend = col.getLegend();
if (showLegend && legend != null && !legend.isEmpty())
sb.append("<dt class='smalltext'><b>").append(title.replace("<br />", "&nbsp;"))
.append("</b><dd>").append(legend).append("</dd></dt>\n");
}
if (showLegend && numLegends > 0)
sb.append("</dl></div>\n");
sb.append("</caption>\n");
sb.append("<tr>");
boolean first = true;
for (TableColumn<?> col : columns) {
String cellValue = col.getTitle() == null ? "" : String.valueOf(col.getTitle()).trim();
sb.append("<th").append(first ? " class='firstcell'" : "").append(">")
.append(cellValue.isEmpty() ? "-" : cellValue).append("</th>");
first = false;
}
sb.append("</tr>\n");
// don't sort if no columns are sortable or if there aren't enough rows
if (rows.size() > 1 && sortCol > -1) {
Collections.sort(rows, TableRow.getComparator(sortCol, columns.get(sortCol).getCellType()));
if (!sortAscending)
Collections.reverse(rows);
}
boolean highlight = true;
for (TableRow row : rows) {
for (int i = 0; i < row.size(); ++i) {
try {
row.set(i, columns.get(i).getCellType().format(row.get(i)));
} catch (Exception ex) {
throw new RuntimeException("Unable to process column " + i, ex);
}
}
row(sb, highlight, columns, row);
highlight = !highlight;
}
if (rows.isEmpty())
sb.append("<tr><td class='center' colspan='").append(columns.size())
.append("'><i>Empty</i></td></tr>\n");
sb.append("</table>\n</div>\n\n");
}
private static void row(StringBuilder sb, boolean highlight, ArrayList<TableColumn<?>> columns,
TableRow row) {
sb.append(highlight ? "<tr class='highlight'>" : "<tr>");
boolean first = true;
for (int i = 0; i < row.size(); ++i) {
String cellValue = String.valueOf(row.get(i)).trim();
if (cellValue.isEmpty() || cellValue.equals(String.valueOf((Object) null)))
cellValue = "-";
sb.append("<td class='").append(first ? "firstcell" : "");
if (columns.get(i).getCellType().alignment() != null)
sb.append(first ? " " : "").append(columns.get(i).getCellType().alignment());
sb.append("'>").append(cellValue).append("</td>");
first = false;
}
sb.append("</tr>\n");
}
}