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 org.apache.juneau.*;
016import org.apache.juneau.internal.*;
017import org.apache.juneau.serializer.*;
018
019/**
020 * Serializes POJOs to HTTP responses as HTML documents.
021 *
022 * <h5 class='topic'>Media types</h5>
023 *
024 * Handles <code>Accept</code> types:  <code><b>text/html</b></code>
025 * <p>
026 * Produces <code>Content-Type</code> types:  <code><b>text/html</b></code>
027 *
028 * <h5 class='topic'>Description</h5>
029 *
030 * Same as {@link HtmlSerializer}, except wraps the response in <code><xt>&lt;html&gt;</code>,
031 * <code><xt>&lt;head&gt;</code>, and <code><xt>&lt;body&gt;</code> tags so that it can be rendered in a browser.
032 *
033 * <p>
034 * Configurable properties are typically specified via <ja>@RestResource(properties)</ja> and <ja>@RestMethod(properties)</ja>
035 * annotations, although they can also be set programmatically via the <code>RestResponse.setProperty()</code> method.
036 *
037 * <h5 class='section'>Example:</h5>
038 * <p class='bcode w800'>
039 *    <ja>@RestResource</ja>(
040 *       messages=<js>"nls/AddressBookResource"</js>,
041 *       properties={
042 *          <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_title</jsf>, value=<js>"$L{title}"</js>),
043 *          <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_description</jsf>, value=<js>"$L{description}"</js>),
044 *          <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_navlinks</jsf>, value=<js>"{options:'?method=OPTIONS',doc:'doc'}"</js>)
045 *       }
046 *    )
047 *    <jk>public class</jk> AddressBookResource <jk>extends</jk> BasicRestServletJena {
048 * </p>
049 *
050 * <p>
051 * Note that shortcut annotations are also provided for these particular settings:
052 * <p class='bcode w800'>
053 *    <ja>@RestResource</ja>(
054 *       messages=<js>"nls/AddressBookResource"</js>,
055 *       title=<js>"$L{title}"</js>,
056 *       description=<js>"$L{description}"</js>,
057 *       htmldoc=<ja>@HtmlDoc</ja>(
058 *          navlinks={
059 *             <js>"options: ?method=OPTIONS"</js>,
060 *             <js>"doc: doc"</js>
061 *          }
062 *       )
063 *    )
064 * </p>
065 *
066 * <p>
067 * The <code>$L{...}</code> variable represent localized strings pulled from the resource bundle identified by the
068 * <code>messages</code> annotation.
069 * <br>These variables are replaced at runtime based on the HTTP request locale.
070 * <br>Several built-in runtime variable types are defined, and the API can be extended to include user-defined variables.
071 */
072public class HtmlDocSerializer extends HtmlStrippedDocSerializer {
073
074   //-------------------------------------------------------------------------------------------------------------------
075   // Configurable properties
076   //-------------------------------------------------------------------------------------------------------------------
077
078   private static final String PREFIX = "HtmlDocSerializer.";
079
080   /**
081    * Configuration property:  Aside section contents.
082    *
083    * <h5 class='section'>Property:</h5>
084    * <ul>
085    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.aside.ls"</js>
086    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
087    *    <li><b>Default:</b>  empty list
088    *    <li><b>Session property:</b>  <jk>true</jk>
089    * </ul>
090    *
091    * <h5 class='section'>Description:</h5>
092    * <p>
093    * Allows you to specify the contents of the aside section on the HTML page.
094    * The aside section floats on the right of the page for providing content supporting the serialized content of
095    * the page.
096    *
097    * <p>
098    * By default, the aside section is empty.
099    *
100    * <h5 class='section'>Example:</h5>
101    * <p class='bcode w800'>
102    *    <ja>@RestResource</ja>(
103    *       htmldoc=<ja>@HtmlDoc</ja>(
104    *          aside={
105    *             <js>"&lt;ul&gt;"</js>,
106    *             <js>" &lt;li&gt;Item 1"</js>,
107    *             <js>" &lt;li&gt;Item 2"</js>,
108    *             <js>" &lt;li&gt;Item 3"</js>,
109    *             <js>"&lt;/ul&gt;"</js>
110    *          }
111    *       )
112    *    )
113    * </p>
114    */
115   public static final String HTMLDOC_aside = PREFIX + "aside.ls";
116
117   /**
118    * Configuration property:  Footer section contents.
119    *
120    * <h5 class='section'>Property:</h5>
121    * <ul>
122    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.footer.ls"</js>
123    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
124    *    <li><b>Default:</b>  empty list
125    *    <li><b>Session property:</b>  <jk>true</jk>
126    * </ul>
127    *
128    * <h5 class='section'>Description:</h5>
129    * <p>
130    * Allows you to specify the contents of the footer section on the HTML page.
131    *
132    * <p>
133    * By default, the footer section is empty.
134    *
135    * <h5 class='section'>Example:</h5>
136    * <p class='bcode w800'>
137    *    <ja>@RestResource</ja>(
138    *       htmldoc=<ja>@HtmlDoc</ja>(
139    *          footer={
140    *             <js>"&lt;b&gt;This interface is great!&lt;/b&gt;"</js>
141    *          }
142    *       )
143    *    )
144    * </p>
145    */
146   public static final String HTMLDOC_footer = PREFIX + "footer.ls";
147
148   /**
149    * Configuration property:  Additional head section content.
150    *
151    * <h5 class='section'>Property:</h5>
152    * <ul>
153    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.head.ls"</js>
154    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
155    *    <li><b>Default:</b>  empty list
156    *    <li><b>Session property:</b>  <jk>true</jk>
157    * </ul>
158    *
159    * <h5 class='section'>Description:</h5>
160    * <p>
161    * Adds the specified HTML content to the head section of the page.
162    *
163    * <h5 class='section'>Example:</h5>
164    * <p class='bcode w800'>
165    *    <ja>@RestResource</ja>(
166    *       properties={
167    *          <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_links</jsf>,
168    *             value=<js>"['&lt;link rel=\"icon\" href=\"htdocs/mypageicon.ico\"&gt;']"</js>)
169    *       }
170    *    )
171    * </p>
172    *
173    * <p>
174    * A shortcut on <ja>@RestResource</ja> is also provided for this setting:
175    * <p class='bcode w800'>
176    *    <ja>@RestResource</ja>(
177    *       htmldoc=@HtmlDoc(
178    *          head={
179    *             <js>"&lt;link rel='icon' href='$U{servlet:/htdocs/mypageicon.ico}'&gt;"</js>
180    *          }
181    *       )
182    *    )
183    * </p>
184    */
185   public static final String HTMLDOC_head = PREFIX + "head.ls";
186
187   /**
188    * Configuration property:  Header section contents.
189    *
190    * <h5 class='section'>Property:</h5>
191    * <ul>
192    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.ls"</js>
193    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
194    *    <li><b>Default:</b>  empty list
195    *    <li><b>Session property:</b>  <jk>true</jk>
196    * </ul>
197    *
198    * <h5 class='section'>Description:</h5>
199    * <p>
200    * Allows you to override the contents of the header section on the HTML page.
201    * The header section normally contains the title and description at the top of the page.
202    *
203    * <h5 class='section'>Example:</h5>
204    * <p class='bcode w800'>
205    *    <ja>@RestResource</ja>(
206    *       htmldoc=<ja>@HtmlDoc</ja>(
207    *          header={
208    *             <js>"&lt;h1&gt;My own header&lt;/h1&gt;"</js>
209    *          }
210    *       )
211    *    )
212    * </p>
213    */
214   public static final String HTMLDOC_header = PREFIX + "header.ls";
215
216   /**
217    * Configuration property:  Nav section contents.
218    *
219    * <h5 class='section'>Property:</h5>
220    * <ul>
221    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.nav.ls"</js>
222    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
223    *    <li><b>Default:</b>  empty list
224    *    <li><b>Session property:</b>  <jk>true</jk>
225    * </ul>
226    *
227    * <h5 class='section'>Description:</h5>
228    * <p>
229    * Allows you to override the contents of the nav section on the HTML page.
230    * The nav section normally contains the page links at the top of the page.
231    *
232    * <h5 class='section'>Example:</h5>
233    * <p class='bcode w800'>
234    *    <ja>@RestResource</ja>(
235    *       htmldoc=<ja>@HtmlDoc</ja>(
236    *          nav={
237    *             <js>"&lt;p class='special-navigation'&gt;This is my special navigation content&lt;/p&gt;"</js>
238    *          }
239    *       )
240    *    )
241    * </p>
242    *
243    * <p>
244    * When this property is specified, the {@link #HTMLDOC_navlinks} property is ignored.
245    */
246   public static final String HTMLDOC_nav = PREFIX + "nav.ls";
247
248   /**
249    * Configuration property:  Page navigation links.
250    *
251    * <h5 class='section'>Property:</h5>
252    * <ul>
253    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.navlinks.ls"</js>
254    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
255    *    <li><b>Default:</b>  empty list
256    *    <li><b>Session property:</b>  <jk>true</jk>
257    * </ul>
258    *
259    * <h5 class='section'>Description:</h5>
260    * <p>
261    * Adds a list of hyperlinks immediately under the title and description but above the content of the page.
262    *
263    * <p>
264    * This can be used to provide convenient hyperlinks when viewing the REST interface from a browser.
265    *
266    * <p>
267    * The value is an array of strings with two possible values:
268    * <ul>
269    *    <li>A key-value pair representing a hyperlink label and href:
270    *       <br><js>"google: http://google.com"</js>
271    *    <li>Arbitrary HTML.
272    * </ul>
273    *
274    * <p>
275    * Relative URLs are considered relative to the servlet path.
276    * For example, if the servlet path is <js>"http://localhost/myContext/myServlet"</js>, and the
277    * URL is <js>"foo"</js>, the link becomes <js>"http://localhost/myContext/myServlet/foo"</js>.
278    * Absolute (<js>"/myOtherContext/foo"</js>) and fully-qualified (<js>"http://localhost2/foo"</js>) URLs
279    * can also be used in addition to various other protocols specified by {@link UriResolver} such as
280    * <js>"servlet:/..."</js>.
281    *
282    * <h5 class='section'>Example:</h5>
283    * <p>
284    * The <code>AddressBookResource</code> sample class uses this property...
285    * <p class='bcode w800'>
286    *    <ja>@RestResource</ja>(
287    *       properties={
288    *          <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_navlinks</jsf>,
289    *             value=<js>"['options: ?method=OPTIONS', 'doc: doc']"</js>)
290    *       }
291    *    )
292    *    <jk>public class</jk> AddressBookResource <jk>extends</jk> BasicRestServletJena {
293    * </p>
294    *
295    * <p>
296    * A shortcut on <ja>@RestResource</ja> is also provided for this setting:
297    * <p class='bcode w800'>
298    *    <ja>@RestResource</ja>(
299    *       htmldoc=@HtmlDoc(
300    *          navlinks={
301    *             <js>"options: ?method=OPTIONS"</js>,
302    *             <js>"doc: doc"</js>
303    *          }
304    *       )
305    *    )
306    *    <jk>public class</jk> AddressBookResource <jk>extends</jk> BasicRestServletJena {
307    * </p>
308    */
309   public static final String HTMLDOC_navlinks = PREFIX + "navlinks.ls";
310
311   /**
312    * Configuration property:  Add to the {@link #HTMLDOC_navlinks} property.
313    */
314   public static final String HTMLDOC_navlinks_add = PREFIX + "navlinks.ls/add";
315
316   /**
317    * Configuration property:  No-results message.
318    *
319    * <h5 class='section'>Property:</h5>
320    * <ul>
321    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.noResultsMessage.s"</js>
322    *    <li><b>Data type:</b>  <code>String</code>
323    *    <li><b>Default:</b>  <js>"&lt;p&gt;no results&lt;/p&gt;"</js>
324    *    <li><b>Session property:</b>  <jk>false</jk>
325    * </ul>
326    *
327    * <h5 class='section'>Description:</h5>
328    * <p>
329    * Allows you to specify the string message used when trying to serialize an empty array or empty list.
330    *
331    * <h5 class='section'>Example:</h5>
332    * <p class='bcode w800'>
333    *    <ja>@RestResource</ja>(
334    *       htmldoc=<ja>@HtmlDoc</ja>(
335    *          noResultsMessage=<js>"&lt;b&gt;This interface is great!&lt;/b&gt;"</js>
336    *       )
337    *    )
338    * </p>
339    *
340    * <p>
341    * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string.
342    */
343   public static final String HTMLDOC_noResultsMessage = PREFIX + "noResultsMessage.s";
344
345   /**
346    * Configuration property:  Prevent word wrap on page.
347    *
348    * <h5 class='section'>Property:</h5>
349    * <ul>
350    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.nowrap.b"</js>
351    *    <li><b>Data type:</b>  <code>Boolean</code>
352    *    <li><b>Default:</b>  <jk>false</jk>
353    *    <li><b>Session property:</b>  <jk>false</jk>
354    * </ul>
355    *
356    * <h5 class='section'>Description:</h5>
357    * <p>
358    * Adds <js>"* {white-space:nowrap}"</js> to the CSS instructions on the page to prevent word wrapping.
359    */
360   public static final String HTMLDOC_nowrap = PREFIX + "nowrap.b";
361
362   /**
363    * Configuration property:  Javascript code.
364    *
365    * <h5 class='section'>Property:</h5>
366    * <ul>
367    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.script.ls"</js>
368    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
369    *    <li><b>Default:</b>  empty list
370    *    <li><b>Session property:</b>  <jk>true</jk>
371    * </ul>
372    *
373    * <h5 class='section'>Description:</h5>
374    * <p>
375    * Adds the specified Javascript code to the HTML page.
376    *
377    * <h5 class='section'>Example:</h5>
378    * <p class='bcode w800'>
379    *    <ja>@RestResource</ja>(
380    *       properties={
381    *          <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_script</jsf>,
382    *             value=<js>"alert('hello!');"</js>)
383    *       }
384    *    )
385    * </p>
386    *
387    * <p>
388    * A shortcut on <ja>@RestResource</ja> is also provided for this setting:
389    * <p class='bcode w800'>
390    *    <ja>@RestResource</ja>(
391    *       htmldoc=@HtmlDoc(
392    *          script={
393    *             <js>"alert('hello!');"</js>
394    *          }
395    *       )
396    *    )
397    * </p>
398    */
399   public static final String HTMLDOC_script = PREFIX + "script.ls";
400
401   /**
402    * Configuration property:  Add to the {@link #HTMLDOC_script} property.
403    */
404   public static final String HTMLDOC_script_add = PREFIX + "script.ls/add";
405
406   /**
407    * Configuration property:  CSS style code.
408    *
409    * <h5 class='section'>Property:</h5>
410    * <ul>
411    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.style.ls"</js>
412    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
413    *    <li><b>Default:</b>  empty list
414    *    <li><b>Session property:</b>  <jk>true</jk>
415    * </ul>
416    *
417    * <h5 class='section'>Description:</h5>
418    * <p>
419    * Adds the specified CSS instructions to the HTML page.
420    *
421    * <h5 class='section'>Example:</h5>
422    * <p class='bcode w800'>
423    *    <ja>@RestResource</ja>(
424    *       properties={
425    *          <ja>@Property</ja>(name=HtmlDocSerializer.<jsf>HTMLDOC_style</jsf>,
426    *             value=<js>"h3 { color: red; }\nh5 { font-weight: bold; }"</js>)
427    *       }
428    *    )
429    * </p>
430    *
431    * <p>
432    * A shortcut on <ja>@RestResource</ja> is also provided for this setting:
433    * <p class='bcode w800'>
434    *    <ja>@RestResource</ja>(
435    *       htmldoc=@HtmlDoc(
436    *          style={
437    *             <js>"h3 { color: red; }"</js>,
438    *             <js>"h5 { font-weight: bold; }"</js>
439    *          }
440    *       )
441    *    )
442    * </p>
443    */
444   public static final String HTMLDOC_style = PREFIX + "style.ls";
445
446   /**
447    * Configuration property:  Add to the {@link #HTMLDOC_style} property.
448    */
449   public static final String HTMLDOC_style_add = PREFIX + "style.ls/add";
450
451   /**
452    * Configuration property:  Stylesheet import URLs.
453    *
454    * <h5 class='section'>Property:</h5>
455    * <ul>
456    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.stylesheet.ls"</js>
457    *    <li><b>Data type:</b>  <code>List&lt;String&gt;</code>
458    *    <li><b>Default:</b>  empty list
459    *    <li><b>Session property:</b>  <jk>true</jk>
460    * </ul>
461    *
462    * <h5 class='section'>Description:</h5>
463    * <p>
464    * Adds a link to the specified stylesheet URL.
465    *
466    * <p>
467    * Note that this stylesheet is controlled by the <code><ja>@RestResource</ja>.stylesheet()</code> annotation.
468    */
469   public static final String HTMLDOC_stylesheet = PREFIX + "stylesheet.ls";
470
471   /**
472    * Configuration property:  Add to the {@link #HTMLDOC_stylesheet} property.
473    */
474   public static final String HTMLDOC_stylesheet_add = PREFIX + "stylesheet.ls/add";
475
476   /**
477    * Configuration property:  HTML document template.
478    *
479    * <h5 class='section'>Property:</h5>
480    * <ul>
481    *    <li><b>Name:</b>  <js>"HtmlDocSerializer.template.c"</js>
482    *    <li><b>Data type:</b>  <code>Class&lt;? <jk>extends</jk> HtmlDocTemplate&gt;</code>
483    *    <li><b>Default:</b>  <code>HtmlDocTemplateBasic.<jk>class</jk></code>
484    *    <li><b>Session property:</b>  <jk>false</jk>
485    * </ul>
486    *
487    * <h5 class='section'>Description:</h5>
488    * <p>
489    * Specifies the template to use for serializing the page.
490    *
491    * <p>
492    * By default, the {@link BasicHtmlDocTemplate} class is used to construct the contents of the HTML page, but
493    * can be overridden with your own custom implementation class.
494    *
495    * <h5 class='section'>Example:</h5>
496    * <p class='bcode w800'>
497    *    <ja>@RestResource</ja>(
498    *       htmldoc=@HtmlDoc(
499    *          template=MySpecialDocTemplate.<jk>class</jk>
500    *       )
501    *    )
502    * </p>
503    */
504   public static final String HTMLDOC_template = PREFIX + "template.c";
505
506
507   //-------------------------------------------------------------------------------------------------------------------
508   // Predefined instances
509   //-------------------------------------------------------------------------------------------------------------------
510
511   /** Default serializer, all default settings. */
512   public static final HtmlDocSerializer DEFAULT = new HtmlDocSerializer(PropertyStore.DEFAULT);
513
514
515   //-------------------------------------------------------------------------------------------------------------------
516   // Instance
517   //-------------------------------------------------------------------------------------------------------------------
518
519   private final String[] style, stylesheet, script, navlinks, head, header, nav, aside, footer;
520   private final String noResultsMessage;
521   private final boolean nowrap;
522   private final HtmlDocTemplate template;
523
524   private volatile HtmlSchemaDocSerializer schemaSerializer;
525
526   /**
527    * Constructor.
528    *
529    * @param ps The property store containing all the settings for this object.
530    */
531   public HtmlDocSerializer(PropertyStore ps) {
532      this(ps, "text/html", (String)null);
533   }
534
535   /**
536    * Constructor.
537    *
538    * @param ps
539    *    The property store containing all the settings for this object.
540    * @param produces
541    *    The media type that this serializer produces.
542    * @param accept
543    *    The accept media types that the serializer can handle.
544    *    <p>
545    *    Can contain meta-characters per the <code>media-type</code> specification of
546    *    {@doc RFC2616.section14.1}
547    *    <p>
548    *    If empty, then assumes the only media type supported is <code>produces</code>.
549    *    <p>
550    *    For example, if this serializer produces <js>"application/json"</js> but should handle media types of
551    *    <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
552    *    <p class='bcode w800'>
553    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json",text/json"</js>);
554    *    </p>
555    *    <br>...or...
556    *    <p class='bcode w800'>
557    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
558    *    </p>
559    * <p>
560    * The accept value can also contain q-values.
561    */
562   public HtmlDocSerializer(PropertyStore ps, String produces, String accept) {
563      super(ps, produces, accept);
564      style = getArrayProperty(HTMLDOC_style, String.class);
565      stylesheet = getArrayProperty(HTMLDOC_stylesheet, String.class);
566      script = getArrayProperty(HTMLDOC_script, String.class);
567      head = getArrayProperty(HTMLDOC_head, String.class);
568      header = getArrayProperty(HTMLDOC_header, String.class);
569      nav = getArrayProperty(HTMLDOC_nav, String.class);
570      aside = getArrayProperty(HTMLDOC_aside, String.class);
571      footer = getArrayProperty(HTMLDOC_footer, String.class);
572      nowrap = getBooleanProperty(HTMLDOC_nowrap, false);
573      navlinks = getArrayProperty(HTMLDOC_navlinks, String.class);
574      noResultsMessage = getStringProperty(HTMLDOC_noResultsMessage, "<p>no results</p>");
575      template = getInstanceProperty(HTMLDOC_template, HtmlDocTemplate.class, BasicHtmlDocTemplate.class);
576   }
577
578   @Override /* Serializer */
579   public HtmlDocSerializerSession createSession(SerializerSessionArgs args) {
580      return new HtmlDocSerializerSession(this, args);
581   }
582
583   @Override /* XmlSerializer */
584   public HtmlSerializer getSchemaSerializer() {
585      if (schemaSerializer == null)
586         schemaSerializer = builder().build(HtmlSchemaDocSerializer.class);
587      return schemaSerializer;
588   }
589
590
591   //-----------------------------------------------------------------------------------------------------------------
592   // Properties
593   //-----------------------------------------------------------------------------------------------------------------
594
595   /**
596    * Configuration property:  CSS style code.
597    *
598    * @see #HTMLDOC_style
599    * @return
600    *    The CSS instructions to add to the HTML page.
601    */
602   protected final String[] getStyle() {
603      return style;
604   }
605
606   /**
607    * Configuration property:  Stylesheet import URLs.
608    *
609    * @see #HTMLDOC_stylesheet
610    * @return
611    *    The link to the stylesheet of the HTML page.
612    */
613   protected final String[] getStylesheet() {
614      return stylesheet;
615   }
616
617   /**
618    * Configuration property:  Javascript code.
619    *
620    * @see #HTMLDOC_script
621    * @return
622    *    Arbitrary Javascript to add to the HTML page.
623    */
624   protected final String[] getScript() {
625      return script;
626   }
627
628   /**
629    * Configuration property:  Page navigation links.
630    *
631    * @see #HTMLDOC_navlinks
632    * @return
633    *    Navigation links to add to the HTML page.
634    */
635   protected final String[] getNavlinks() {
636      return navlinks;
637   }
638
639   /**
640    * Configuration property:  Additional head section content.
641    *
642    * @see #HTMLDOC_head
643    * @return
644    *    HTML content to add to the head section of the HTML page.
645    */
646   protected final String[] getHead() {
647      return head;
648   }
649
650   /**
651    * Configuration property:  Header section contents.
652    *
653    * @see #HTMLDOC_header
654    * @return
655    *    The overridden contents of the header section on the HTML page.
656    */
657   protected final String[] getHeader() {
658      return header;
659   }
660
661   /**
662    * Configuration property:  Nav section contents.
663    *
664    * @see #HTMLDOC_nav
665    * @return
666    *    The overridden contents of the nav section on the HTML page.
667    */
668   protected final String[] getNav() {
669      return nav;
670   }
671
672   /**
673    * Configuration property:  Aside section contents.
674    *
675    * @see #HTMLDOC_aside
676    * @return
677    *    The overridden contents of the aside section on the HTML page.
678    */
679   protected final String[] getAside() {
680      return aside;
681   }
682
683   /**
684    * Configuration property:  Footer section contents.
685    *
686    * @see #HTMLDOC_footer
687    * @return
688    *    The overridden contents of the footer section on the HTML page.
689    */
690   protected final String[] getFooter() {
691      return footer;
692   }
693
694   /**
695    * Configuration property:  No-results message.
696    *
697    * @see #HTMLDOC_noResultsMessage
698    * @return
699    *    The message used when serializing an empty array or empty list.
700    */
701   protected final String getNoResultsMessage() {
702      return noResultsMessage;
703   }
704
705   /**
706    * Configuration property:  Prevent word wrap on page.
707    *
708    * @see #HTMLDOC_nowrap
709    * @return
710    *    <jk>true</jk> if <js>"* {white-space:nowrap}"</js> shoudl be added to the CSS instructions on the page to prevent word wrapping.
711    */
712   protected final boolean isNowrap() {
713      return nowrap;
714   }
715
716   /**
717    * Configuration property:  HTML document template.
718    *
719    * @see #HTMLDOC_template
720    * @return
721    *    The template to use for serializing the page.
722    */
723   protected final HtmlDocTemplate getTemplate() {
724      return template;
725   }
726
727   @Override /* Context */
728   public ObjectMap asMap() {
729      return super.asMap()
730         .append("HtmlDocSerializer", new ObjectMap()
731            .append("header", header)
732            .append("nav", nav)
733            .append("navlinks", navlinks)
734            .append("aside", aside)
735            .append("footer", footer)
736            .append("style", style)
737            .append("head", head)
738            .append("stylesheet", stylesheet)
739            .append("nowrap", nowrap)
740            .append("template", template)
741            .append("noResultsMessage", noResultsMessage)
742         );
743   }
744
745   /**
746    * @deprecated Use {@link #HtmlDocSerializer(PropertyStore, String, String)}
747    */
748   @SuppressWarnings("javadoc")
749   @Deprecated
750   public HtmlDocSerializer(PropertyStore ps, String produces, String...accept) {
751      this(ps, produces, StringUtils.join(accept, ","));
752   }
753
754}