001package org.javasimon.console.html; 002 003import org.javasimon.Simon; 004import org.javasimon.console.SimonType; 005import org.javasimon.console.reflect.Getter; 006import org.javasimon.console.reflect.GetterFactory; 007import org.javasimon.console.text.StringifierFactory; 008 009import java.io.IOException; 010import java.io.Writer; 011 012/** 013 * Class to ease HTML generation. 014 * 015 * @author gquintana 016 */ 017public class HtmlBuilder<T extends HtmlBuilder> { 018 019 /** Delegate write. */ 020 private final Writer writer; 021 /** Stringifier factory. */ 022 private final StringifierFactory stringifierFactory; 023 024 /** Constructor without stringifier factory. */ 025 public HtmlBuilder(Writer writer) { 026 this.writer = writer; 027 this.stringifierFactory = null; 028 } 029 030 /** Constructor with stringifier factory. */ 031 public HtmlBuilder(Writer writer, StringifierFactory stringifierFactory) { 032 this.writer = writer; 033 this.stringifierFactory = stringifierFactory; 034 } 035 036 /** 037 * Begin an element without closing (no ending >). 038 * 039 * @param element tag name 040 * @param id element ID 041 * @param cssClass CSS class name 042 */ 043 private void doBegin(String element, String id, String cssClass) throws IOException { 044 writer.write('<'); 045 writer.write(element); 046 attr("id", id); 047 attr("class", cssClass); 048 } 049 050 /** 051 * Add attribute. 052 * 053 * @param name Attribute name 054 * @param value Attribute value 055 */ 056 public T attr(String name, String value) throws IOException { 057 if (value != null) { 058 writer.write(' '); 059 writer.write(name); 060 writer.write("=\""); 061 writer.write(value); 062 writer.write('\"'); 063 } 064 return (T) this; 065 } 066 067 /** 068 * Begin an element. 069 * 070 * @param element Tag name 071 * @param id Element Id 072 * @param cssClass CSS class name 073 */ 074 public T begin(String element, String id, String cssClass) throws IOException { 075 doBegin(element, id, cssClass); 076 writer.write('>'); 077 return (T) this; 078 } 079 080 /** 081 * Begin an element. 082 */ 083 public T begin(String element) throws IOException { 084 return begin(element, null, null); 085 } 086 087 /** 088 * Simple element. 089 * 090 * @param element Tag name 091 * @param id Element Id 092 * @param cssClass CSS class name 093 */ 094 public T element(String element, String id, String cssClass) throws IOException { 095 doBegin(element, id, cssClass); 096 writer.write(" />"); 097 return (T) this; 098 } 099 100 /** 101 * End an element. 102 * 103 * @param element Tag name 104 */ 105 public T end(String element) throws IOException { 106 writer.write("</"); 107 writer.write(element); 108 writer.write('>'); 109 return (T) this; 110 } 111 112 /** 113 * Writes text. 114 * 115 * @param text Text (can be null) 116 */ 117 public T text(String text) throws IOException { 118 if (text != null) { 119 writer.write(text); 120 } 121 return (T) this; 122 } 123 124 /** 125 * Writes verbatim. 126 * 127 * @param text Text 128 */ 129 public T write(String text) throws IOException { 130 writer.write(text); 131 return (T) this; 132 } 133 134 /** 135 * Adds a CSS StyleSheet link. 136 */ 137 private T cssResource(String path) throws IOException { 138 return (T) write("<link href=\"../resource/").write(path).write("\" rel=\"stylesheet\" type=\"text/css\" />"); 139 } 140 141 private T resources(Iterable<HtmlResource> resources) throws IOException { 142 // Write CSS Resources 143 cssResource("css/javasimon.css"); 144 for (HtmlResource resource : resources) { 145 if (resource.getType() == HtmlResourceType.CSS) { 146 cssResource(resource.getPath()); 147 } 148 } 149 // Write JavaScript Resources 150 for (HtmlResource resource : resources) { 151 if (resource.getType() == HtmlResourceType.JS) { 152 write("<script src=\"../resource/").write(resource.getPath()).write("\" type=\"text/javascript\"></script>"); 153 } 154 } 155 return (T) this; 156 } 157 158 /** 159 * Page header. 160 * 161 * @param title Page title 162 */ 163 public T header(String title, Iterable<HtmlResource> resources) throws IOException { 164 return (T) begin("html") 165 .begin("head") 166 .begin("title").text("Simon Console: ").text(title).end("title") 167 .resources(resources) 168 .end("head") 169 .begin("body") 170 .begin("h1") 171 .write("<img id=\"logo\" src=\"../resource/images/logo.png\" alt=\"Logo\" />") 172 .text("Simon Console: ").text(title) 173 .end("h1"); 174 } 175 176 /** 177 * Page footer. 178 */ 179 public T footer() throws IOException { 180 return (T) end("body").end("html"); 181 } 182 183 /** 184 * Write value using appropriate stringifier. 185 * 186 * @param value Typed value 187 * @param subType Sub type 188 */ 189 public <X> T value(X value, String subType) throws IOException { 190 return text(stringifierFactory.toString(value, subType)); 191 } 192 193 /** 194 * Write Simon property (using Java Bean convention). 195 * 196 * @param simon Simon 197 * @param propertyName Property name 198 */ 199 public T simonProperty(Simon simon, String propertyName) throws IOException { 200 Getter getter = GetterFactory.getGetter(simon.getClass(), propertyName); 201 if (getter != null) { 202 value(getter.get(simon), getter.getSubType()); 203 } 204 return (T) this; 205 } 206 207 /** 208 * Apply stringifier on object and write it. 209 * 210 * @param object Object 211 */ 212 public T object(Object object) throws IOException { 213 text(stringifierFactory.toString(object)); 214 return (T) this; 215 } 216 217 /** 218 * Icon image representing Simon Type. 219 * 220 * @param simonType Simon Type 221 * @param rootPath Path to root of Simon Console resources 222 */ 223 public T simonTypeImg(SimonType simonType, String rootPath) throws IOException { 224 String image = null; 225 switch (simonType) { 226 case COUNTER: 227 image = "TypeCounter.png"; 228 break; 229 case STOPWATCH: 230 image = "TypeStopwatch.png"; 231 break; 232 case UNKNOWN: 233 image = "TypeUnknown.png"; 234 break; 235 } 236 String label = simonType.name().toLowerCase(); 237 doBegin("img", null, label + " icon"); 238 attr("src", rootPath + "resource/images/" + image); 239 attr("alt", label); 240 writer.write(" />"); 241 return (T) this; 242 } 243}