001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.html; 014 015import java.util.*; 016 017import org.apache.juneau.*; 018import org.apache.juneau.annotation.*; 019import org.apache.juneau.html.annotation.*; 020import org.apache.juneau.serializer.*; 021import org.apache.juneau.svl.*; 022 023/** 024 * Serializes POJOs to HTTP responses as HTML documents. 025 * 026 * <h5 class='topic'>Media types</h5> 027 * 028 * Handles <c>Accept</c> types: <bc>text/html</bc> 029 * <p> 030 * Produces <c>Content-Type</c> types: <bc>text/html</bc> 031 * 032 * <h5 class='topic'>Description</h5> 033 * 034 * Same as {@link HtmlSerializer}, except wraps the response in <code><xt><html></code>, 035 * <code><xt><head></code>, and <code><xt><body></code> tags so that it can be rendered in a browser. 036 * 037 * <p> 038 * Configurable properties are typically specified via <ja>@Rest(properties)</ja> and <ja>@RestMethod(properties)</ja> 039 * annotations, although they can also be set programmatically via the <c>RestResponse.setProperty()</c> method. 040 * 041 * <h5 class='section'>Example:</h5> 042 * <p class='bcode w800'> 043 * <ja>@Rest</ja>( 044 * messages=<js>"nls/AddressBookResource"</js>, 045 * properties={ 046 * <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_title</jsf>, value=<js>"$L{title}"</js>), 047 * <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_description</jsf>, value=<js>"$L{description}"</js>), 048 * <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_navlinks</jsf>, value=<js>"{options:'servlet:/?method=OPTIONS',doc:'doc'}"</js>) 049 * } 050 * ) 051 * <jk>public class</jk> AddressBookResource <jk>extends</jk> BasicRestServletJena { 052 * </p> 053 * 054 * <p> 055 * Note that shortcut annotations are also provided for these particular settings: 056 * <p class='bcode w800'> 057 * <ja>@Rest</ja>( 058 * messages=<js>"nls/AddressBookResource"</js>, 059 * title=<js>"$L{title}"</js>, 060 * description=<js>"$L{description}"</js> 061 * ) 062 * <ja>@HtmlDocConfig</ja>( 063 * navlinks={ 064 * <js>"options: servlet:/?method=OPTIONS"</js>, 065 * <js>"doc: doc"</js> 066 * } 067 * ) 068 * </p> 069 * 070 * <p> 071 * The <c>$L{...}</c> variable represent localized strings pulled from the resource bundle identified by the 072 * <c>messages</c> annotation. 073 * <br>These variables are replaced at runtime based on the HTTP request locale. 074 * <br>Several built-in runtime variable types are defined, and the API can be extended to include user-defined variables. 075 */ 076@ConfigurableContext 077public class HtmlDocSerializer extends HtmlStrippedDocSerializer { 078 079 //------------------------------------------------------------------------------------------------------------------- 080 // Configurable properties 081 //------------------------------------------------------------------------------------------------------------------- 082 083 static final String PREFIX = "HtmlDocSerializer"; 084 085 /** 086 * Configuration property: Aside section contents. 087 * 088 * <h5 class='section'>Property:</h5> 089 * <ul class='spaced-list'> 090 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_aside HTMLDOC_aside} 091 * <li><b>Name:</b> <js>"HtmlDocSerializer.aside.ls"</js> 092 * <li><b>Data type:</b> <c>List<String></c> 093 * <li><b>System property:</b> <c>HtmlDocSerializer.aside</c> 094 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_ASIDE</c> 095 * <li><b>Default:</b> empty list 096 * <li><b>Session property:</b> <jk>true</jk> 097 * <li><b>Annotations:</b> 098 * <ul> 099 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#aside()} 100 * </ul> 101 * </ul> 102 * 103 * <h5 class='section'>Description:</h5> 104 * <p> 105 * Allows you to specify the contents of the aside section on the HTML page. 106 * The aside section floats on the right of the page for providing content supporting the serialized content of 107 * the page. 108 * 109 * <p> 110 * By default, the aside section is empty. 111 * 112 * <h5 class='section'>Example:</h5> 113 * <p class='bcode w800'> 114 * <ja>@HtmlDocConfig</ja>( 115 * aside={ 116 * <js>"<ul>"</js>, 117 * <js>" <li>Item 1"</js>, 118 * <js>" <li>Item 2"</js>, 119 * <js>" <li>Item 3"</js>, 120 * <js>"</ul>"</js> 121 * } 122 * ) 123 * </p> 124 */ 125 public static final String HTMLDOC_aside = PREFIX + ".aside.ls"; 126 127 /** 128 * Configuration property: Footer section contents. 129 * 130 * <h5 class='section'>Property:</h5> 131 * <ul class='spaced-list'> 132 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_footer HTMLDOC_footer} 133 * <li><b>Name:</b> <js>"HtmlDocSerializer.footer.ls"</js> 134 * <li><b>Data type:</b> <c>List<String></c> 135 * <li><b>System property:</b> <c>HtmlDocSerializer.footer</c> 136 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_FOOTER</c> 137 * <li><b>Default:</b> empty list 138 * <li><b>Session property:</b> <jk>true</jk> 139 * <li><b>Annotations:</b> 140 * <ul> 141 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#footer()} 142 * </ul> 143 * </ul> 144 * 145 * <h5 class='section'>Description:</h5> 146 * <p> 147 * Allows you to specify the contents of the footer section on the HTML page. 148 * 149 * <p> 150 * By default, the footer section is empty. 151 * 152 * <h5 class='section'>Example:</h5> 153 * <p class='bcode w800'> 154 * <ja>@HtmlDocConfig</ja>( 155 * footer={ 156 * <js>"<b>This interface is great!</b>"</js> 157 * } 158 * ) 159 * </p> 160 */ 161 public static final String HTMLDOC_footer = PREFIX + ".footer.ls"; 162 163 /** 164 * Configuration property: Additional head section content. 165 * 166 * <h5 class='section'>Property:</h5> 167 * <ul class='spaced-list'> 168 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_head HTMLDOC_head} 169 * <li><b>Name:</b> <js>"HtmlDocSerializer.head.ls"</js> 170 * <li><b>Data type:</b> <c>List<String></c> 171 * <li><b>System property:</b> <c>HtmlDocSerializer.head</c> 172 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_HEAD</c> 173 * <li><b>Default:</b> empty list 174 * <li><b>Session property:</b> <jk>true</jk> 175 * <li><b>Annotations:</b> 176 * <ul> 177 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#head()} 178 * </ul> 179 * </ul> 180 * 181 * <h5 class='section'>Description:</h5> 182 * <p> 183 * Adds the specified HTML content to the head section of the page. 184 * 185 * <h5 class='section'>Example:</h5> 186 * <p class='bcode w800'> 187 * <ja>@Rest</ja>( 188 * properties={ 189 * <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_links</jsf>, 190 * value=<js>"['<link rel=\"icon\" href=\"htdocs/mypageicon.ico\">']"</js>) 191 * } 192 * ) 193 * </p> 194 * 195 * <p> 196 * A shortcut on <ja>@Rest</ja> is also provided for this setting: 197 * <p class='bcode w800'> 198 * <ja>@HtmlDocConfig</ja>( 199 * head={ 200 * <js>"<link rel='icon' href='$U{servlet:/htdocs/mypageicon.ico}'>"</js> 201 * } 202 * ) 203 * </p> 204 */ 205 public static final String HTMLDOC_head = PREFIX + ".head.ls"; 206 207 /** 208 * Configuration property: Header section contents. 209 * 210 * <h5 class='section'>Property:</h5> 211 * <ul class='spaced-list'> 212 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_header HTMLDOC_header} 213 * <li><b>Name:</b> <js>"HtmlDocSerializer.header.ls"</js> 214 * <li><b>Data type:</b> <c>List<String></c> 215 * <li><b>System property:</b> <c>HtmlDocSerializer.header</c> 216 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_HEADER</c> 217 * <li><b>Default:</b> empty list 218 * <li><b>Session property:</b> <jk>true</jk> 219 * <li><b>Annotations:</b> 220 * <ul> 221 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#header()} 222 * </ul> 223 * </ul> 224 * 225 * <h5 class='section'>Description:</h5> 226 * <p> 227 * Allows you to override the contents of the header section on the HTML page. 228 * The header section normally contains the title and description at the top of the page. 229 * 230 * <h5 class='section'>Example:</h5> 231 * <p class='bcode w800'> 232 * <ja>@HtmlDocConfig</ja>( 233 * header={ 234 * <js>"<h1>My own header</h1>"</js> 235 * } 236 * ) 237 * </p> 238 */ 239 public static final String HTMLDOC_header = PREFIX + ".header.ls"; 240 241 /** 242 * Configuration property: Nav section contents. 243 * 244 * <h5 class='section'>Property:</h5> 245 * <ul class='spaced-list'> 246 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nav HTMLDOC_nav} 247 * <li><b>Name:</b> <js>"HtmlDocSerializer.nav.ls"</js> 248 * <li><b>Data type:</b> <c>List<String></c> 249 * <li><b>System property:</b> <c>HtmlDocSerializer.nav</c> 250 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_NAV</c> 251 * <li><b>Default:</b> empty list 252 * <li><b>Session property:</b> <jk>true</jk> 253 * <li><b>Annotations:</b> 254 * <ul> 255 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#nav()} 256 * </ul> 257 * </ul> 258 * 259 * <h5 class='section'>Description:</h5> 260 * <p> 261 * Allows you to override the contents of the nav section on the HTML page. 262 * The nav section normally contains the page links at the top of the page. 263 * 264 * <h5 class='section'>Example:</h5> 265 * <p class='bcode w800'> 266 * <ja>@HtmlDocConfig</ja>( 267 * nav={ 268 * <js>"<p class='special-navigation'>This is my special navigation content</p>"</js> 269 * } 270 * ) 271 * </p> 272 * 273 * <p> 274 * When this property is specified, the {@link #HTMLDOC_navlinks} property is ignored. 275 */ 276 public static final String HTMLDOC_nav = PREFIX + ".nav.ls"; 277 278 /** 279 * Configuration property: Page navigation links. 280 * 281 * <h5 class='section'>Property:</h5> 282 * <ul class='spaced-list'> 283 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_navlinks HTMLDOC_navlinks} 284 * <li><b>Name:</b> <js>"HtmlDocSerializer.navlinks.ls"</js> 285 * <li><b>Data type:</b> <c>List<String></c> 286 * <li><b>System property:</b> <c>HtmlDocSerializer.navlinks</c> 287 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_NAVLINKS</c> 288 * <li><b>Default:</b> empty list 289 * <li><b>Session property:</b> <jk>true</jk> 290 * <li><b>Annotations:</b> 291 * <ul> 292 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#navlinks()} 293 * </ul> 294 * </ul> 295 * 296 * <h5 class='section'>Description:</h5> 297 * <p> 298 * Adds a list of hyperlinks immediately under the title and description but above the content of the page. 299 * 300 * <p> 301 * This can be used to provide convenient hyperlinks when viewing the REST interface from a browser. 302 * 303 * <p> 304 * The value is an array of strings with two possible values: 305 * <ul> 306 * <li>A key-value pair representing a hyperlink label and href: 307 * <br><js>"google: http://google.com"</js> 308 * <li>Arbitrary HTML. 309 * </ul> 310 * 311 * <p> 312 * Relative URLs are considered relative to the servlet path. 313 * For example, if the servlet path is <js>"http://localhost/myContext/myServlet"</js>, and the 314 * URL is <js>"foo"</js>, the link becomes <js>"http://localhost/myContext/myServlet/foo"</js>. 315 * Absolute (<js>"/myOtherContext/foo"</js>) and fully-qualified (<js>"http://localhost2/foo"</js>) URLs 316 * can also be used in addition to various other protocols specified by {@link UriResolver} such as 317 * <js>"servlet:/..."</js>. 318 * 319 * <h5 class='section'>Example:</h5> 320 * <p> 321 * The <c>AddressBookResource</c> sample class uses this property... 322 * <p class='bcode w800'> 323 * <ja>@Rest</ja>( 324 * properties={ 325 * <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_navlinks</jsf>, 326 * value=<js>"['options: servlet:/?method=OPTIONS', 'doc: doc']"</js>) 327 * } 328 * ) 329 * <jk>public class</jk> AddressBookResource <jk>extends</jk> BasicRestServletJena { 330 * </p> 331 * 332 * <p> 333 * A shortcut on <ja>@Rest</ja> is also provided for this setting: 334 * <p class='bcode w800'> 335 * <ja>@HtmlDocConfig</ja>( 336 * navlinks={ 337 * <js>"options: servlet:/?method=OPTIONS"</js>, 338 * <js>"doc: doc"</js> 339 * } 340 * ) 341 * <jk>public class</jk> AddressBookResource <jk>extends</jk> BasicRestServletJena { 342 * </p> 343 */ 344 public static final String HTMLDOC_navlinks = PREFIX + ".navlinks.ls"; 345 346 /** 347 * Configuration property: Add to the {@link #HTMLDOC_navlinks} property. 348 */ 349 public static final String HTMLDOC_navlinks_add = PREFIX + ".navlinks.ls/add"; 350 351 /** 352 * Configuration property: No-results message. 353 * 354 * <h5 class='section'>Property:</h5> 355 * <ul class='spaced-list'> 356 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_noResultsMessage HTMLDOC_noResultsMessage} 357 * <li><b>Name:</b> <js>"HtmlDocSerializer.noResultsMessage.s"</js> 358 * <li><b>Data type:</b> <c>String</c> 359 * <li><b>System property:</b> <c>HtmlDocSerializer.noResultsMessage</c> 360 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_NORESULTSMESSAGE</c> 361 * <li><b>Default:</b> <js>"<p>no results</p>"</js> 362 * <li><b>Session property:</b> <jk>false</jk> 363 * <li><b>Annotations:</b> 364 * <ul> 365 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#noResultsMessage()} 366 * </ul> 367 * </ul> 368 * 369 * <h5 class='section'>Description:</h5> 370 * <p> 371 * Allows you to specify the string message used when trying to serialize an empty array or empty list. 372 * 373 * <h5 class='section'>Example:</h5> 374 * <p class='bcode w800'> 375 * <ja>@HtmlDocConfig</ja>( 376 * noResultsMessage=<js>"<b>This interface is great!</b>"</js> 377 * ) 378 * </p> 379 * 380 * <p> 381 * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string. 382 */ 383 public static final String HTMLDOC_noResultsMessage = PREFIX + ".noResultsMessage.s"; 384 385 /** 386 * Configuration property: Prevent word wrap on page. 387 * 388 * <h5 class='section'>Property:</h5> 389 * <ul class='spaced-list'> 390 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_nowrap HTMLDOC_nowrap} 391 * <li><b>Name:</b> <js>"HtmlDocSerializer.nowrap.b"</js> 392 * <li><b>Data type:</b> <jk>boolean</jk> 393 * <li><b>System property:</b> <c>HtmlDocSerializer.nowrap</c> 394 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_NOWRAP</c> 395 * <li><b>Default:</b> <jk>false</jk> 396 * <li><b>Session property:</b> <jk>false</jk> 397 * <li><b>Annotations:</b> 398 * <ul> 399 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#nowrap()} 400 * </ul> 401 * </ul> 402 * 403 * <h5 class='section'>Description:</h5> 404 * <p> 405 * Adds <js>"* {white-space:nowrap}"</js> to the CSS instructions on the page to prevent word wrapping. 406 */ 407 public static final String HTMLDOC_nowrap = PREFIX + ".nowrap.b"; 408 409 /** 410 * Configuration property: Javascript code. 411 * 412 * <h5 class='section'>Property:</h5> 413 * <ul class='spaced-list'> 414 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_script HTMLDOC_script} 415 * <li><b>Name:</b> <js>"HtmlDocSerializer.script.ls"</js> 416 * <li><b>Data type:</b> <c>List<String></c> 417 * <li><b>System property:</b> <c>HtmlDocSerializer.script</c> 418 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_SCRIPT</c> 419 * <li><b>Default:</b> empty list 420 * <li><b>Session property:</b> <jk>true</jk> 421 * <li><b>Annotations:</b> 422 * <ul> 423 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#script()} 424 * </ul> 425 * </ul> 426 * 427 * <h5 class='section'>Description:</h5> 428 * <p> 429 * Adds the specified Javascript code to the HTML page. 430 * 431 * <h5 class='section'>Example:</h5> 432 * <p class='bcode w800'> 433 * <ja>@Rest</ja>( 434 * properties={ 435 * <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_script</jsf>, 436 * value=<js>"alert('hello!');"</js>) 437 * } 438 * ) 439 * </p> 440 * 441 * <p> 442 * A shortcut on <ja>@Rest</ja> is also provided for this setting: 443 * <p class='bcode w800'> 444 * <ja>@HtmlDocConfig</ja>( 445 * script={ 446 * <js>"alert('hello!');"</js> 447 * } 448 * ) 449 * </p> 450 */ 451 public static final String HTMLDOC_script = PREFIX + ".script.ls"; 452 453 /** 454 * Configuration property: Add to the {@link #HTMLDOC_script} property. 455 */ 456 public static final String HTMLDOC_script_add = PREFIX + ".script.ls/add"; 457 458 /** 459 * Configuration property: CSS style code. 460 * 461 * <h5 class='section'>Property:</h5> 462 * <ul class='spaced-list'> 463 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_style HTMLDOC_style} 464 * <li><b>Name:</b> <js>"HtmlDocSerializer.style.ls"</js> 465 * <li><b>Data type:</b> <c>List<String></c> 466 * <li><b>System property:</b> <c>HtmlDocSerializer.style</c> 467 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_STYLE</c> 468 * <li><b>Default:</b> empty list 469 * <li><b>Session property:</b> <jk>true</jk> 470 * <li><b>Annotations:</b> 471 * <ul> 472 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#style()} 473 * </ul> 474 * </ul> 475 * 476 * <h5 class='section'>Description:</h5> 477 * <p> 478 * Adds the specified CSS instructions to the HTML page. 479 * 480 * <h5 class='section'>Example:</h5> 481 * <p class='bcode w800'> 482 * <ja>@Rest</ja>( 483 * properties={ 484 * <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_style</jsf>, 485 * value=<js>"h3 { color: red; }\nh5 { font-weight: bold; }"</js>) 486 * } 487 * ) 488 * </p> 489 * 490 * <p> 491 * A shortcut on <ja>@Rest</ja> is also provided for this setting: 492 * <p class='bcode w800'> 493 * <ja>@HtmlDocConfig</ja>( 494 * style={ 495 * <js>"h3 { color: red; }"</js>, 496 * <js>"h5 { font-weight: bold; }"</js> 497 * } 498 * ) 499 * </p> 500 */ 501 public static final String HTMLDOC_style = PREFIX + ".style.ls"; 502 503 /** 504 * Configuration property: Add to the {@link #HTMLDOC_style} property. 505 */ 506 public static final String HTMLDOC_style_add = PREFIX + ".style.ls/add"; 507 508 /** 509 * Configuration property: Stylesheet import URLs. 510 * 511 * <h5 class='section'>Property:</h5> 512 * <ul class='spaced-list'> 513 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_stylesheet HTMLDOC_stylesheet} 514 * <li><b>Name:</b> <js>"HtmlDocSerializer.stylesheet.ls"</js> 515 * <li><b>Data type:</b> <c>List<String></c> 516 * <li><b>System property:</b> <c>HtmlDocSerializer.stylesheet</c> 517 * <li><b>Environment variable:</b> <c>HTMLDOCSERIALIZER_STYLESHEET</c> 518 * <li><b>Default:</b> empty list 519 * <li><b>Session property:</b> <jk>true</jk> 520 * <li><b>Annotations:</b> 521 * <ul> 522 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#stylesheet()} 523 * </ul> 524 * </ul> 525 * 526 * <h5 class='section'>Description:</h5> 527 * <p> 528 * Adds a link to the specified stylesheet URL. 529 * 530 * <p> 531 * Note that this stylesheet is controlled by the <code><ja>@Rest</ja>.stylesheet()</code> annotation. 532 */ 533 public static final String HTMLDOC_stylesheet = PREFIX + ".stylesheet.ls"; 534 535 /** 536 * Configuration property: Add to the {@link #HTMLDOC_stylesheet} property. 537 */ 538 public static final String HTMLDOC_stylesheet_add = PREFIX + ".stylesheet.ls/add"; 539 540 /** 541 * Configuration property: HTML document template. 542 * 543 * <h5 class='section'>Property:</h5> 544 * <ul class='spaced-list'> 545 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_template HTMLDOC_template} 546 * <li><b>Name:</b> <js>"HtmlDocSerializer.template.c"</js> 547 * <li><b>Data type:</b> <code>Class<{@link org.apache.juneau.html.HtmlDocTemplate}></code> 548 * <li><b>Default:</b> {@link org.apache.juneau.html.BasicHtmlDocTemplate} 549 * <li><b>Session property:</b> <jk>false</jk> 550 * <li><b>Annotations:</b> 551 * <ul> 552 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#template()} 553 * </ul> 554 * </ul> 555 * 556 * <h5 class='section'>Description:</h5> 557 * <p> 558 * Specifies the template to use for serializing the page. 559 * 560 * <p> 561 * By default, the {@link BasicHtmlDocTemplate} class is used to construct the contents of the HTML page, but 562 * can be overridden with your own custom implementation class. 563 * 564 * <h5 class='section'>Example:</h5> 565 * <p class='bcode w800'> 566 * <ja>@HtmlDocConfig</ja>( 567 * template=MySpecialDocTemplate.<jk>class</jk> 568 * ) 569 * </p> 570 */ 571 public static final String HTMLDOC_template = PREFIX + ".template.c"; 572 573 /** 574 * Configuration property: HTML Widgets. 575 * 576 * <h5 class='section'>Property:</h5> 577 * <ul class='spaced-list'> 578 * <li><b>ID:</b> {@link org.apache.juneau.html.HtmlDocSerializer#HTMLDOC_widgets HTMLDOC_widgets} 579 * <li><b>Name:</b> <js>"HtmlDocSerializer.widgets.lo"</js> 580 * <li><b>Data type:</b><c>List<{@link org.apache.juneau.html.HtmlWidget}|Class<{@link org.apache.juneau.html.HtmlWidget}>></c> 581 * <li><b>Default:</b> empty list 582 * <li><b>Session property:</b> <jk>false</jk> 583 * <li><b>Annotations:</b> 584 * <ul> 585 * <li class='ja'>{@link HtmlDocConfig#widgets()} 586 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlDocConfig#widgets()} 587 * </ul> 588 * <li><b>Methods:</b> 589 * <ul> 590 * <li class='jm'>{@link HtmlDocSerializerBuilder#widgets(Class...)} 591 * <li class='jm'>{@link HtmlDocSerializerBuilder#widgets(HtmlWidget...)} 592 * <li class='jm'>{@link HtmlDocSerializerBuilder#widgetsReplace(Class...)} 593 * <li class='jm'>{@link HtmlDocSerializerBuilder#widgetsReplace(HtmlWidget...)} 594 * </ul> 595 * </ul> 596 * 597 * <h5 class='section'>Description:</h5> 598 * <p> 599 * Defines widgets that can be used in conjunction with string variables of the form <js>"$W{name}"</js>to quickly 600 * generate arbitrary replacement text. 601 * 602 * Widgets resolve the following variables: 603 * <ul class='spaced-list'> 604 * <li><js>"$W{name}"</js> - Contents returned by {@link HtmlWidget#getHtml(VarResolverSession)}. 605 * <li><js>"$W{name.script}"</js> - Contents returned by {@link HtmlWidget#getScript(VarResolverSession)}. 606 * <br>The script contents are automatically inserted into the <xt><head/script></xt> section 607 * in the HTML page. 608 * <li><js>"$W{name.style}"</js> - Contents returned by {@link HtmlWidget#getStyle(VarResolverSession)}. 609 * <br>The styles contents are automatically inserted into the <xt><head/style></xt> section 610 * in the HTML page. 611 * </ul> 612 * 613 * <p> 614 * The following examples shows how to associate a widget with a REST method and then have it rendered in the links 615 * and aside section of the page: 616 * 617 * <p class='bcode w800'> 618 * <ja>@HtmlDocConfig</ja>( 619 * widgets={ 620 * MyWidget.<jk>class</jk> 621 * }, 622 * navlinks={ 623 * <js>"$W{MyWidget}"</js> 624 * }, 625 * aside={ 626 * <js>"Check out this widget: $W{MyWidget}"</js> 627 * } 628 * ) 629 * </p> 630 * 631 * <ul class='notes'> 632 * <li> 633 * Widgets are inherited from super classes, but can be overridden by reusing the widget name. 634 * </ul> 635 * 636 * <ul class='seealso'> 637 * <li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.Widgets} 638 * </ul> 639 */ 640 public static final String HTMLDOC_widgets = PREFIX + ".widgets.lo"; 641 642 //------------------------------------------------------------------------------------------------------------------- 643 // Predefined instances 644 //------------------------------------------------------------------------------------------------------------------- 645 646 /** Default serializer, all default settings. */ 647 public static final HtmlDocSerializer DEFAULT = new HtmlDocSerializer(PropertyStore.DEFAULT); 648 649 650 //------------------------------------------------------------------------------------------------------------------- 651 // Instance 652 //------------------------------------------------------------------------------------------------------------------- 653 654 private final String[] style, stylesheet, script, navlinks, head, header, nav, aside, footer; 655 private final String noResultsMessage; 656 private final boolean nowrap; 657 private final HtmlDocTemplate template; 658 private final Map<String,HtmlWidget> widgets; 659 660 private volatile HtmlSchemaDocSerializer schemaSerializer; 661 662 /** 663 * Constructor. 664 * 665 * @param ps The property store containing all the settings for this object. 666 */ 667 public HtmlDocSerializer(PropertyStore ps) { 668 this(ps, "text/html", (String)null); 669 } 670 671 /** 672 * Constructor. 673 * 674 * @param ps 675 * The property store containing all the settings for this object. 676 * @param produces 677 * The media type that this serializer produces. 678 * @param accept 679 * The accept media types that the serializer can handle. 680 * <p> 681 * Can contain meta-characters per the <c>media-type</c> specification of 682 * {@doc RFC2616.section14.1} 683 * <p> 684 * If empty, then assumes the only media type supported is <c>produces</c>. 685 * <p> 686 * For example, if this serializer produces <js>"application/json"</js> but should handle media types of 687 * <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be: 688 * <p class='bcode w800'> 689 * <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json",text/json"</js>); 690 * </p> 691 * <br>...or... 692 * <p class='bcode w800'> 693 * <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*​/json"</js>); 694 * </p> 695 * <p> 696 * The accept value can also contain q-values. 697 */ 698 public HtmlDocSerializer(PropertyStore ps, String produces, String accept) { 699 super(ps, produces, accept); 700 style = getArrayProperty(HTMLDOC_style, String.class); 701 stylesheet = getArrayProperty(HTMLDOC_stylesheet, String.class); 702 script = getArrayProperty(HTMLDOC_script, String.class); 703 head = getArrayProperty(HTMLDOC_head, String.class); 704 header = getArrayProperty(HTMLDOC_header, String.class); 705 nav = getArrayProperty(HTMLDOC_nav, String.class); 706 aside = getArrayProperty(HTMLDOC_aside, String.class); 707 footer = getArrayProperty(HTMLDOC_footer, String.class); 708 nowrap = getBooleanProperty(HTMLDOC_nowrap, false); 709 navlinks = getArrayProperty(HTMLDOC_navlinks, String.class); 710 noResultsMessage = getStringProperty(HTMLDOC_noResultsMessage, "<p>no results</p>"); 711 template = getInstanceProperty(HTMLDOC_template, HtmlDocTemplate.class, BasicHtmlDocTemplate.class); 712 713 Map<String,HtmlWidget> widgets = new HashMap<>(); 714 for (HtmlWidget w : getInstanceArrayProperty(HTMLDOC_widgets, HtmlWidget.class, new HtmlWidget[0])) 715 widgets.put(w.getName(), w); 716 this.widgets = Collections.unmodifiableMap(widgets); 717 } 718 719 @Override /* Context */ 720 public HtmlDocSerializerBuilder builder() { 721 return new HtmlDocSerializerBuilder(getPropertyStore()); 722 } 723 724 /** 725 * Instantiates a new clean-slate {@link HtmlDocSerializerBuilder} object. 726 * 727 * <p> 728 * This is equivalent to simply calling <code><jk>new</jk> HtmlDocSerializerBuilder()</code>. 729 * 730 * <p> 731 * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies 732 * the settings of the object called on. 733 * 734 * @return A new {@link HtmlDocSerializerBuilder} object. 735 */ 736 public static HtmlDocSerializerBuilder create() { 737 return new HtmlDocSerializerBuilder(); 738 } 739 740 @Override /* Serializer */ 741 public HtmlDocSerializerSession createSession() { 742 return createSession(createDefaultSessionArgs()); 743 } 744 745 @Override /* Serializer */ 746 public HtmlDocSerializerSession createSession(SerializerSessionArgs args) { 747 return new HtmlDocSerializerSession(this, args); 748 } 749 750 @Override /* XmlSerializer */ 751 public HtmlSerializer getSchemaSerializer() { 752 if (schemaSerializer == null) 753 schemaSerializer = builder().build(HtmlSchemaDocSerializer.class); 754 return schemaSerializer; 755 } 756 757 //----------------------------------------------------------------------------------------------------------------- 758 // Properties 759 //----------------------------------------------------------------------------------------------------------------- 760 761 /** 762 * Configuration property: Aside section contents. 763 * 764 * @see #HTMLDOC_aside 765 * @return 766 * The overridden contents of the aside section on the HTML page. 767 */ 768 protected final String[] getAside() { 769 return aside; 770 } 771 772 /** 773 * Configuration property: Footer section contents. 774 * 775 * @see #HTMLDOC_footer 776 * @return 777 * The overridden contents of the footer section on the HTML page. 778 */ 779 protected final String[] getFooter() { 780 return footer; 781 } 782 783 /** 784 * Configuration property: Additional head section content. 785 * 786 * @see #HTMLDOC_head 787 * @return 788 * HTML content to add to the head section of the HTML page. 789 */ 790 protected final String[] getHead() { 791 return head; 792 } 793 794 /** 795 * Configuration property: Header section contents. 796 * 797 * @see #HTMLDOC_header 798 * @return 799 * The overridden contents of the header section on the HTML page. 800 */ 801 protected final String[] getHeader() { 802 return header; 803 } 804 805 /** 806 * Configuration property: Nav section contents. 807 * 808 * @see #HTMLDOC_nav 809 * @return 810 * The overridden contents of the nav section on the HTML page. 811 */ 812 protected final String[] getNav() { 813 return nav; 814 } 815 816 /** 817 * Configuration property: Page navigation links. 818 * 819 * @see #HTMLDOC_navlinks 820 * @return 821 * Navigation links to add to the HTML page. 822 */ 823 protected final String[] getNavlinks() { 824 return navlinks; 825 } 826 827 /** 828 * Configuration property: No-results message. 829 * 830 * @see #HTMLDOC_noResultsMessage 831 * @return 832 * The message used when serializing an empty array or empty list. 833 */ 834 protected final String getNoResultsMessage() { 835 return noResultsMessage; 836 } 837 838 /** 839 * Configuration property: Prevent word wrap on page. 840 * 841 * @see #HTMLDOC_nowrap 842 * @return 843 * <jk>true</jk> if <js>"* {white-space:nowrap}"</js> shoudl be added to the CSS instructions on the page to prevent word wrapping. 844 */ 845 protected final boolean isNowrap() { 846 return nowrap; 847 } 848 849 /** 850 * Configuration property: Javascript code. 851 * 852 * @see #HTMLDOC_script 853 * @return 854 * Arbitrary Javascript to add to the HTML page. 855 */ 856 protected final String[] getScript() { 857 return script; 858 } 859 860 /** 861 * Configuration property: CSS style code. 862 * 863 * @see #HTMLDOC_style 864 * @return 865 * The CSS instructions to add to the HTML page. 866 */ 867 protected final String[] getStyle() { 868 return style; 869 } 870 871 /** 872 * Configuration property: Stylesheet import URLs. 873 * 874 * @see #HTMLDOC_stylesheet 875 * @return 876 * The link to the stylesheet of the HTML page. 877 */ 878 protected final String[] getStylesheet() { 879 return stylesheet; 880 } 881 882 /** 883 * Configuration property: HTML document template. 884 * 885 * @see #HTMLDOC_template 886 * @return 887 * The template to use for serializing the page. 888 */ 889 protected final HtmlDocTemplate getTemplate() { 890 return template; 891 } 892 893 /** 894 * Configuration property: HTML widgets. 895 * 896 * @see #HTMLDOC_widgets 897 * @return 898 * Widgets defined on this serializers. 899 */ 900 protected final Map<String,HtmlWidget> getWidgets() { 901 return widgets; 902 } 903 904 //----------------------------------------------------------------------------------------------------------------- 905 // Other methods 906 //----------------------------------------------------------------------------------------------------------------- 907 908 @Override /* Context */ 909 public ObjectMap toMap() { 910 return super.toMap() 911 .append("HtmlDocSerializer", new DefaultFilteringObjectMap() 912 .append("header", header) 913 .append("nav", nav) 914 .append("navlinks", navlinks) 915 .append("aside", aside) 916 .append("footer", footer) 917 .append("style", style) 918 .append("head", head) 919 .append("stylesheet", stylesheet) 920 .append("nowrap", nowrap) 921 .append("template", template) 922 .append("noResultsMessage", noResultsMessage) 923 .append("widgets", widgets.keySet()) 924 ); 925 } 926}