org.apache.juneau.html.HtmlDocSerializer Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * 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.juneau.html;
import org.apache.juneau.*;
import org.apache.juneau.serializer.*;
/**
* Serializes POJOs to HTTP responses as HTML documents.
*
* Media types
*
* Handles Accept
types: text/html
*
* Produces Content-Type
types: text/html
*
*
Description
*
* Same as {@link HtmlSerializer}, except wraps the response in <html>
,
* <head>
, and <body>
tags so that it can be rendered in a browser.
*
*
* Configurable properties are typically specified via @RestResource(properties) and @RestMethod(properties)
* annotations, although they can also be set programmatically via the RestResponse.setProperty()
method.
*
*
Example:
*
* @RestResource (
* messages="nls/AddressBookResource" ,
* properties={
* @Property (name=HtmlDocSerializer.HTMLDOC_title , value="$L{title}" ),
* @Property (name=HtmlDocSerializer.HTMLDOC_description , value="$L{description}" ),
* @Property (name=HtmlDocSerializer.HTMLDOC_navlinks , value="{options:'?method=OPTIONS',doc:'doc'}" )
* }
* )
* public class AddressBookResource extends BasicRestServletJena {
*
*
*
* Note that shortcut annotations are also provided for these particular settings:
*
* @RestResource (
* messages="nls/AddressBookResource" ,
* title="$L{title}" ,
* description="$L{description}" ,
* htmldoc=@HtmlDoc (
* navlinks={
* "options: ?method=OPTIONS" ,
* "doc: doc"
* }
* )
* )
*
*
*
* The $L{...}
variable represent localized strings pulled from the resource bundle identified by the
* messages
annotation.
*
These variables are replaced at runtime based on the HTTP request locale.
*
Several built-in runtime variable types are defined, and the API can be extended to include user-defined variables.
*/
public class HtmlDocSerializer extends HtmlStrippedDocSerializer {
//-------------------------------------------------------------------------------------------------------------------
// Configurable properties
//-------------------------------------------------------------------------------------------------------------------
private static final String PREFIX = "HtmlDocSerializer.";
/**
* Configuration property: Aside section contents.
*
*
Property:
*
* - Name:
"HtmlDocSerializer.aside.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Allows you to specify the contents of the aside section on the HTML page.
* The aside section floats on the right of the page for providing content supporting the serialized content of
* the page.
*
*
* By default, the aside section is empty.
*
*
Example:
*
* @RestResource (
* htmldoc=@HtmlDoc (
* aside={
* "<ul>" ,
* " <li>Item 1" ,
* " <li>Item 2" ,
* " <li>Item 3" ,
* "</ul>"
* }
* )
* )
*
*/
public static final String HTMLDOC_aside = PREFIX + "aside.ls";
/**
* Configuration property: Footer section contents.
*
* Property:
*
* - Name:
"HtmlDocSerializer.footer.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Allows you to specify the contents of the footer section on the HTML page.
*
*
* By default, the footer section is empty.
*
*
Example:
*
* @RestResource (
* htmldoc=@HtmlDoc (
* footer={
* "<b>This interface is great!</b>"
* }
* )
* )
*
*/
public static final String HTMLDOC_footer = PREFIX + "footer.ls";
/**
* Configuration property: Additional head section content.
*
* Property:
*
* - Name:
"HtmlDocSerializer.head.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Adds the specified HTML content to the head section of the page.
*
*
Example:
*
* @RestResource (
* properties={
* @Property (name=HtmlDocSerializer.HTMLDOC_links ,
* value="['<link rel=\"icon\" href=\"htdocs/mypageicon.ico\">']" )
* }
* )
*
*
*
* A shortcut on @RestResource is also provided for this setting:
*
* @RestResource (
* htmldoc=@HtmlDoc(
* head={
* "<link rel='icon' href='$U{servlet:/htdocs/mypageicon.ico}'>"
* }
* )
* )
*
*/
public static final String HTMLDOC_head = PREFIX + "head.ls";
/**
* Configuration property: Header section contents.
*
* Property:
*
* - Name:
"HtmlDocSerializer.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Allows you to override the contents of the header section on the HTML page.
* The header section normally contains the title and description at the top of the page.
*
*
Example:
*
* @RestResource (
* htmldoc=@HtmlDoc (
* header={
* "<h1>My own header</h1>"
* }
* )
* )
*
*/
public static final String HTMLDOC_header = PREFIX + "header.ls";
/**
* Configuration property: Nav section contents.
*
* Property:
*
* - Name:
"HtmlDocSerializer.nav.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Allows you to override the contents of the nav section on the HTML page.
* The nav section normally contains the page links at the top of the page.
*
*
Example:
*
* @RestResource (
* htmldoc=@HtmlDoc (
* nav={
* "<p class='special-navigation'>This is my special navigation content</p>"
* }
* )
* )
*
*
*
* When this property is specified, the {@link #HTMLDOC_navlinks} property is ignored.
*/
public static final String HTMLDOC_nav = PREFIX + "nav.ls";
/**
* Configuration property: Page navigation links.
*
*
Property:
*
* - Name:
"HtmlDocSerializer.navlinks.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Adds a list of hyperlinks immediately under the title and description but above the content of the page.
*
*
* This can be used to provide convenient hyperlinks when viewing the REST interface from a browser.
*
*
* The value is an array of strings with two possible values:
*
* - A key-value pair representing a hyperlink label and href:
*
"google: http://google.com"
* - Arbitrary HTML.
*
*
*
* Relative URLs are considered relative to the servlet path.
* For example, if the servlet path is "http://localhost/myContext/myServlet" , and the
* URL is "foo" , the link becomes "http://localhost/myContext/myServlet/foo" .
* Absolute ("/myOtherContext/foo" ) and fully-qualified ("http://localhost2/foo" ) URLs
* can also be used in addition to various other protocols specified by {@link UriResolver} such as
* "servlet:/..." .
*
*
Example:
*
* The AddressBookResource
sample class uses this property...
*
* @RestResource (
* properties={
* @Property (name=HtmlDocSerializer.HTMLDOC_navlinks ,
* value="['options: ?method=OPTIONS', 'doc: doc']" )
* }
* )
* public class AddressBookResource extends BasicRestServletJena {
*
*
*
* A shortcut on @RestResource is also provided for this setting:
*
* @RestResource (
* htmldoc=@HtmlDoc(
* navlinks={
* "options: ?method=OPTIONS" ,
* "doc: doc"
* }
* )
* )
* public class AddressBookResource extends BasicRestServletJena {
*
*/
public static final String HTMLDOC_navlinks = PREFIX + "navlinks.ls";
/**
* Configuration property: Add to the {@link #HTMLDOC_navlinks} property.
*/
public static final String HTMLDOC_navlinks_add = PREFIX + "navlinks.ls/add";
/**
* Configuration property: No-results message.
*
* Property:
*
* - Name:
"HtmlDocSerializer.noResultsMessage.s"
* - Data type:
String
* - Default:
"<p>no results</p>"
* - Session property:
false
*
*
* Description:
*
* Allows you to specify the string message used when trying to serialize an empty array or empty list.
*
*
Example:
*
* @RestResource (
* htmldoc=@HtmlDoc (
* noResultsMessage="<b>This interface is great!</b>"
* )
* )
*
*
*
* A value of "NONE" can be used to represent no value to differentiate it from an empty string.
*/
public static final String HTMLDOC_noResultsMessage = PREFIX + "noResultsMessage.s";
/**
* Configuration property: Prevent word wrap on page.
*
*
Property:
*
* - Name:
"HtmlDocSerializer.nowrap.b"
* - Data type:
Boolean
* - Default:
false
* - Session property:
false
*
*
* Description:
*
* Adds "* {white-space:nowrap}" to the CSS instructions on the page to prevent word wrapping.
*/
public static final String HTMLDOC_nowrap = PREFIX + "nowrap.b";
/**
* Configuration property: Javascript code.
*
*
Property:
*
* - Name:
"HtmlDocSerializer.script.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Adds the specified Javascript code to the HTML page.
*
*
Example:
*
* @RestResource (
* properties={
* @Property (name=HtmlDocSerializer.HTMLDOC_script ,
* value="alert('hello!');" )
* }
* )
*
*
*
* A shortcut on @RestResource is also provided for this setting:
*
* @RestResource (
* htmldoc=@HtmlDoc(
* script={
* "alert('hello!');"
* }
* )
* )
*
*/
public static final String HTMLDOC_script = PREFIX + "script.ls";
/**
* Configuration property: Add to the {@link #HTMLDOC_script} property.
*/
public static final String HTMLDOC_script_add = PREFIX + "script.ls/add";
/**
* Configuration property: CSS style code.
*
* Property:
*
* - Name:
"HtmlDocSerializer.style.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Adds the specified CSS instructions to the HTML page.
*
*
Example:
*
* @RestResource (
* properties={
* @Property (name=HtmlDocSerializer.HTMLDOC_style ,
* value="h3 { color: red; }\nh5 { font-weight: bold; }" )
* }
* )
*
*
*
* A shortcut on @RestResource is also provided for this setting:
*
* @RestResource (
* htmldoc=@HtmlDoc(
* style={
* "h3 { color: red; }" ,
* "h5 { font-weight: bold; }"
* }
* )
* )
*
*/
public static final String HTMLDOC_style = PREFIX + "style.ls";
/**
* Configuration property: Add to the {@link #HTMLDOC_style} property.
*/
public static final String HTMLDOC_style_add = PREFIX + "style.ls/add";
/**
* Configuration property: Stylesheet import URLs.
*
* Property:
*
* - Name:
"HtmlDocSerializer.stylesheet.ls"
* - Data type:
List<String>
* - Default: empty list
*
- Session property:
true
*
*
* Description:
*
* Adds a link to the specified stylesheet URL.
*
*
* Note that this stylesheet is controlled by the @RestResource .stylesheet()
annotation.
*/
public static final String HTMLDOC_stylesheet = PREFIX + "stylesheet.ls";
/**
* Configuration property: Add to the {@link #HTMLDOC_stylesheet} property.
*/
public static final String HTMLDOC_stylesheet_add = PREFIX + "stylesheet.ls/add";
/**
* Configuration property: HTML document template.
*
*
Property:
*
* - Name:
"HtmlDocSerializer.template.c"
* - Data type:
Class<? extends HtmlDocTemplate>
* - Default:
HtmlDocTemplateBasic.class
* - Session property:
false
*
*
* Description:
*
* Specifies the template to use for serializing the page.
*
*
* By default, the {@link BasicHtmlDocTemplate} class is used to construct the contents of the HTML page, but
* can be overridden with your own custom implementation class.
*
*
Example:
*
* @RestResource (
* htmldoc=@HtmlDoc(
* template=MySpecialDocTemplate.class
* )
* )
*
*/
public static final String HTMLDOC_template = PREFIX + "template.c";
//-------------------------------------------------------------------------------------------------------------------
// Predefined instances
//-------------------------------------------------------------------------------------------------------------------
/** Default serializer, all default settings. */
public static final HtmlDocSerializer DEFAULT = new HtmlDocSerializer(PropertyStore.DEFAULT);
//-------------------------------------------------------------------------------------------------------------------
// Instance
//-------------------------------------------------------------------------------------------------------------------
private final String[] style, stylesheet, script, navlinks, head, header, nav, aside, footer;
private final String noResultsMessage;
private final boolean nowrap;
private final HtmlDocTemplate template;
private volatile HtmlSchemaDocSerializer schemaSerializer;
/**
* Constructor.
*
* @param ps The property store containing all the settings for this object.
*/
public HtmlDocSerializer(PropertyStore ps) {
this(ps, "text/html", null);
}
/**
* Constructor.
*
* @param ps
* The property store containing all the settings for this object.
* @param produces
* The media type that this serializer produces.
* @param accept
* The accept media types that the serializer can handle.
*
* Can contain meta-characters per the media-type
specification of
* {@doc RFC2616.section14.1}
*
* If empty, then assumes the only media type supported is produces
.
*
* For example, if this serializer produces "application/json" but should handle media types of
* "application/json" and "text/json" , then the arguments should be:
*
* super (ps, "application/json" , "application/json",text/json" );
*
*
...or...
*
* super (ps, "application/json" , "*/json" );
*
*
* The accept value can also contain q-values.
*/
public HtmlDocSerializer(PropertyStore ps, String produces, String accept) {
super(ps, produces, accept);
style = getArrayProperty(HTMLDOC_style, String.class);
stylesheet = getArrayProperty(HTMLDOC_stylesheet, String.class);
script = getArrayProperty(HTMLDOC_script, String.class);
head = getArrayProperty(HTMLDOC_head, String.class);
header = getArrayProperty(HTMLDOC_header, String.class);
nav = getArrayProperty(HTMLDOC_nav, String.class);
aside = getArrayProperty(HTMLDOC_aside, String.class);
footer = getArrayProperty(HTMLDOC_footer, String.class);
nowrap = getBooleanProperty(HTMLDOC_nowrap, false);
navlinks = getArrayProperty(HTMLDOC_navlinks, String.class);
noResultsMessage = getStringProperty(HTMLDOC_noResultsMessage, "
no results
");
template = getInstanceProperty(HTMLDOC_template, HtmlDocTemplate.class, BasicHtmlDocTemplate.class);
}
@Override /* Serializer */
public HtmlDocSerializerSession createSession(SerializerSessionArgs args) {
return new HtmlDocSerializerSession(this, args);
}
@Override /* XmlSerializer */
public HtmlSerializer getSchemaSerializer() {
if (schemaSerializer == null)
schemaSerializer = builder().build(HtmlSchemaDocSerializer.class);
return schemaSerializer;
}
//-----------------------------------------------------------------------------------------------------------------
// Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* Configuration property: CSS style code.
*
* @see #HTMLDOC_style
* @return
* The CSS instructions to add to the HTML page.
*/
protected final String[] getStyle() {
return style;
}
/**
* Configuration property: Stylesheet import URLs.
*
* @see #HTMLDOC_stylesheet
* @return
* The link to the stylesheet of the HTML page.
*/
protected final String[] getStylesheet() {
return stylesheet;
}
/**
* Configuration property: Javascript code.
*
* @see #HTMLDOC_script
* @return
* Arbitrary Javascript to add to the HTML page.
*/
protected final String[] getScript() {
return script;
}
/**
* Configuration property: Page navigation links.
*
* @see #HTMLDOC_navlinks
* @return
* Navigation links to add to the HTML page.
*/
protected final String[] getNavlinks() {
return navlinks;
}
/**
* Configuration property: Additional head section content.
*
* @see #HTMLDOC_head
* @return
* HTML content to add to the head section of the HTML page.
*/
protected final String[] getHead() {
return head;
}
/**
* Configuration property: Header section contents.
*
* @see #HTMLDOC_header
* @return
* The overridden contents of the header section on the HTML page.
*/
protected final String[] getHeader() {
return header;
}
/**
* Configuration property: Nav section contents.
*
* @see #HTMLDOC_nav
* @return
* The overridden contents of the nav section on the HTML page.
*/
protected final String[] getNav() {
return nav;
}
/**
* Configuration property: Aside section contents.
*
* @see #HTMLDOC_aside
* @return
* The overridden contents of the aside section on the HTML page.
*/
protected final String[] getAside() {
return aside;
}
/**
* Configuration property: Footer section contents.
*
* @see #HTMLDOC_footer
* @return
* The overridden contents of the footer section on the HTML page.
*/
protected final String[] getFooter() {
return footer;
}
/**
* Configuration property: No-results message.
*
* @see #HTMLDOC_noResultsMessage
* @return
* The message used when serializing an empty array or empty list.
*/
protected final String getNoResultsMessage() {
return noResultsMessage;
}
/**
* Configuration property: Prevent word wrap on page.
*
* @see #HTMLDOC_nowrap
* @return
* true if "* {white-space:nowrap}" shoudl be added to the CSS instructions on the page to prevent word wrapping.
*/
protected final boolean isNowrap() {
return nowrap;
}
/**
* Configuration property: HTML document template.
*
* @see #HTMLDOC_template
* @return
* The template to use for serializing the page.
*/
protected final HtmlDocTemplate getTemplate() {
return template;
}
@Override /* Context */
public ObjectMap asMap() {
return super.asMap()
.append("HtmlDocSerializer", new ObjectMap()
.append("header", header)
.append("nav", nav)
.append("navlinks", navlinks)
.append("aside", aside)
.append("footer", footer)
.append("style", style)
.append("head", head)
.append("stylesheet", stylesheet)
.append("nowrap", nowrap)
.append("template", template)
.append("noResultsMessage", noResultsMessage)
);
}
}