You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/06/07 00:27:46 UTC

[3/5] incubator-juneau git commit: Enhancements to HTML Doc rendering.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/CodeFormatterResource.html
----------------------------------------------------------------------
diff --git a/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/CodeFormatterResource.html b/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/CodeFormatterResource.html
deleted file mode 100644
index 90441cf..0000000
--- a/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/CodeFormatterResource.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE HTML>
-<!--
-/***************************************************************************************************************************
- * 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.
- *
- ***************************************************************************************************************************/
- -->
-<html>
-<head>
-	<style type='text/css'>
-		@import '$R{servletURI}/style.css';
-	</style>
-	<script>
-		// Quick and dirty function to allow tabs in textarea.
-		function checkTab(e) {
-		    if (e.keyCode == 9) {
-			    var t = e.target;
-			    var ss = t.selectionStart, se = t.selectionEnd;
-	            t.value = t.value.slice(0,ss).concat('\t').concat(t.value.slice(ss,t.value.length));
-		        e.preventDefault();
-		    }
-		}	
-		// Load results from IFrame into this document.
-		function loadResults(buff) {
-			var doc = buff.contentDocument || buff.contentWindow.document;
-			var buffBody = doc.getElementById('data');
-			if (buffBody != null) {
-				document.getElementById('results').innerHTML = buffBody.innerHTML;
-			}
-		}
-	</script>
-</head>
-<body>
-	<h3 class='title'>Code Formatter</h3>
-	<div class='data'>
-		<form id='form' action='codeFormatter' method='POST' target='buff'>
-			<table>
-				<tr>
-					<th>Language: </th>
-					<td>
-						<select name='lang'>
-							<option value='java'>Java</option>
-							<option value='xml'>XML</option>
-						</select>
-					</td>
-					<td><button type='submit'>Submit</button><button type='reset'>Reset</button></td>
-				</tr>		
-				<tr>
-					<td colspan='3'><textarea name='code' style='min-width:800px;min-height:400px;font-family:Courier;font-size:9pt;' onkeydown='checkTab(event)'></textarea></td>
-				</tr>
-			</table>
-		</form>
-		<div id='results' class='monospace'>
-		</div>
-	</div>
-	<iframe name='buff' style='display:none' onload="parent.loadResults(this)"></iframe>
-</body>
-</html>
-

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
----------------------------------------------------------------------
diff --git a/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java b/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
index 80a4aa9..81307c1 100644
--- a/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
+++ b/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
@@ -41,13 +41,13 @@ public class RootResourcesTest extends RestTestcase {
 		ResourceDescription[] x = r.getResponse(ResourceDescription[].class);
 		assertEquals("helloWorld", x[0].getName().getName());
 		assertEquals(path + "/helloWorld", x[0].getName().getHref());
-		assertEquals("Hello World sample resource", x[0].getDescription());
+		assertEquals("Hello World", x[0].getDescription());
 
 		r = jsonClient.doOptions("");
 		ObjectMap x2 = r.getResponse(ObjectMap.class);
 		String s = x2.getObjectMap("info").getString("description");
 		if (debug) System.err.println(s);
-		assertTrue(s, s.startsWith("This is an example"));
+		assertTrue(s, s.startsWith("Example of a router resource page"));
 	}
 
 	//====================================================================================================
@@ -60,13 +60,13 @@ public class RootResourcesTest extends RestTestcase {
 		ResourceDescription[] x = r.getResponse(ResourceDescription[].class);
 		assertEquals("helloWorld", x[0].getName().getName());
 		assertEquals(path + "/helloWorld", x[0].getName().getHref());
-		assertEquals("Hello World sample resource", x[0].getDescription());
+		assertEquals("Hello World", x[0].getDescription());
 
 		r = jsonClient.doOptions("");
 		ObjectMap x2 = r.getResponse(ObjectMap.class);
 		String s = x2.getObjectMap("info").getString("description");
 		if (debug) System.err.println(s);
-		assertTrue(s, s.startsWith("This is an example"));
+		assertTrue(s, s.startsWith("Example of a router resource page"));
 		
 		client.closeQuietly();
 	}
@@ -81,13 +81,13 @@ public class RootResourcesTest extends RestTestcase {
 		ResourceDescription[] x = r.getResponse(ResourceDescription[].class);
 		assertEquals("helloWorld", x[0].getName().getName());
 		assertTrue(x[0].getName().getHref().endsWith("/helloWorld"));
-		assertEquals("Hello World sample resource", x[0].getDescription());
+		assertEquals("Hello World", x[0].getDescription());
 
 		r = jsonClient.doOptions("").accept("text/json");
 		ObjectMap x2 = r.getResponse(ObjectMap.class);
 		String s = x2.getObjectMap("info").getString("description");
 		if (debug) System.err.println(s);
-		assertTrue(s, s.startsWith("This is an example"));
+		assertTrue(s, s.startsWith("Example of a router resource page"));
 		
 		client.closeQuietly();
 	}
@@ -127,6 +127,6 @@ public class RootResourcesTest extends RestTestcase {
 		RestCall r = jsonClient.doOptions("");
 		Swagger o = r.getResponse(Swagger.class);
 		if (debug) System.err.println(o);
-		assertEquals("This is an example of a router resource that is used to access other resources.", o.getInfo().getDescription());
+		assertEquals("Example of a router resource page.", o.getInfo().getDescription());
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-microservice/src/main/java/org/apache/juneau/microservice/Resource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/src/main/java/org/apache/juneau/microservice/Resource.java b/juneau-microservice/src/main/java/org/apache/juneau/microservice/Resource.java
index 0e32ebe..eaeb701 100755
--- a/juneau-microservice/src/main/java/org/apache/juneau/microservice/Resource.java
+++ b/juneau-microservice/src/main/java/org/apache/juneau/microservice/Resource.java
@@ -37,7 +37,9 @@ import org.apache.juneau.svl.vars.*;
  */
 @SuppressWarnings("serial")
 @RestResource(
-	pageLinks="{up:'request:/..',options:'servlet:/?method=OPTIONS'}",
+	htmldoc=@HtmlDoc(
+		links="{up:'request:/..',options:'servlet:/?method=OPTIONS'}"
+	),
 	config="$S{juneau.configFile}",
 	stylesheet="$C{REST/stylesheet,styles/juneau.css}"
 )

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceGroup.java b/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
index 8c66669..e48ccb5 100755
--- a/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
+++ b/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
@@ -38,7 +38,9 @@ import org.apache.juneau.svl.vars.*;
  */
 @SuppressWarnings("serial")
 @RestResource(
-	pageLinks="{up:'request:/..',options:'servlet:/?method=OPTIONS'}",
+	htmldoc=@HtmlDoc(
+		links="{up:'request:/..',options:'servlet:/?method=OPTIONS'}"
+	),
 	config="$S{juneau.configFile}",
 	stylesheet="$C{REST/stylesheet,styles/juneau.css}"
 )

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceJena.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceJena.java b/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceJena.java
index 4d971c9..efe3cd5 100755
--- a/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceJena.java
+++ b/juneau-microservice/src/main/java/org/apache/juneau/microservice/ResourceJena.java
@@ -20,7 +20,9 @@ import org.apache.juneau.rest.jena.*;
  */
 @SuppressWarnings("serial")
 @RestResource(
-	pageLinks="{up:'request:/..',options:'servlet:/?method=OPTIONS'}",
+	htmldoc=@HtmlDoc(
+		links="{up:'request:/..',options:'servlet:/?method=OPTIONS'}"
+	),
 	config="$S{juneau.configFile}",
 	stylesheet="$C{REST/stylesheet,styles/juneau.css}"
 )

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java b/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
index 2b2c99c..b8d542a 100755
--- a/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
+++ b/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
@@ -33,7 +33,9 @@ import org.apache.juneau.rest.annotation.Body;
 	path="/config",
 	title="Configuration",
 	description="Contents of configuration file.",
-	pageLinks="{up:'request:/..',options:'servlet:/?method=OPTIONS',edit:'servlet:/edit'}"
+	htmldoc=@HtmlDoc(
+		links="{up:'request:/..',options:'servlet:/?method=OPTIONS',edit:'servlet:/edit'}"
+	)
 )
 public class ConfigResource extends Resource {
 	private static final long serialVersionUID = 1L;
@@ -81,9 +83,11 @@ public class ConfigResource extends Resource {
 	 */
 	@RestMethod(name="GET", path="/{section}",
 		description="Show config file section.",
-		parameters={
-			@Parameter(in="path", name="section", description="Section name.")
-		}
+		swagger=@MethodSwagger(
+			parameters={
+				@Parameter(in="path", name="section", description="Section name.")
+			}
+		)
 	)
 	public ObjectMap getConfigSection(@Path("section") String section) throws Exception {
 		return getSection(section);
@@ -99,10 +103,12 @@ public class ConfigResource extends Resource {
 	 */
 	@RestMethod(name="GET", path="/{section}/{key}",
 		description="Show config file entry.",
-		parameters={
-			@Parameter(in="path", name="section", description="Section name."),
-			@Parameter(in="path", name="key", description="Entry name.")
-		}
+		swagger=@MethodSwagger(
+			parameters={
+				@Parameter(in="path", name="section", description="Section name."),
+				@Parameter(in="path", name="key", description="Entry name.")
+			}
+		)
 	)
 	public String getConfigEntry(@Path("section") String section, @Path("key") String key) throws Exception {
 		return getSection(section).getString(key);
@@ -117,9 +123,11 @@ public class ConfigResource extends Resource {
 	 */
 	@RestMethod(name="POST", path="/",
 		description="Sets contents of config file from a FORM post.",
-		parameters={
-			@Parameter(in="formData", name="contents", description="New contents in INI file format.")
-		}
+		swagger=@MethodSwagger(
+			parameters={
+				@Parameter(in="formData", name="contents", description="New contents in INI file format.")
+			}
+		)
 	)
 	public ConfigFile setConfigContentsFormPost(@FormData("contents") String contents) throws Exception {
 		return setConfigContents(new StringReader(contents));
@@ -134,9 +142,11 @@ public class ConfigResource extends Resource {
 	 */
 	@RestMethod(name="PUT", path="/",
 		description="Sets contents of config file.",
-		parameters={
-			@Parameter(in="body", description="New contents in INI file format.")
-		}
+		swagger=@MethodSwagger(
+			parameters={
+				@Parameter(in="body", description="New contents in INI file format.")
+			}
+		)
 	)
 	public ConfigFile setConfigContents(@Body Reader contents) throws Exception {
 		ConfigFile cf2 = new ConfigFileBuilder().build(contents);
@@ -153,10 +163,12 @@ public class ConfigResource extends Resource {
 	 */
 	@RestMethod(name="PUT", path="/{section}",
 		description="Add or overwrite a config file section.",
-		parameters={
-			@Parameter(in="path", name="section", description="Section name."),
-			@Parameter(in="body", description="New contents for section as a simple map with string keys and values.")
-		}
+		swagger=@MethodSwagger(
+			parameters={
+				@Parameter(in="path", name="section", description="Section name."),
+				@Parameter(in="body", description="New contents for section as a simple map with string keys and values.")
+			}
+		)
 	)
 	public ObjectMap setConfigSection(@Path("section") String section, @Body Map<String,String> contents) throws Exception {
 		getConfigContents().setSection(section, contents);
@@ -174,11 +186,13 @@ public class ConfigResource extends Resource {
 	 */
 	@RestMethod(name="PUT", path="/{section}/{key}",
 		description="Add or overwrite a config file entry.",
-		parameters={
-			@Parameter(in="path", name="section", description="Section name."),
-			@Parameter(in="path", name="key", description="Entry name."),
-			@Parameter(in="body", description="New value as a string.")
-		}
+		swagger=@MethodSwagger(
+			parameters={
+				@Parameter(in="path", name="section", description="Section name."),
+				@Parameter(in="path", name="key", description="Entry name."),
+				@Parameter(in="body", description="New value as a string.")
+			}
+		)
 	)
 	public String setConfigSection(@Path("section") String section, @Path("key") String key, @Body String value) throws Exception {
 		getConfigContents().put(section, key, value, false);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java b/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
index 8f67665..060a7e6 100755
--- a/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
+++ b/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
@@ -57,7 +57,9 @@ import org.apache.juneau.utils.*;
 	title="File System Explorer",
 	description="Contents of $R{attribute.path}",
 	messages="nls/DirectoryResource",
-	pageLinks="{up:'request:/..',options:'servlet:/?method=OPTIONS'}",
+	htmldoc=@HtmlDoc(
+		links="{up:'request:/..',options:'servlet:/?method=OPTIONS'}"
+	),
 	properties={
 		@Property(name=HTML_uriAnchorText, value=PROPERTY_NAME),
 		@Property(name=REST_allowMethodParam, value="*"),

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java b/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
index 865c35c..52d4783 100755
--- a/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
+++ b/juneau-microservice/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
@@ -87,7 +87,13 @@ public class LogsResource extends Resource {
 	 * @return The log file.
 	 * @throws Exception
 	 */
-	@RestMethod(name="GET", path="/*", responses={@Response(200),@Response(404)})
+	@RestMethod(
+		name="GET", 
+		path="/*", 
+		swagger=@MethodSwagger(
+			responses={@Response(200),@Response(404)}
+		)
+	)	
 	public Object getFileOrDirectory(RestRequest req, RestResponse res, @Properties ObjectMap properties, @PathRemainder String path) throws Exception {
 
 		File f = getFile(path);
@@ -101,12 +107,12 @@ public class LogsResource extends Resource {
 					l.add(new FileResource(fc, fUrl));
 				}
 			}
-			res.setPageText(new StringMessage("Contents of {0}", f.getAbsolutePath()));
-			properties.put(HTMLDOC_text, "Contents of " + f.getAbsolutePath());
+			res.setHtmlDescription(new StringMessage("Contents of {0}", f.getAbsolutePath()));
+			properties.put(HTMLDOC_description, "Contents of " + f.getAbsolutePath());
 			return l;
 		}
 
-		res.setPageText(new StringMessage("File details on {0}", f.getAbsolutePath()));
+		res.setHtmlDescription(new StringMessage("File details on {0}", f.getAbsolutePath()));
 		return new FileResource(f, new URL(req.getTrimmedRequestURL().toString()));
 	}
 
@@ -125,7 +131,13 @@ public class LogsResource extends Resource {
 	 * @param severity Optional severity filter.  Only show log entries with the specified severity.  Example: "&amp;severity=(ERROR,WARN)".
 	 * @throws Exception
 	 */
-	@RestMethod(name="VIEW", path="/*", responses={@Response(200),@Response(404)})
+	@RestMethod(
+		name="VIEW", 
+		path="/*",
+		swagger=@MethodSwagger(
+			responses={@Response(200),@Response(404)}
+		)
+	)
 	@SuppressWarnings("nls")
 	public void viewFile(RestRequest req, RestResponse res, @PathRemainder String path, @Properties ObjectMap properties, @Query("highlight") boolean highlight, @Query("start") String start, @Query("end") String end, @Query("thread") String thread, @Query("loggers") String[] loggers, @Query("severity") String[] severity) throws Exception {
 
@@ -198,7 +210,14 @@ public class LogsResource extends Resource {
 	 * @return The parsed contents of the log file.
 	 * @throws Exception
 	 */
-	@RestMethod(name="PARSE", path="/*", converters=Queryable.class, responses={@Response(200),@Response(404)})
+	@RestMethod(
+		name="PARSE", 
+		path="/*", 
+		converters=Queryable.class, 
+		swagger=@MethodSwagger(
+			responses={@Response(200),@Response(404)}
+		)
+	)
 	public LogParser viewParsedEntries(RestRequest req, @PathRemainder String path, @Query("start") String start, @Query("end") String end, @Query("thread") String thread, @Query("loggers") String[] loggers, @Query("severity") String[] severity) throws Exception {
 
 		File f = getFile(path);
@@ -218,7 +237,13 @@ public class LogsResource extends Resource {
 	 * @return The contents of the log file.
 	 * @throws Exception
 	 */
-	@RestMethod(name="DOWNLOAD", path="/*", responses={@Response(200),@Response(404)})
+	@RestMethod(
+		name="DOWNLOAD", 
+		path="/*", 
+		swagger=@MethodSwagger(
+			responses={@Response(200),@Response(404)}
+		)
+	)
 	public Object downloadFile(RestResponse res, @PathRemainder String path) throws Exception {
 
 		File f = getFile(path);
@@ -238,7 +263,13 @@ public class LogsResource extends Resource {
 	 * @return A redirect object to the root.
 	 * @throws Exception
 	 */
-	@RestMethod(name="DELETE", path="/*", responses={@Response(200),@Response(404)})
+	@RestMethod(
+		name="DELETE", 
+		path="/*",
+		swagger=@MethodSwagger(
+			responses={@Response(200),@Response(404)}
+		)
+	)
 	public Object deleteFile(@PathRemainder String path) throws Exception {
 
 		File f = getFile(path);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index 90f2cf8..7f70117 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -1944,12 +1944,11 @@ public final class RestCall {
 	/**
 	 * Sets <code>Debug: value</code> header on this request.
 	 *
-	 * @param value The debug value.
 	 * @return This object (for method chaining).
 	 * @throws RestCallException
 	 */
-	public RestCall debug(boolean value) throws RestCallException {
-		header("Debug", value);
+	public RestCall debug() throws RestCallException {
+		header("Debug", true);
 		return this;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 5dc2ac6..23b31bf 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -1481,10 +1481,10 @@ public class RestClientBuilder extends CoreObjectBuilder {
 	}
 
 	@Override /* CoreObjectBuilder */
-	public RestClientBuilder debug(boolean value) {
-		super.debug(value);
-		this.debug = value;
-		header("Debug", value);
+	public RestClientBuilder debug() {
+		super.debug();
+		this.debug = true;
+		header("Debug", true);
 		return this;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/package.html
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/package.html b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/package.html
index 0f685ef..0696559 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/package.html
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/package.html
@@ -632,7 +632,7 @@
 	<h3 class='topic' onclick='toggle(this)'>1.5 - Debugging</h3>
 	<div class='topic'>
 		<p>
-			Use the {@link org.apache.juneau.rest.client.RestClientBuilder#debug(boolean)} method to enable logging for HTTP requests
+			Use the {@link org.apache.juneau.rest.client.RestClientBuilder#debug()} method to enable logging for HTTP requests
 			made from the client.
 		</p>
 		<p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HtmlPropertiesResource.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HtmlPropertiesResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HtmlPropertiesResource.java
index 648008c..e75ea5a 100644
--- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HtmlPropertiesResource.java
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HtmlPropertiesResource.java
@@ -39,9 +39,11 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 
 	@RestResource(
 		path="/Normal",
-		pageTitle="Normal-title",
-		pageText="Normal-text",
-		pageLinks="{link:'Normal-links'}"
+		htmldoc=@HtmlDoc(
+			title="Normal-title",
+			description="Normal-text",
+			links="{link:'Normal-links'}"
+		)
 	)
 	public static class Normal extends RestServletDefault {
 
@@ -56,7 +58,14 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		//----------------------------------------------------------------------------------------------------
 		// Values pulled from @RestResource(pageX), overridden by @RestMethod(pageX) annotations.
 		//----------------------------------------------------------------------------------------------------
-		@RestMethod(path="/test2", pageTitle="Normal.test2-title", pageText="Normal.test2-text", pageLinks="{link:'Normal.test2-links'}")
+		@RestMethod(
+			path="/test2",
+			htmldoc=@HtmlDoc(
+				title="Normal.test2-title",
+				description="Normal.test2-text",
+				links="{link:'Normal.test2-links'}"
+			)
+		)
 		public String test2() {
 			return "OK";
 		}
@@ -66,9 +75,9 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		//----------------------------------------------------------------------------------------------------
 		@RestMethod(path="/test3")
 		public String test3(RestResponse res) {
-			res.setPageTitle("Normal.test3-title");
-			res.setPageText("Normal.test3-text");
-			res.setPageLinks("{link:'Normal.test3-links'}");
+			res.setHtmlTitle("Normal.test3-title");
+			res.setHtmlDescription("Normal.test3-text");
+			res.setHtmlLinks("{link:'Normal.test3-links'}");
 			return "OK";
 		}
 
@@ -78,7 +87,7 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		@RestMethod(path="/test4")
 		public String test4(RestResponse res) {
 			res.setProperty(HtmlDocSerializerContext.HTMLDOC_title, "Normal.test4-title");
-			res.setProperty(HtmlDocSerializerContext.HTMLDOC_text, "Normal.test4-text");
+			res.setProperty(HtmlDocSerializerContext.HTMLDOC_description, "Normal.test4-text");
 			res.setProperty(HtmlDocSerializerContext.HTMLDOC_links, "{link:'Normal.test4-links'}");
 			return "OK";
 		}
@@ -91,9 +100,9 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 
 		@Override
 		public void init(RestConfig config) throws Exception {
-			config.setPageTitle("NormalInit-title");
-			config.setPageText("NormalInit-text");
-			config.setPageLinks("{link:'NormalInit-links'}");
+			config.setHtmlTitle("NormalInit-title");
+			config.setHtmlDescription("NormalInit-text");
+			config.setHtmlLinks("{link:'NormalInit-links'}");
 			super.init(config);
 		}
 
@@ -108,7 +117,14 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		//----------------------------------------------------------------------------------------------------
 		// Values pulled from RestConfig.setX() methods, overridden by @RestMethod(pageX) annotations.
 		//----------------------------------------------------------------------------------------------------
-		@RestMethod(path="/test2", pageTitle="NormalInit.test2-title", pageText="NormalInit.test2-text", pageLinks="{link:'NormalInit.test2-links'}")
+		@RestMethod(
+			path="/test2",
+			htmldoc=@HtmlDoc(
+				title="NormalInit.test2-title",
+				description="NormalInit.test2-text",
+				links="{link:'NormalInit.test2-links'}"
+			)
+		)
 		public String test2() {
 			return "OK";
 		}
@@ -118,9 +134,9 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		//----------------------------------------------------------------------------------------------------
 		@RestMethod(path="/test3")
 		public String test3(RestResponse res) {
-			res.setPageTitle("NormalInit.test3-title");
-			res.setPageText("NormalInit.test3-text");
-			res.setPageLinks("{link:'NormalInit.test3-links'}");
+			res.setHtmlTitle("NormalInit.test3-title");
+			res.setHtmlDescription("NormalInit.test3-text");
+			res.setHtmlLinks("{link:'NormalInit.test3-links'}");
 			return "OK";
 		}
 
@@ -130,7 +146,7 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		@RestMethod(path="/test4")
 		public String test4(RestResponse res) {
 			res.setProperty(HtmlDocSerializerContext.HTMLDOC_title, "NormalInit.test4-title");
-			res.setProperty(HtmlDocSerializerContext.HTMLDOC_text, "NormalInit.test4-text");
+			res.setProperty(HtmlDocSerializerContext.HTMLDOC_description, "NormalInit.test4-text");
 			res.setProperty(HtmlDocSerializerContext.HTMLDOC_links, "{link:'NormalInit.test4-links'}");
 			return "OK";
 		}
@@ -164,8 +180,8 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		//----------------------------------------------------------------------------------------------------
 		@RestMethod(path="/test3")
 		public String test3(RestResponse res) {
-			res.setPageTitle("NormalDefaulting.test3-title");
-			res.setPageText("NormalDefaulting.test3-text");
+			res.setHtmlTitle("NormalDefaulting.test3-title");
+			res.setHtmlDescription("NormalDefaulting.test3-text");
 			return "OK";
 		}
 
@@ -175,7 +191,7 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		@RestMethod(path="/test4")
 		public String test4(RestResponse res) {
 			res.setProperty(HtmlDocSerializerContext.HTMLDOC_title, "NormalDefaulting.test4-title");
-			res.setProperty(HtmlDocSerializerContext.HTMLDOC_text, "NormalDefaulting.test4-text");
+			res.setProperty(HtmlDocSerializerContext.HTMLDOC_description, "NormalDefaulting.test4-text");
 			return "OK";
 		}
 	}
@@ -199,7 +215,14 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		// Values pulled from parent @RestResource(path/title), overridden by @RestMethod(pageX) annotations.
 		//----------------------------------------------------------------------------------------------------
 		@Override
-		@RestMethod(path="/test2", pageTitle="NormalSubclassed1.test2-title", pageText="NormalSubclassed1.test2-text", pageLinks="{link:'NormalSubclassed1.test2-links'}")
+		@RestMethod(
+			path="/test2",
+			htmldoc=@HtmlDoc(
+				title="NormalSubclassed1.test2-title",
+				description="NormalSubclassed1.test2-text",
+				links="{link:'NormalSubclassed1.test2-links'}"
+			)
+		)
 		public String test2() {
 			return "OK";
 		}
@@ -207,9 +230,11 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 
 	@RestResource(
 		path="/NormalSubclassed2",
-		pageTitle="NormalSubclassed2-title",
-		pageText="NormalSubclassed2-text",
-		pageLinks="{link:'NormalSubclassed2-links'}"
+		htmldoc=@HtmlDoc(
+			title="NormalSubclassed2-title",
+			description="NormalSubclassed2-text",
+			links="{link:'NormalSubclassed2-links'}"
+		)
 	)
 	public static class NormalSubclassed2 extends Normal {
 
@@ -226,7 +251,14 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		// Values pulled from parent @RestResource(path/title), overridden by @RestMethod(pageX).
 		//----------------------------------------------------------------------------------------------------
 		@Override
-		@RestMethod(path="/test2", pageTitle="NormalSubclassed2.test2-title", pageText="NormalSubclassed2.test2-text", pageLinks="{link:'NormalSubclassed2.test2-links'}")
+		@RestMethod(
+			path="/test2",
+			htmldoc=@HtmlDoc(
+				title="NormalSubclassed2.test2-title",
+				description="NormalSubclassed2.test2-text",
+				links="{link:'NormalSubclassed2.test2-links'}"
+			)
+		)
 		public String test2() {
 			return "OK";
 		}
@@ -235,9 +267,11 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 	@RestResource(
 		path="/LocalizedExplicit",
 		messages="HtmlPropertiesResource",
-		pageTitle="$L{pageTitle}",
-		pageText="$L{pageText}",
-		pageLinks="$L{pageLinks}"
+		htmldoc=@HtmlDoc(
+			title="$L{pageTitle}",
+			description="$L{pageText}",
+			links="$L{pageLinks}"
+		)
 	)
 	public static class LocalizedExplicit extends RestServletDefault {
 
@@ -252,7 +286,12 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		//----------------------------------------------------------------------------------------------------
 		// Values pulled from @RestResource(pageX) with $L variables, overridden by @RestMethod(pageX) with $L variables.
 		//----------------------------------------------------------------------------------------------------
-		@RestMethod(path="/test2", pageTitle="$L{test2.pageTitle}", pageText="$L{test2.pageText}", pageLinks="$L{test2.pageLinks}")
+		@RestMethod(
+			path="/test2",
+			htmldoc=@HtmlDoc(
+				title="$L{test2.pageTitle}", description="$L{test2.pageText}", links="$L{test2.pageLinks}"
+			)
+		)
 		public String test2() {
 			return "OK";
 		}
@@ -262,9 +301,9 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		//----------------------------------------------------------------------------------------------------
 		@RestMethod(path="/test3")
 		public String test3(RestResponse res) {
-			res.setPageTitle("$L{test3.pageTitle}");
-			res.setPageText("$L{test3.pageText}");
-			res.setPageLinks("$L{test3.pageLinks}");
+			res.setHtmlTitle("$L{test3.pageTitle}");
+			res.setHtmlDescription("$L{test3.pageText}");
+			res.setHtmlLinks("$L{test3.pageLinks}");
 			return "OK";
 		}
 
@@ -274,7 +313,7 @@ public class HtmlPropertiesResource extends RestServletGroupDefault {
 		@RestMethod(path="/test4")
 		public String test4(RestResponse res) {
 			res.setProperty(HtmlDocSerializerContext.HTMLDOC_title, "$L{test4.pageTitle}");
-			res.setProperty(HtmlDocSerializerContext.HTMLDOC_text, "$L{test4.pageText}");
+			res.setProperty(HtmlDocSerializerContext.HTMLDOC_description, "$L{test4.pageText}");
 			res.setProperty(HtmlDocSerializerContext.HTMLDOC_links, "$L{test4.pageLinks}");
 			return "OK";
 		}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsResource.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsResource.java
index d9ce1e7..0048e8e 100644
--- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsResource.java
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsResource.java
@@ -48,24 +48,26 @@ public class NlsResource extends RestServletGroupDefault {
 		@RestMethod(
 			name="POST", path="/{a}",
 			description="Test1.c",
-			parameters={
-				@Parameter(in="path", name="a", description="Test1.d"),
-				@Parameter(in="query", name="b", description="Test1.e"),
-				@Parameter(in="body", description="Test1.f"),
-				@Parameter(in="header", name="D", description="Test1.g"),
-				@Parameter(in="path", name="a2", description="Test1.h"),
-				@Parameter(in="query", name="b2", description="Test1.i"),
-				@Parameter(in="header", name="D2", description="Test1.j"),
-			},
-			responses={
-				@Response(200),
-				@Response(value=201,
-					description="Test1.l",
-					headers={
-						@Parameter(in="foo", name="bar", description="Test1.m"),
-					}
-				)
-			}
+			swagger=@MethodSwagger(
+				parameters={
+					@Parameter(in="path", name="a", description="Test1.d"),
+					@Parameter(in="query", name="b", description="Test1.e"),
+					@Parameter(in="body", description="Test1.f"),
+					@Parameter(in="header", name="D", description="Test1.g"),
+					@Parameter(in="path", name="a2", description="Test1.h"),
+					@Parameter(in="query", name="b2", description="Test1.i"),
+					@Parameter(in="header", name="D2", description="Test1.j"),
+				},
+				responses={
+					@Response(200),
+					@Response(value=201,
+						description="Test1.l",
+						headers={
+							@Parameter(in="foo", name="bar", description="Test1.m"),
+						}
+					)
+				}
+			)
 		)
 		public String test1(@Path("a") String a, @Query("b") String b, @Body String c, @Header("D") String d,
 				@Path("e") String e, @Query("f") String f, @Header("g") String g) {
@@ -166,24 +168,26 @@ public class NlsResource extends RestServletGroupDefault {
 		@RestMethod(
 			name="POST", path="/{a}",
 			description="$L{foo}",
-			parameters={
-				@Parameter(in="path", name="a", description="$L{foo}"),
-				@Parameter(in="query", name="b", description="$L{foo}"),
-				@Parameter(in="body", description="$L{foo}"),
-				@Parameter(in="header", name="D", description="$L{foo}"),
-				@Parameter(in="path", name="a2", description="$L{foo}"),
-				@Parameter(in="query", name="b2", description="$L{foo}"),
-				@Parameter(in="header", name="D2", description="$L{foo}")
-			},
-			responses={
-				@Response(200),
-				@Response(value=201,
-					description="$L{foo}",
-					headers={
-						@Parameter(in="foo", name="bar", description="$L{foo}"),
-					}
-				)
-			}
+			swagger=@MethodSwagger(
+				parameters={
+					@Parameter(in="path", name="a", description="$L{foo}"),
+					@Parameter(in="query", name="b", description="$L{foo}"),
+					@Parameter(in="body", description="$L{foo}"),
+					@Parameter(in="header", name="D", description="$L{foo}"),
+					@Parameter(in="path", name="a2", description="$L{foo}"),
+					@Parameter(in="query", name="b2", description="$L{foo}"),
+					@Parameter(in="header", name="D2", description="$L{foo}")
+				},
+				responses={
+					@Response(200),
+					@Response(value=201,
+						description="$L{foo}",
+						headers={
+							@Parameter(in="foo", name="bar", description="$L{foo}"),
+						}
+					)
+				}
+			)
 		)
 		public String test6(@Path("a") String a, @Query("b") String b, @Body String c, @Header("D") String d,
 				@Path("e") String e, @Query("f") String f, @Header("g") String g) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
index c3e3cf0..acf2b8c 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
@@ -258,28 +258,4 @@ public class HtmlPropertiesTest extends RestTestcase {
 		assertTrue(s.contains("LocalizedExplicit.test4.nls.pageText"));
 		assertTrue(s.contains("LocalizedExplicit.test4.nls.pageLinks"));
 	}
-
-	//----------------------------------------------------------------------------------------------------
-	// Values pulled from resource bundle.
-	//----------------------------------------------------------------------------------------------------
-	@Test
-	public void testLocalizedImplicitTest1() throws Exception {
-		RestClient client = TestMicroservice.DEFAULT_CLIENT;
-		String s = client.doGet("/testHtmlProperties/LocalizedImplicit/test1").accept("text/html").getResponseAsString();
-		assertTrue(s.contains("LocalizedImplicit.nls.pageTitle"));
-		assertTrue(s.contains("LocalizedImplicit.nls.pageText"));
-		assertTrue(s.contains("LocalizedImplicit.nls.pageLinks"));
-	}
-
-	//----------------------------------------------------------------------------------------------------
-	// Values pulled from resource bundle, overridden by values in resource bundle at method level.
-	//----------------------------------------------------------------------------------------------------
-	@Test
-	public void testLocalizedImplicitTest2() throws Exception {
-		RestClient client = TestMicroservice.DEFAULT_CLIENT;
-		String s = client.doGet("/testHtmlProperties/LocalizedImplicit/test2").accept("text/html").getResponseAsString();
-		assertTrue(s.contains("LocalizedImplicit.test2.nls.pageTitle"));
-		assertTrue(s.contains("LocalizedImplicit.test2.nls.pageText"));
-		assertTrue(s.contains("LocalizedImplicit.test2.nls.pageLinks"));
-	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
index 521c965..983180e 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
@@ -55,7 +55,7 @@ public class RestTestcase {
 	 */
 	protected RestClient getDebugClient(String label, Serializer serializer, Parser parser) {
 		if (! clients.containsKey(label))
-			clients.put(label, TestMicroservice.client(serializer, parser).debug(true).build());
+			clients.put(label, TestMicroservice.client(serializer, parser).debug().build());
 		return clients.get(label);
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java b/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
index efb827c..69d6814 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
@@ -14,6 +14,7 @@ package org.apache.juneau.rest;
 
 import static javax.servlet.http.HttpServletResponse.*;
 import static org.apache.juneau.dto.swagger.SwaggerBuilder.*;
+import static org.apache.juneau.html.HtmlDocSerializerContext.*;
 import static org.apache.juneau.internal.ClassUtils.*;
 import static org.apache.juneau.internal.Utils.*;
 import static org.apache.juneau.rest.RestContext.*;
@@ -29,9 +30,11 @@ import org.apache.juneau.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.html.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.widget.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.svl.*;
 import org.apache.juneau.urlencoding.*;
@@ -63,7 +66,11 @@ class CallMethod implements Comparable<CallMethod>  {
 	private final org.apache.juneau.rest.annotation.Parameter[] parameters;
 	private final Response[] responses;
 	private final RestContext context;
-	private final String pageTitle, pageText, pageLinks;
+	private final String htmlTitle, htmlDescription, htmlHeader, htmlLinks, htmlNav, htmlAside, htmlFooter, htmlCss,
+		htmlCssUrl, htmlNoResultsMessage;
+	private final boolean htmlNoWrap;
+	private final HtmlDocTemplate htmlTemplate;
+	private final Map<String,Widget> widgets;
 
 	CallMethod(Object servlet, java.lang.reflect.Method method, RestContext context) throws RestServletException {
 		Builder b = new Builder(servlet, method, context);
@@ -94,13 +101,26 @@ class CallMethod implements Comparable<CallMethod>  {
 		this.priority = b.priority;
 		this.parameters = b.parameters;
 		this.responses = b.responses;
-		this.pageTitle = b.pageTitle;
-		this.pageText = b.pageText;
-		this.pageLinks = b.pageLinks;
+		this.htmlTitle = b.htmlTitle;
+		this.htmlDescription = b.htmlDescription;
+		this.htmlHeader = b.htmlHeader;
+		this.htmlLinks = b.htmlLinks;
+		this.htmlNav = b.htmlNav;
+		this.htmlAside = b.htmlAside;
+		this.htmlFooter = b.htmlFooter;
+		this.htmlCss = b.htmlCss;
+		this.htmlCssUrl = b.htmlCssUrl;
+		this.htmlNoWrap = b.htmlNoWrap;
+		this.htmlTemplate = b.htmlTemplate;
+		this.htmlNoResultsMessage = b.htmlNoResultsMessage;
+		this.widgets = Collections.unmodifiableMap(b.widgets);
 	}
 
 	private static class Builder  {
-		private String httpMethod, defaultCharset, description, tags, summary, externalDocs, pageTitle, pageText, pageLinks;
+		private String httpMethod, defaultCharset, description, tags, summary, externalDocs, htmlTitle, htmlDescription,
+			htmlLinks, htmlNav, htmlAside, htmlFooter, htmlCssUrl, htmlCss, htmlHeader, htmlNoResultsMessage;
+		private boolean htmlNoWrap;
+		private HtmlDocTemplate htmlTemplate;
 		private UrlPathPattern pathPattern;
 		private RestParam[] params;
 		private RestGuard[] guards;
@@ -117,6 +137,7 @@ class CallMethod implements Comparable<CallMethod>  {
 		private Integer priority;
 		private org.apache.juneau.rest.annotation.Parameter[] parameters;
 		private Response[] responses;
+		private Map<String,Widget> widgets;
 
 		private Builder(Object servlet, java.lang.reflect.Method method, RestContext context) throws RestServletException {
 			try {
@@ -127,25 +148,41 @@ class CallMethod implements Comparable<CallMethod>  {
 
 				if (! m.description().isEmpty())
 					description = m.description();
-				if (! m.tags().isEmpty())
-					tags = m.tags();
+				MethodSwagger sm = m.swagger();
+				if (! sm.tags().isEmpty())
+					tags = sm.tags();
 				if (! m.summary().isEmpty())
 					summary = m.summary();
-				if (! m.externalDocs().isEmpty())
-					externalDocs = m.externalDocs();
-				deprecated = m.deprecated();
-				parameters = m.parameters();
-				responses = m.responses();
+				if (! sm.externalDocs().isEmpty())
+					externalDocs = sm.externalDocs();
+				deprecated = sm.deprecated();
+				parameters = sm.parameters();
+				responses = sm.responses();
 				serializers = context.getSerializers();
 				parsers = context.getParsers();
 				urlEncodingSerializer = context.getUrlEncodingSerializer();
 				urlEncodingParser = context.getUrlEncodingParser();
 				encoders = context.getEncoders();
 				properties = context.getProperties();
+				widgets = new HashMap<String,Widget>(context.getWidgets());
+				for (Class<? extends Widget> wc : m.widgets()) {
+					Widget w = ClassUtils.newInstance(Widget.class, wc);
+					widgets.put(w.getName(), w);
+				}
 
-				pageTitle = m.pageTitle().isEmpty() ? context.getPageTitle() : m.pageTitle();
-				pageText = m.pageText().isEmpty() ? context.getPageText() : m.pageText();
-				pageLinks = m.pageLinks().isEmpty() ? context.getPageLinks() : m.pageLinks();
+				HtmlDoc hd = m.htmldoc();
+				htmlTitle = hd.title().isEmpty() ? context.getHtmlTitle() : hd.title();
+				htmlDescription = hd.description().isEmpty() ? context.getHtmlDescription() : hd.description();
+				htmlHeader = hd.header().isEmpty() ? context.getHtmlHeader() : hd.header();
+				htmlLinks = hd.links().isEmpty() ? context.getHtmlLinks() : hd.links();
+				htmlNav = hd.nav().isEmpty() ? context.getHtmlNav() : hd.nav();
+				htmlAside = hd.aside().isEmpty() ? context.getHtmlAside() : hd.aside();
+				htmlFooter = hd.footer().isEmpty() ? context.getHtmlFooter() : hd.footer();
+				htmlCss = hd.css().isEmpty() ? context.getHtmlCss() : hd.css();
+				htmlCssUrl = hd.cssUrl().isEmpty() ? context.getHtmlCssUrl() : hd.cssUrl();
+				htmlNoWrap = hd.nowrap() ? hd.nowrap() : context.getHtmlNoWrap();
+				htmlNoResultsMessage = hd.noResultsMessage().isEmpty() ? context.getHtmlNoResultsMessage() : hd.header();
+				htmlTemplate = hd.template() == HtmlDocTemplate.class ? context.getHtmlTemplate() : ClassUtils.newInstance(HtmlDocTemplate.class, hd.template());
 
 				List<Inherit> si = Arrays.asList(m.serializersInherit());
 				List<Inherit> pi = Arrays.asList(m.parsersInherit());
@@ -700,7 +737,8 @@ class CallMethod implements Comparable<CallMethod>  {
 		req.getPathMatch().setRemainder(remainder);
 
 		ObjectMap requestProperties = createRequestProperties(properties, req);
-		req.init(method, requestProperties, defaultRequestHeaders, defaultQuery, defaultFormData, defaultCharset, serializers, parsers, urlEncodingParser, encoders, pageTitle, pageText, pageLinks);
+		req.init(method, requestProperties, defaultRequestHeaders, defaultQuery, defaultFormData, defaultCharset,
+			serializers, parsers, urlEncodingParser, encoders, widgets);
 		res.init(requestProperties, defaultCharset, serializers, urlEncodingSerializer, encoders);
 
 		// Class-level guards
@@ -820,12 +858,41 @@ class CallMethod implements Comparable<CallMethod>  {
 						return req.getMethodSummary();
 					if (k.equals(REST_methodDescription))
 						return req.getMethodDescription();
-					if (k.equals(HtmlDocSerializerContext.HTMLDOC_title))
-						return req.getPageTitle();
-					if (k.equals(HtmlDocSerializerContext.HTMLDOC_text))
-						return req.getPageText();
-					if (k.equals(HtmlDocSerializerContext.HTMLDOC_links))
-						return req.getPageLinks();
+					if (k.equals(HTMLDOC_title)) {
+						String s = htmlTitle;
+						if (! StringUtils.isEmpty(s))
+							return req.resolveVars(s);
+						return req.getServletTitle();
+					}
+					if (k.equals(HTMLDOC_description)) {
+						String s = htmlDescription;
+						if (! StringUtils.isEmpty(s))
+							return req.resolveVars(s);
+						s = req.getMethodSummary();
+						if (StringUtils.isEmpty(s))
+							s = req.getServletDescription();
+						return s;
+					}
+					if (k.equals(HTMLDOC_header))
+						return htmlHeader == null ? null : req.resolveVars(htmlHeader);
+					if (k.equals(HTMLDOC_links))
+						return htmlLinks == null ? null : req.resolveVars(htmlLinks);
+					if (k.equals(HTMLDOC_nav))
+						return htmlNav == null ? null : req.resolveVars(htmlNav);
+					if (k.equals(HTMLDOC_aside))
+						return htmlAside == null ? null : req.resolveVars(htmlAside);
+					if (k.equals(HTMLDOC_footer))
+						return htmlFooter == null ? null : req.resolveVars(htmlFooter);
+					if (k.equals(HTMLDOC_css))
+						return htmlCss == null ? null : req.resolveVars(htmlCss);
+					if (k.equals(HTMLDOC_cssUrl))
+						return htmlCssUrl == null ? null : req.resolveVars(htmlCssUrl);
+					if (k.equals(HTMLDOC_template))
+						return htmlTemplate;
+					if (k.equals(HTMLDOC_nowrap))
+						return htmlNoWrap;
+					if (k.equals(HTMLDOC_noResultsMessage))
+						return htmlNoResultsMessage == null ? null : req.resolveVars(htmlNoResultsMessage);
 					o = req.getPathMatch().get(k);
 					if (o == null)
 						o = req.getHeader(k);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
index 8d35327..234cabf 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
@@ -26,6 +26,7 @@ import javax.servlet.http.*;
 import org.apache.juneau.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.encoders.Encoder;
+import org.apache.juneau.html.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.ini.*;
 import org.apache.juneau.internal.*;
@@ -33,6 +34,7 @@ import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.response.*;
 import org.apache.juneau.rest.vars.*;
+import org.apache.juneau.rest.widget.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.svl.*;
 import org.apache.juneau.svl.vars.*;
@@ -105,7 +107,8 @@ public class RestConfig implements ServletConfig {
 	Object favIcon;
 	List<Object> staticFiles;
 	RestContext parentContext;
-	String path, pageTitle, pageText, pageLinks;
+	String path, htmlTitle, htmlDescription, htmlLinks, htmlHeader, htmlNav, htmlAside, htmlFooter, htmlCss, htmlCssUrl,
+		htmlNoResultsMessage;
 	String clientVersionHeader = "X-Client-Version";
 
 	Object resourceResolver = RestResourceResolver.class;
@@ -113,6 +116,12 @@ public class RestConfig implements ServletConfig {
 	Object callHandler = RestCallHandler.class;
 	Object infoProvider = RestInfoProvider.class;
 
+	boolean htmlNoWrap;
+	Object htmlTemplate = HtmlDocTemplateBasic.class;
+
+	Class<?> resourceClass;
+	Map<String,Widget> widgets = new HashMap<String,Widget>();
+
 	/**
 	 * Constructor.
 	 * @param config The servlet config passed into the servlet by the servlet container.
@@ -121,6 +130,7 @@ public class RestConfig implements ServletConfig {
 	 */
 	RestConfig(ServletConfig config, Class<?> resourceClass, RestContext parentContext) throws ServletException {
 		this.inner = config;
+		this.resourceClass = resourceClass;
 		this.parentContext = parentContext;
 		try {
 
@@ -193,12 +203,7 @@ public class RestConfig implements ServletConfig {
 					setPath(r.path());
 				if (! r.clientVersionHeader().isEmpty())
 					setClientVersionHeader(r.clientVersionHeader());
-				if (! r.pageTitle().isEmpty())
-					setPageTitle(r.pageTitle());
-				if (! r.pageText().isEmpty())
-					setPageText(r.pageText());
-				if (! r.pageLinks().isEmpty())
-					setPageLinks(r.pageLinks());
+
 				if (r.resourceResolver() != RestResourceResolver.class)
 					setResourceResolver(r.resourceResolver());
 				if (r.logger() != RestLogger.Normal.class)
@@ -207,6 +212,35 @@ public class RestConfig implements ServletConfig {
 					setCallHandler(r.callHandler());
 				if (r.infoProvider() != RestInfoProvider.class)
 					setInfoProvider(r.infoProvider());
+
+				for (Class<? extends Widget> cw : r.widgets())
+					addWidget(cw);
+
+				HtmlDoc hd = r.htmldoc();
+				if (! hd.title().isEmpty())
+					setHtmlTitle(hd.title());
+				if (! hd.description().isEmpty())
+					setHtmlDescription(hd.description());
+				if (! hd.header().isEmpty())
+					setHtmlHeader(hd.header());
+				if (! hd.links().isEmpty())
+					setHtmlLinks(hd.links());
+				if (! hd.nav().isEmpty())
+					setHtmlNav(hd.nav());
+				if (! hd.aside().isEmpty())
+					setHtmlAside(hd.aside());
+				if (! hd.footer().isEmpty())
+					setHtmlFooter(hd.footer());
+				if (! hd.css().isEmpty())
+					setHtmlCss(hd.css());
+				if (! hd.cssUrl().isEmpty())
+					setHtmlCssUrl(hd.cssUrl());
+				if (! hd.noResultsMessage().isEmpty())
+					setHtmlNoResultsMessage(hd.noResultsMessage());
+				if (hd.nowrap())
+					setHtmlNoWrap(true);
+				if (hd.template() != HtmlDocTemplate.class)
+					setHtmlTemplate(hd.template());
 			}
 
 			addResponseHandlers(
@@ -254,7 +288,9 @@ public class RestConfig implements ServletConfig {
 	 * 	<li>{@link RequestVar}
 	 * 	<li>{@link SerializedRequestAttrVar}
 	 * 	<li>{@link ServletInitParamVar}
+	 * 	<li>{@link UrlVar}
 	 * 	<li>{@link UrlEncodeVar}
+	 * 	<li>{@link WidgetVar}
 	 * </ul>
 	 *
 	 * @param vars The {@link Var} classes to add to this config.
@@ -1016,41 +1052,313 @@ public class RestConfig implements ServletConfig {
 	}
 
 	/**
-	 * Sets the page title to use on HTML views of pages.
+	 * Sets the HTML page title.
+	 * <p>
+	 * The format of this value is plain text.
+	 * <p>
+	 * It gets wrapped in a <code><xt>&lt;h3&gt; <xa>class</xa>=<xs>'title'</xs>&gt;</xt></code> element and then added
+	 * 	to the <code><xt>&lt;header&gt;</code> section on the page.
+	 * <p>
+	 * If not specified, the page title is pulled from one of the following locations:
+	 * <ol>
+	 * 	<li><code>{servletClass}.{methodName}.pageTitle</code> resource bundle value.
+	 * 	<li><code>{servletClass}.pageTitle</code> resource bundle value.
+	 * 	<li><code><ja>@RestResource</ja>(title)</code> annotation.
+	 * 	<li><code>{servletClass}.title</code> resource bundle value.
+	 * 	<li><code>info/title</code> entry in swagger file.
+	 * <ol>
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no value.
+	 * <p>
+	 * <ul class='doctree'>
+	 * 	<li class='info'>
+	 * 		In most cases, you'll simply want to use the <code>@RestResource(title)</code> annotation to specify the
+	 * 		page title.
+	 * 		However, this annotation is provided in cases where you want the page title to be different that the one
+	 * 		shown in the swagger document.
+	 * </ul>
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#title() @HtmlDoc.title()} annotation.
+	 *
+	 * @param value The HTML page title.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlTitle(String value) {
+		this.htmlTitle = value;
+		return this;
+	}
+
+	/**
+	 * Sets the HTML page description.
+	 * <p>
+	 * The format of this value is plain text.
+	 * <p>
+	 * It gets wrapped in a <code><xt>&lt;h5&gt; <xa>class</xa>=<xs>'description'</xs>&gt;</xt></code> element and then
+	 * 	added to the <code><xt>&lt;header&gt;</code> section on the page.
+	 * <p>
+	 * If not specified, the page title is pulled from one of the following locations:
+	 * <ol>
+	 * 	<li><code>{servletClass}.{methodName}.pageText</code> resource bundle value.
+	 * 	<li><code>{servletClass}.pageText</code> resource bundle value.
+	 * 	<li><code><ja>@RestMethod</ja>(summary)</code> annotation.
+	 * 	<li><code>{servletClass}.{methodName}.summary</code> resource bundle value.
+	 * 	<li><code>summary</code> entry in swagger file for method.
+	 * 	<li><code>{servletClass}.description</code> resource bundle value.
+	 * 	<li><code>info/description</code> entry in swagger file.
+	 * <ol>
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no value.
+	 * <p>
+	 * <ul class='doctree'>
+	 * 	<li class='info'>
+	 * 		In most cases, you'll simply want to use the <code>@RestResource(description)</code> or
+	 * 		<code>@RestMethod(summary)</code> annotations to specify the page text.
+	 * 		However, this annotation is provided in cases where you want the text to be different that the values shown
+	 * 		in the swagger document.
+	 * </ul>
 	 * <p>
-	 * This is the programmatic equivalent to the {@link RestResource#pageTitle() @RestResource.pageTitle()} annotation.
+	 * This is the programmatic equivalent to the {@link HtmlDoc#description() @HtmlDoc.description()} annotation.
 	 *
-	 * @param pageTitle The page title text.
+	 * @param value The HTML page description.
 	 * @return This object (for method chaining).
 	 */
-	public RestConfig setPageTitle(String pageTitle) {
-		this.pageTitle = pageTitle;
+	public RestConfig setHtmlDescription(String value) {
+		this.htmlDescription = value;
 		return this;
 	}
 
 	/**
-	 * Sets the page text to use on HTML views of pages.
+	 * Sets the HTML header section contents.
+	 * <p>
+	 * The format of this value is HTML.
+	 * <p>
+	 * The page header normally contains the title and description, but this value can be used to override the contents
+	 * 	to be whatever you want.
+	 * <p>
+	 * When a value is specified, the {@link #setHtmlTitle(String)} and {@link #setHtmlDescription(String)} values will be ignored.
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no header.
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#header() @HtmlDoc.header()} annotation.
+	 *
+	 * @param value The HTML header section contents.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlHeader(String value) {
+		this.htmlHeader = value;
+		return this;
+	}
+
+	/**
+	 * Sets the links in the HTML nav section.
+	 * <p>
+	 * The format of this value is a lax-JSON map of key/value pairs where the keys are the link text and the values are
+	 * 	relative (to the servlet) or absolute URLs.
+	 * <p>
+	 * The page links are positioned immediately under the title and text.
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no value.
+	 * <p>
+	 * This field can also use URIs of any support type in {@link UriResolver}.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#links() @HtmlDoc.links()} annotation.
+	 *
+	 * @param value The HTML nav section links links.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlLinks(String value) {
+		this.htmlLinks = value;
+		return this;
+	}
+
+	/**
+	 * Sets the HTML nav section contents.
+	 * <p>
+	 * The format of this value is HTML.
+	 * <p>
+	 * The nav section of the page contains the links.
+	 * <p>
+	 * The format of this value is HTML.
+	 * <p>
+	 * When a value is specified, the {@link #setHtmlLinks(String)} value will be ignored.
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no value.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#nav() @HtmlDoc.nav()} annotation.
+	 *
+	 * @param value The HTML nav section contents.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlNav(String value) {
+		this.htmlNav = value;
+		return this;
+	}
+
+	/**
+	 * Sets the HTML aside section contents.
+	 * <p>
+	 * The format of this value is HTML.
+	 * <p>
+	 * The aside section typically floats on the right side of the page.
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no value.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#aside() @HtmlDoc.aside()} annotation.
+	 *
+	 * @param value The HTML aside section contents.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlAside(String value) {
+		this.htmlAside = value;
+		return this;
+	}
+
+	/**
+	 * Sets the HTML footer section contents.
+	 * <p>
+	 * The format of this value is HTML.
+	 * <p>
+	 * The footer section typically floats on the bottom of the page.
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no value.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#footer() @HtmlDoc.footer()} annotation.
+	 *
+	 * @param value The HTML footer section contents.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlFooter(String value) {
+		this.htmlFooter = value;
+		return this;
+	}
+
+	/**
+	 * Sets the HTML CSS style section contents.
+	 * <p>
+	 * The format of this value is CSS.
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
+	 * <p>
+	 * A value of <js>"NONE"</js> can be used to force no value.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#css() @HtmlDoc.css()} annotation.
+	 *
+	 * @param value The HTML CSS style section contents.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlCss(String value) {
+		this.htmlCss = value;
+		return this;
+	}
+
+	/**
+	 * Sets the CSS URL in the HTML CSS style section.
+	 * <p>
+	 * The format of this value is a URL.
+	 * <p>
+	 * Specifies the URL to the stylesheet to add as a link in the style tag in the header.
+	 * <p>
+	 * The format of this value is CSS.
+	 * <p>
+	 * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>) and can use URL protocols defined
+	 * 	by {@link UriResolver}.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#cssUrl() @HtmlDoc.cssUrl()} annotation.
+	 *
+	 * @param value The CSS URL in the HTML CSS style section.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlCssUrl(String value) {
+		this.htmlCssUrl = value;
+		return this;
+	}
+
+	/**
+	 * Shorthand method for forcing the rendered HTML content to be no-wrap.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#nowrap() @HtmlDoc.nowrap()} annotation.
+	 *
+	 * @param value The new nowrap setting.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlNoWrap(boolean value) {
+		this.htmlNoWrap = value;
+		return this;
+	}
+
+	/**
+	 * Specifies the text to display when serializing an empty array or collection.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#noResultsMessage() @HtmlDoc.noResultsMessage()} annotation.
+	 *
+	 * @param value The text to display when serializing an empty array or collection.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlNoResultsMessage(String value) {
+		this.htmlNoResultsMessage = value;
+		return this;
+	}
+
+	/**
+	 * Specifies the template class to use for rendering the HTML page.
+	 * <p>
+	 * By default, uses {@link HtmlDocTemplateBasic} to render the contents, although you can provide
+	 * 	 your own custom renderer or subclasses from the basic class to have full control over how the page is
+	 * 	rendered.
+	 * <p>
+	 * This is the programmatic equivalent to the {@link HtmlDoc#template() @HtmlDoc.template()} annotation.
+	 *
+	 * @param value The HTML page template to use to render the HTML page.
+	 * @return This object (for method chaining).
+	 */
+	public RestConfig setHtmlTemplate(Class<? extends HtmlDocTemplate> value) {
+		this.htmlTemplate = value;
+		return this;
+	}
+
+	/**
+	 * Specifies the template class to use for rendering the HTML page.
+	 * <p>
+	 * By default, uses {@link HtmlDocTemplateBasic} to render the contents, although you can provide
+	 * 	 your own custom renderer or subclasses from the basic class to have full control over how the page is
+	 * 	rendered.
 	 * <p>
-	 * This is the programmatic equivalent to the {@link RestResource#pageText() @RestResource.pageText()} annotation.
+	 * This is the programmatic equivalent to the {@link HtmlDoc#template() @HtmlDoc.template()} annotation.
 	 *
-	 * @param pageText The page text.
+	 * @param value The HTML page template to use to render the HTML page.
 	 * @return This object (for method chaining).
 	 */
-	public RestConfig setPageText(String pageText) {
-		this.pageText = pageText;
+	public RestConfig setHtmlTemplate(HtmlDocTemplate value) {
+		this.htmlTemplate = value;
 		return this;
 	}
 
 	/**
-	 * Sets the page links to use on HTML views of pages.
+	 * Defines widgets that can be used in conjunction with string variables of the form <js>"$W{name}"</js>to quickly
+	 * 	generate arbitrary replacement text.
 	 * <p>
-	 * This is the programmatic equivalent to the {@link RestResource#pageLinks() @RestResource.pageLinks()} annotation.
+	 * Widgets are inherited from parent to child, but can be overridden by reusing the widget name.
 	 *
-	 * @param pageLinks The page links.
+	 * @param value The widget class to add.
 	 * @return This object (for method chaining).
 	 */
-	public RestConfig setPageLinks(String pageLinks) {
-		this.pageLinks = pageLinks;
+	public RestConfig addWidget(Class<? extends Widget> value) {
+		Widget w = ClassUtils.newInstance(Widget.class, value);
+		this.widgets.put(w.getName(), w);
 		return this;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
index 62aca6c..cec08c0 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -33,6 +33,7 @@ import javax.servlet.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.encoders.*;
+import org.apache.juneau.html.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.ini.*;
 import org.apache.juneau.internal.*;
@@ -41,6 +42,7 @@ import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.annotation.Properties;
 import org.apache.juneau.rest.vars.*;
+import org.apache.juneau.rest.widget.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.svl.*;
 import org.apache.juneau.urlencoding.*;
@@ -300,7 +302,20 @@ public final class RestContext extends Context {
 		paramFormat,
 		clientVersionHeader,
 		fullPath,
-		pageTitle, pageText, pageLinks;
+		htmlTitle,
+		htmlDescription,
+		htmlHeader,
+		htmlLinks,
+		htmlNav,
+		htmlAside,
+		htmlCss,
+		htmlCssUrl,
+		htmlFooter,
+		htmlNoResultsMessage;
+	private final boolean htmlNoWrap;
+	private final HtmlDocTemplate htmlTemplate;
+	private final Map<String,Widget> widgets;
+
 	private final Set<String> allowMethodParams;
 
 	private final ObjectMap properties;
@@ -398,9 +413,20 @@ public final class RestContext extends Context {
 			this.childResources = Collections.synchronizedMap(new LinkedHashMap<String,RestContext>());  // Not unmodifiable on purpose so that children can be replaced.
 			this.logger = b.logger;
 			this.fullPath = b.fullPath;
-			this.pageTitle = b.pageTitle;
-			this.pageText = b.pageText;
-			this.pageLinks = b.pageLinks;
+			this.widgets = Collections.unmodifiableMap(b.widgets);
+
+			this.htmlTitle = b.htmlTitle;
+			this.htmlDescription = b.htmlDescription;
+			this.htmlHeader = b.htmlHeader;
+			this.htmlLinks = b.htmlLinks;
+			this.htmlNav = b.htmlNav;
+			this.htmlAside = b.htmlAside;
+			this.htmlCss = b.htmlCss;
+			this.htmlCssUrl = b.htmlCssUrl;
+			this.htmlFooter = b.htmlFooter;
+			this.htmlNoWrap = b.htmlNoWrap;
+			this.htmlNoResultsMessage = b.htmlNoResultsMessage;
+			this.htmlTemplate = b.htmlTemplate;
 
 			//----------------------------------------------------------------------------------------------------
 			// Initialize the child resources.
@@ -572,7 +598,11 @@ public final class RestContext extends Context {
 		UrlEncodingSerializer urlEncodingSerializer;
 		UrlEncodingParser urlEncodingParser;
 		EncoderGroup encoders;
-		String clientVersionHeader = "", defaultCharset, paramFormat, pageTitle, pageText, pageLinks;
+		String clientVersionHeader = "", defaultCharset, paramFormat, htmlTitle, htmlDescription, htmlHeader, htmlLinks,
+			htmlNav, htmlAside, htmlCss, htmlCssUrl, htmlFooter, htmlNoResultsMessage;
+		boolean htmlNoWrap;
+		HtmlDocTemplate htmlTemplate;
+
 		List<MediaType> supportedContentTypes, supportedAcceptTypes;
 		Map<String,String> defaultRequestHeaders = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER);
 		Map<String,Object> defaultResponseHeaders;
@@ -588,6 +618,7 @@ public final class RestContext extends Context {
 		Set<String> allowMethodParams = new LinkedHashSet<String>();
 		RestLogger logger;
 		String fullPath;
+		Map<String,Widget> widgets;
 
 		@SuppressWarnings("unchecked")
 		private Builder(Object resource, RestConfig sc) throws Exception {
@@ -610,7 +641,7 @@ public final class RestContext extends Context {
 					allowMethodParams.add(m.toUpperCase());
 
 			varResolver = sc.varResolverBuilder
-				.vars(LocalizationVar.class, RequestVar.class, SerializedRequestAttrVar.class, ServletInitParamVar.class, UrlEncodeVar.class)
+				.vars(LocalizationVar.class, RequestVar.class, SerializedRequestAttrVar.class, ServletInitParamVar.class, UrlVar.class, UrlEncodeVar.class, WidgetVar.class)
 				.build()
 			;
 			configFile = sc.configFile.getResolving(this.varResolver);
@@ -716,9 +747,20 @@ public final class RestContext extends Context {
 
 			fullPath = (sc.parentContext == null ? "" : (sc.parentContext.fullPath + '/')) + sc.path;
 
-			pageTitle = sc.pageTitle;
-			pageText = sc.pageText;
-			pageLinks = sc.pageLinks;
+			widgets = sc.widgets;
+
+			htmlTitle = sc.htmlTitle;
+			htmlDescription = sc.htmlDescription;
+			htmlHeader = sc.htmlHeader;
+			htmlLinks = sc.htmlLinks;
+			htmlNav = sc.htmlNav;
+			htmlAside = sc.htmlAside;
+			htmlCss = sc.htmlCss;
+			htmlCssUrl = sc.htmlCssUrl;
+			htmlFooter = sc.htmlFooter;
+			htmlNoWrap = sc.htmlNoWrap;
+			htmlNoResultsMessage = sc.htmlNoResultsMessage;
+			htmlTemplate = ClassUtils.newInstance(HtmlDocTemplate.class, sc.htmlTemplate);
 		}
 	}
 
@@ -940,30 +982,146 @@ public final class RestContext extends Context {
 	}
 
 	/**
-	 * Returns the page title as defined by the {@link RestResource#pageTitle()} annotation or {@link RestConfig#setPageTitle(String)} method.
+	 * The HTML page title.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#title()} annotation or {@link RestConfig#setHtmlTitle(String)} method.
 	 *
-	 * @return The page title.
+	 * @return The HTML page title.
 	 */
-	public String getPageTitle() {
-		return pageTitle;
+	public String getHtmlTitle() {
+		return htmlTitle;
 	}
 
 	/**
-	 * Returns the page text as defined by the {@link RestResource#pageText()} annotation or {@link RestConfig#setPageText(String)} method.
+	 * The HTML page description.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#description()} annotation or {@link RestConfig#setHtmlDescription(String)} method.
 	 *
-	 * @return The page text.
+	 * @return The HTML page description.
 	 */
-	public String getPageText() {
-		return pageText;
+	public String getHtmlDescription() {
+		return htmlDescription;
 	}
 
 	/**
-	 * Returns the page links as defined by the {@link RestResource#pageLinks()} annotation or {@link RestConfig#setPageLinks(String)} method.
+	 * The HTML page header contents.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#header()} annotation or {@link RestConfig#setHtmlHeader(String)} method.
+	 *
+	 * @return The HTML page header contents.
+	 */
+	public String getHtmlHeader() {
+		return htmlHeader;
+	}
+
+	/**
+	 * The HTML page nav section links.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#links()} annotation or {@link RestConfig#setHtmlLinks(String)} method.
+	 *
+	 * @return The HTML page nav section links.
+	 */
+	public String getHtmlLinks() {
+		return htmlLinks;
+	}
+
+	/**
+	 * The HTML page nav section contents.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#nav()} annotation or {@link RestConfig#setHtmlNav(String)} method.
+	 *
+	 * @return The HTML page nav section contents.
+	 */
+	public String getHtmlNav() {
+		return htmlNav;
+	}
+
+	/**
+	 * The HTML page aside section contents.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#aside()} annotation or {@link RestConfig#setHtmlAside(String)} method.
+	 *
+	 * @return The HTML page aside section contents.
+	 */
+	public String getHtmlAside() {
+		return htmlAside;
+	}
+
+	/**
+	 * The HTML page footer section contents.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#footer()} annotation or {@link RestConfig#setHtmlFooter(String)} method.
+	 *
+	 * @return The HTML page footer section contents.
+	 */
+	public String getHtmlFooter() {
+		return htmlFooter;
+	}
+
+	/**
+	 * The HTML page CSS URL.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#cssUrl()} annotation or {@link RestConfig#setHtmlCssUrl(String)} method.
+	 *
+	 * @return The HTML page CSS URL.
+	 */
+	public String getHtmlCssUrl() {
+		return htmlCssUrl;
+	}
+
+	/**
+	 * The HTML page CSS contents.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#css()} annotation or {@link RestConfig#setHtmlCss(String)} method.
+	 *
+	 * @return The HTML page CSS contents.
+	 */
+	public String getHtmlCss() {
+		return htmlCss;
+	}
+
+	/**
+	 * The HTML page nowrap setting.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#nowrap()} annotation or {@link RestConfig#setHtmlNoWrap(boolean)} method.
+	 *
+	 * @return The HTML page nowrap setting.
+	 */
+	public boolean getHtmlNoWrap() {
+		return htmlNoWrap;
+	}
+
+	/**
+	 * The HTML page template.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#template()} annotation or {@link RestConfig#setHtmlTemplate(Class)} method.
+	 *
+	 * @return The HTML page template.
+	 */
+	public HtmlDocTemplate getHtmlTemplate() {
+		return htmlTemplate;
+	}
+
+	/**
+	 * The HTML page no-results message.
+	 * <p>
+	 * Defined by the {@link HtmlDoc#noResultsMessage()} annotation or {@link RestConfig#setHtmlNoResultsMessage(String)} method.
+	 *
+	 * @return The HTML page no-results message.
+	 */
+	public String getHtmlNoResultsMessage() {
+		return htmlNoResultsMessage;
+	}
+
+	/**
+	 * The widgets used for resolving <js>"$W{...}"<js> variables.
+	 * <p>
+	 * Defined by the {@link RestResource#widgets()} annotation or {@link RestConfig#addWidget(Class)} method.
 	 *
-	 * @return The page links.
+	 * @return The var resolver widgets as a map with keys being the name returned by {@link Widget#getName()}.
 	 */
-	public String getPageLinks() {
-		return pageLinks;
+	public Map<String,Widget> getWidgets() {
+		return widgets;
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest/src/main/java/org/apache/juneau/rest/RestInfoProvider.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestInfoProvider.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestInfoProvider.java
index 18488e6..0254be6 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestInfoProvider.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestInfoProvider.java
@@ -91,18 +91,19 @@ public class RestInfoProvider {
 					title = r.title();
 				if (! r.description().isEmpty())
 					description = r.description();
-				if (! r.termsOfService().isEmpty())
-					termsOfService = r.termsOfService();
-				if (! r.contact().isEmpty())
-					contact = r.contact();
-				if (! r.license().isEmpty())
-					license = r.license();
-				if (! r.version().isEmpty())
-					version = r.version();
-				if (! r.tags().isEmpty())
-					tags = r.tags();
-				if (! r.externalDocs().isEmpty())
-					externalDocs = r.externalDocs();
+				ResourceSwagger sr = r.swagger();
+				if (! sr.termsOfService().isEmpty())
+					termsOfService = sr.termsOfService();
+				if (! sr.contact().isEmpty())
+					contact = sr.contact();
+				if (! sr.license().isEmpty())
+					license = sr.license();
+				if (! sr.version().isEmpty())
+					version = sr.version();
+				if (! sr.tags().isEmpty())
+					tags = sr.tags();
+				if (! sr.externalDocs().isEmpty())
+					externalDocs = sr.externalDocs();
 			}
 		}
 	}
@@ -298,7 +299,7 @@ public class RestInfoProvider {
 	 * <p>
 	 * The default implementation returns the contact information from the following locations (whichever matches first):
 	 * <ol>
-	 * 	<li>{@link RestResource#contact() @RestResource.contact()} annotation on this class, and then any parent classes.
+	 * 	<li>{@link ResourceSwagger#contact() @ResourceSwagger.contact()} annotation on this class, and then any parent classes.
 	 * 	<li><ck>[ClassName].contact</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
 	 * 		annotation for this class, then any parent classes.
 	 * 	<li><ck>contact</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
@@ -334,7 +335,7 @@ public class RestInfoProvider {
 	 * <p>
 	 * The default implementation returns the license information from the following locations (whichever matches first):
 	 * <ol>
-	 * 	<li>{@link RestResource#license() @RestResource.license()} annotation on this class, and then any parent classes.
+	 * 	<li>{@link ResourceSwagger#license() @ResourceSwagger.license()} annotation on this class, and then any parent classes.
 	 * 	<li><ck>[ClassName].license</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
 	 * 		annotation for this class, then any parent classes.
 	 * 	<li><ck>license</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
@@ -370,7 +371,7 @@ public class RestInfoProvider {
 	 * <p>
 	 * The default implementation returns the terms-of-service information from the following locations (whichever matches first):
 	 * <ol>
-	 * 	<li>{@link RestResource#termsOfService() @RestResource.termsOfService()} annotation on this class, and then any parent classes.
+	 * 	<li>{@link ResourceSwagger#termsOfService() @ResourceSwagger.termsOfService()} annotation on this class, and then any parent classes.
 	 * 	<li><ck>[ClassName].termsOfService</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
 	 * 		annotation for this class, then any parent classes.
 	 * 	<li><ck>termsOfService</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
@@ -401,7 +402,7 @@ public class RestInfoProvider {
 	 * <p>
 	 * The default implementation returns the version information from the following locations (whichever matches first):
 	 * <ol>
-	 * 	<li>{@link RestResource#version() @RestResource.version()} annotation on this class, and then any parent classes.
+	 * 	<li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent classes.
 	 * 	<li><ck>[ClassName].version</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
 	 * 		annotation for this class, then any parent classes.
 	 * 	<li><ck>version</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
@@ -432,7 +433,7 @@ public class RestInfoProvider {
 	 * <p>
 	 * The default implementation returns the version information from the following locations (whichever matches first):
 	 * <ol>
-	 * 	<li>{@link RestResource#version() @RestResource.version()} annotation on this class, and then any parent classes.
+	 * 	<li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent classes.
 	 * 	<li><ck>[ClassName].version</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
 	 * 		annotation for this class, then any parent classes.
 	 * 	<li><ck>version</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
@@ -468,7 +469,7 @@ public class RestInfoProvider {
 	 * <p>
 	 * The default implementation returns the version information from the following locations (whichever matches first):
 	 * <ol>
-	 * 	<li>{@link RestResource#version() @RestResource.version()} annotation on this class, and then any parent classes.
+	 * 	<li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent classes.
 	 * 	<li><ck>[ClassName].version</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
 	 * 		annotation for this class, then any parent classes.
 	 * 	<li><ck>version</ck> property in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/f4812b7c/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
index 5112e25..74fa22c 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -35,6 +35,7 @@ import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.ini.*;
 import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.widget.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.svl.*;
 import org.apache.juneau.uon.*;
@@ -87,7 +88,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	private RequestHeaders headers;
 	private ConfigFile cf;
 	private Swagger swagger, fileSwagger;
-	private String pageTitle, pageText, pageLinks;
+	private Map<String,Widget> widgets;
 
 	/**
 	 * Constructor.
@@ -155,7 +156,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	final void init(Method javaMethod, ObjectMap properties, Map<String,String> defHeader,
 			Map<String,String> defQuery, Map<String,String> defFormData, String defaultCharset,
 			SerializerGroup mSerializers, ParserGroup mParsers, UrlEncodingParser mUrlEncodingParser,
-			EncoderGroup encoders, String pageTitle, String pageText, String pageLinks) {
+			EncoderGroup encoders, Map<String,Widget> widgets) {
 		this.javaMethod = javaMethod;
 		this.properties = properties;
 		this.urlEncodingParser = mUrlEncodingParser;
@@ -181,10 +182,8 @@ public final class RestRequest extends HttpServletRequestWrapper {
 		this.serializerGroup = mSerializers;
 		this.parserGroup = mParsers;
 		this.defaultCharset = defaultCharset;
-		this.pageTitle = pageTitle;
-		this.pageText = pageText;
-		this.pageLinks = pageLinks;
 		this.defFormData = defFormData;
+		this.widgets = widgets;
 
 		if (debug) {
 			String msg = ""
@@ -698,57 +697,6 @@ public final class RestRequest extends HttpServletRequestWrapper {
 		return context.getInfoProvider().getMethodDescription(javaMethod.getName(), this);
 	}
 
-	/**
-	 * Returns the localized page title for HTML views.
-	 *
-	 * @return The localized page title for HTML views.
-	 */
-	protected String getPageTitle() {
-		String s = pageTitle;
-		if (isEmpty(s))
-			s = context.getMessages().findFirstString(getLocale(), javaMethod.getName() + ".pageTitle");
-		if (isEmpty(s))
-			s = context.getMessages().findFirstString(getLocale(), "pageTitle");
-		if (! isEmpty(s))
-			return resolveVars(s);
-		s = getServletTitle();
-		return s;
-	}
-
-	/**
-	 * Returns the localized page text for HTML views.
-	 *
-	 * @return The localized page text for HTML views.
-	 */
-	protected String getPageText() {
-		String s = pageText;
-		if (isEmpty(s))
-			s = context.getMessages().findFirstString(getLocale(), javaMethod.getName() + ".pageText");
-		if (isEmpty(s))
-			s = context.getMessages().findFirstString(getLocale(), "pageText");
-		if (! isEmpty(s))
-			return resolveVars(s);
-		s = getMethodSummary();
-		if (isEmpty(s))
-			s = getServletDescription();
-		return s;
-	}
-
-	/**
-	 * Returns the localized page links for HTML views.
-	 *
-	 * @return The localized page links for HTML views.
-	 */
-	protected String getPageLinks() {
-		String s = pageLinks;
-		if (isEmpty(s))
-			s = context.getMessages().findFirstString(getLocale(), javaMethod.getName() + ".pageLinks");
-		if (isEmpty(s))
-			s = context.getMessages().findFirstString(getLocale(), "pageLinks");
-		return resolveVars(s);
-	}
-
-
 	//--------------------------------------------------------------------------------
 	// Other methods
 	//--------------------------------------------------------------------------------
@@ -955,7 +903,8 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	/**
 	 * Returns the localized swagger associated with the servlet.
 	 *
-	 * @return The swagger associated with the servlet.  Never <jk>null</jk>.
+	 * @return The swagger associated with the servlet.
+	 * 	Never <jk>null</jk>.
 	 */
 	public Swagger getSwagger() {
 		if (swagger == null)
@@ -964,6 +913,16 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	}
 
 	/**
+	 * Returns the widgets used for resolving <js>"$W{...}"</js> string variables.
+	 *
+	 * @return The widgets used for resolving <js>"$W{...}"</js> string variables.
+	 * 	Never <jk>null</jk>.
+	 */
+	public Map<String,Widget> getWidgets() {
+		return widgets;
+	}
+
+	/**
 	 * Returns the localized Swagger from the file system.
 	 * <p>
 	 * Looks for a file called <js>"{ServletClass}_{locale}.json"</js> in the same package