001package org.javasimon.console.action; 002 003import org.javasimon.Sample; 004import org.javasimon.Simon; 005import org.javasimon.console.Action; 006import org.javasimon.console.ActionContext; 007import org.javasimon.console.ActionException; 008import org.javasimon.console.SimonType; 009import org.javasimon.console.SimonTypeFactory; 010import org.javasimon.console.SimonVisitor; 011import org.javasimon.console.SimonVisitors; 012import org.javasimon.console.TimeFormatType; 013import org.javasimon.console.reflect.Getter; 014import org.javasimon.console.reflect.GetterFactory; 015import org.javasimon.console.text.Stringifier; 016import org.javasimon.console.text.StringifierFactory; 017 018import java.io.IOException; 019import java.io.PrintWriter; 020import java.util.ArrayList; 021import java.util.List; 022import java.util.Set; 023 024import javax.servlet.ServletException; 025 026/** 027 * Base class for exporting Simons as tabular data. 028 * The following methods are called during rendering and can be overridden: 029 * <ul> 030 * <li>{@link #printTable }: <ul> 031 * <li>{@link #printHeaderRow}: <ul> 032 * <li>{@link #printHeaderCell} : {@link #printCell} </li> 033 * </ul></li> 034 * <li>{@link #printBody}: <ul> 035 * <li>{@link #printBodyRow}: <ul> 036 * <li>{@link #printBodyCell} : {@link #printCell} </li> 037 * </ul></li> 038 * </ul></li> 039 * </ul></li> 040 * </ul> 041 * 042 * @author gquintana 043 */ 044public class AbstractTableAction extends Action { 045 046 /** Value formatter. */ 047 protected StringifierFactory stringifierFactory; 048 /** Pattern for Simon name filtering. */ 049 private String pattern; 050 /** Types for Simon type filtering. */ 051 private Set<SimonType> types; 052 /** Column list in response. */ 053 private List<Column> columns = new ArrayList<>(); 054 /** Content type of response. */ 055 protected final String contentType; 056 /** Decimal format pattern used for printing doubles. */ 057 protected String numberPattern = StringifierFactory.READABLE_NUMBER_PATTERN; 058 059 /** Base constructor initializes columns list. */ 060 protected AbstractTableAction(ActionContext context, String contentType) { 061 super(context); 062 this.contentType = contentType; 063 columns.add(new Column<String>("Name", "name")); 064 columns.add(new Column<SimonType>("Type", "type") { 065 private Stringifier<SimonType> stringifier; 066 067 @Override 068 public SimonType getValue(Object object) { 069 return SimonTypeFactory.getValueFromInstance((Sample) object); 070 } 071 072 @Override 073 public String getFormattedValue(Object object) { 074 return getStringifier(object).toString(getValue(object)); 075 } 076 077 @Override 078 public Stringifier<SimonType> getStringifier(Object object) { 079 if (stringifier == null) { 080 stringifier = stringifierFactory.getStringifier(SimonType.class); 081 } 082 return stringifier; 083 } 084 }); 085 columns.add(new Column<Long>("Counter", "counter")); 086 columns.add(new Column<Long>("Total", "total")); 087 columns.add(new Column<Long>("Min", "min")); 088 columns.add(new Column<Long>("Mean", "mean")); 089 columns.add(new Column<Long>("Last", "last")); 090 columns.add(new Column<Long>("Max", "max")); 091 columns.add(new Column<Double>("Std Dev", "standardDeviation")); 092 columns.add(new Column<Long>("First Use", "firstUsage")); 093 columns.add(new Column<Long>("Last Use", "lastUsage")); 094 columns.add(new Column<String>("Note", "note")); 095 096 } 097 098 public String getPattern() { 099 return pattern; 100 } 101 102 public void setPattern(String pattern) { 103 this.pattern = pattern; 104 } 105 106 @Override 107 public void readParameters() { 108 TimeFormatType timeFormat = getContext().getParameterAsEnum("timeFormat", TimeFormatType.class, TimeFormatType.MILLISECOND); 109 stringifierFactory.init(timeFormat, 110 StringifierFactory.READABLE_DATE_PATTERN, 111 numberPattern); 112 pattern = getContext().getParameterAsString("pattern", null); 113 types = getContext().getParametersAsEnums("type", SimonType.class, null); 114 } 115 116 protected void printTable(PrintWriter writer) throws IOException { 117 printHeaderRow(writer); 118 printBody(writer); 119 } 120 121 protected void printHeaderRow(PrintWriter writer) throws IOException { 122 for (Column column : columns) { 123 printHeaderCell(column, writer); 124 } 125 } 126 127 protected void printHeaderCell(Column c, PrintWriter writer) throws IOException { 128 printCell(c, c.getTitle(), writer); 129 } 130 131 protected void printBody(PrintWriter writer) throws IOException { 132 SimonVisitors.visitList(getContext().getManager(), pattern, types, new SimonVisitorImpl(writer)); 133 } 134 135 protected void printBodyRow(Simon simon, PrintWriter writer) throws IOException { 136 printBodyRow(simon.sample(), writer); 137 } 138 139 protected void printBodyRow(Sample sample, PrintWriter writer) throws IOException { 140 for (Column column : columns) { 141 printBodyCell(column, sample, writer); 142 } 143 } 144 145 protected void printBodyCell(Column c, Sample sample, PrintWriter writer) throws IOException { 146 printCell(c, c.getFormattedValue(sample), writer); 147 } 148 149 protected void printCell(Column c, String s, PrintWriter writer) throws IOException { 150 if (s != null) { 151 writer.write(s); 152 } 153 } 154 155 public void execute() throws ServletException, IOException, ActionException { 156 dontCache(); 157 PrintWriter writer = null; 158 try { 159 getContext().setContentType(contentType); 160 writer = getContext().getWriter(); 161 printTable(writer); 162 } finally { 163 if (writer != null) { 164 writer.flush(); 165 } 166 } 167 } 168 169 private class SimonVisitorImpl implements SimonVisitor { 170 171 private final PrintWriter writer; 172 173 public SimonVisitorImpl(PrintWriter writer) { 174 this.writer = writer; 175 } 176 177 public void visit(Simon simon) throws IOException { 178 printBodyRow(simon, writer); 179 } 180 } 181 182 protected class Column<T> { 183 /** Column title/header. */ 184 private final String title; 185 /** Column property name. */ 186 private final String name; 187 188 public Column(String title, String name) { 189 this.title = title; 190 this.name = name; 191 } 192 193 /** Get column property name. */ 194 public String getName() { 195 return name; 196 } 197 198 /** Get column property title/header. */ 199 public String getTitle() { 200 return title; 201 } 202 203 /** 204 * Returns getter for given column and row (simon). 205 * 206 * @param object Simon row 207 * @return getter 208 */ 209 @SuppressWarnings("unchecked") 210 private Getter<T> getGetter(Object object) { 211 return GetterFactory.getGetter(object.getClass(), name); 212 } 213 214 /** Returns raw column value. */ 215 public T getValue(Object object) { 216 Getter<T> getter = getGetter(object); 217 return getter == null ? null : getter.get(object); 218 } 219 220 /** 221 * Get stringier used for given column and row. 222 * 223 * @param object Row (simon) 224 * @return Stringifier 225 */ 226 public Stringifier<T> getStringifier(Object object) { 227 Getter<T> getter = getGetter(object); 228 if (getter == null) { 229 return stringifierFactory.getNullStringifier(); 230 } else { 231 return stringifierFactory.getStringifier(getter.getType(), getter.getSubType()); 232 } 233 } 234 235 /** Get formatted column value. */ 236 public String getFormattedValue(Object object) { 237 Getter<T> getter = getGetter(object); 238 if (getter == null) { 239 return stringifierFactory.toString(null); 240 } else { 241 return stringifierFactory.toString(getter.get(object), getter.getSubType()); 242 } 243 } 244 } 245}