Repository: incubator-juneau
Updated Branches:
  refs/heads/master b95ee52b4 -> 21a80b823


Add @HtmlDoc(head) annotation.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/21a80b82
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/21a80b82
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/21a80b82

Branch: refs/heads/master
Commit: 21a80b8232fd03084c629a71e6b682f77e14902d
Parents: b95ee52
Author: JamesBognar <[email protected]>
Authored: Sat Oct 7 17:37:18 2017 -0400
Committer: JamesBognar <[email protected]>
Committed: Sat Oct 7 17:37:18 2017 -0400

----------------------------------------------------------------------
 eclipse-preferences/user-dictionary.txt         |  2 +
 .../apache/juneau/ini/ConfigFileWrapped.java    |  5 +-
 .../juneau/utils/StringVarResolverTest.java     |  2 +-
 .../juneau/html/HtmlDocSerializerContext.java   | 46 +++++++++++++-
 .../juneau/html/HtmlDocSerializerSession.java   | 16 ++++-
 .../juneau/html/HtmlDocTemplateBasic.java       |  4 ++
 .../apache/juneau/svl/VarResolverSession.java   | 10 +--
 juneau-doc/src/main/javadoc/overview.html       | 12 ++++
 .../juneau/examples/rest/PetStoreResource.java  |  3 +
 .../java/org/apache/juneau/rest/CallMethod.java |  6 +-
 .../org/apache/juneau/rest/RestCallHandler.java |  6 +-
 .../java/org/apache/juneau/rest/RestConfig.java | 64 +++++---------------
 .../org/apache/juneau/rest/RestContext.java     | 54 ++++++-----------
 .../org/apache/juneau/rest/RestRequest.java     | 18 ++++++
 .../org/apache/juneau/rest/RestResponse.java    | 31 ++++++++++
 .../apache/juneau/rest/RestServletDefault.java  | 11 ++--
 .../java/org/apache/juneau/rest/RestUtils.java  | 17 ++++++
 .../apache/juneau/rest/annotation/HtmlDoc.java  | 42 +++++++++++++
 .../juneau/rest/annotation/RestResource.java    | 38 ------------
 19 files changed, 241 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/eclipse-preferences/user-dictionary.txt
----------------------------------------------------------------------
diff --git a/eclipse-preferences/user-dictionary.txt 
b/eclipse-preferences/user-dictionary.txt
index 12425c8..0c387d7 100644
--- a/eclipse-preferences/user-dictionary.txt
+++ b/eclipse-preferences/user-dictionary.txt
@@ -492,3 +492,5 @@ strived
 protobuf
 maven
 configurability
+navlinks
+fav

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFileWrapped.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFileWrapped.java
 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFileWrapped.java
index da8e83b..1454a18 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFileWrapped.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFileWrapped.java
@@ -241,10 +241,7 @@ public final class ConfigFileWrapped extends ConfigFile {
 
        @Override /* ConfigFile */
        public String get(String sectionName, String sectionKey) {
-               String s = cf.get(sectionName, sectionKey);
-               if (s == null)
-                       return null;
-               return vs.resolve(s);
+               return vs.resolve(cf.get(sectionName, sectionKey));
        }
 
        @Override /* ConfigFile */

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
index 364e233..baef26b 100755
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
@@ -30,7 +30,7 @@ public class StringVarResolverTest {
                String t;
 
                t = null;
-               assertEquals("", vr.resolve(t));
+               assertEquals(null, vr.resolve(t));
 
                t = "";
                assertEquals("", vr.resolve(t));

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
index 55f2274..f017253 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
@@ -434,6 +434,48 @@ public final class HtmlDocSerializerContext extends 
HtmlSerializerContext {
        public static final String HTMLDOC_script_add = 
"HtmlDocSerializer.script.list.add";
 
        /**
+        * <b>Configuration property:</b>  Additional head section content.
+        *
+        * <ul>
+        *      <li><b>Name:</b> <js>"HtmlDocSerializer.head.list"</js>
+        *      <li><b>Data type:</b> <code>List&lt;String&gt;</code>
+        *      <li><b>Default:</b> empty list
+        *      <li><b>Session-overridable:</b> <jk>true</jk>
+        * </ul>
+        *
+        * <p>
+        * Adds the specified HTML content to the head section of the page.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode'>
+        *      <ja>@RestResource</ja>(
+        *              properties={
+        *                      
<ja>@Property</ja>(name=HtmlDocSerializerContext.<jsf>HTMLDOC_links</jsf>,
+        *                              value=<js>"['<link rel=\"icon\" 
href=\"htdocs/mypageicon.ico\">']"</js>)
+        *              }
+        *      )
+        * </p>
+        *
+        * <p>
+        * A shortcut on <ja>@RestResource</ja> is also provided for this 
setting:
+        * <p class='bcode'>
+        *      <ja>@RestResource</ja>(
+        *              htmldoc=@HtmlDoc(
+        *                      head={
+        *                              <js>"<link rel='icon' 
href='$U{servlet:/htdocs/mypageicon.ico}'>"</js>
+        *                      }
+        *              )
+        *      )
+        * </p>
+        */
+       public static final String HTMLDOC_head = "HtmlDocSerializer.head.list";
+
+       /**
+        * <b>Configuration property:</b>  Add to the {@link #HTMLDOC_head} 
property.
+        */
+       public static final String HTMLDOC_links_add = 
"HtmlDocSerializer.head.list.add";
+
+       /**
         * <b>Configuration property:</b>  HTML document template.
         *
         * <ul>
@@ -462,7 +504,7 @@ public final class HtmlDocSerializerContext extends 
HtmlSerializerContext {
        public static final String HTMLDOC_template = 
"HtmlDocSerializer.template";
 
 
-       final String[] style, stylesheet, script, navlinks;
+       final String[] style, stylesheet, script, navlinks, head;
        final String header, nav, aside, footer, noResultsMessage;
        final boolean nowrap;
        final HtmlDocTemplate template;
@@ -480,6 +522,7 @@ public final class HtmlDocSerializerContext extends 
HtmlSerializerContext {
                style = ps.getProperty(HTMLDOC_style, String[].class, new 
String[0]);
                stylesheet = ps.getProperty(HTMLDOC_stylesheet, String[].class, 
new String[0]);
                script = ps.getProperty(HTMLDOC_script, String[].class, new 
String[0]);
+               head = ps.getProperty(HTMLDOC_head, String[].class, new 
String[0]);
                header = ps.getProperty(HTMLDOC_header, String.class, null);
                nav = ps.getProperty(HTMLDOC_nav, String.class, null);
                aside = ps.getProperty(HTMLDOC_aside, String.class, null);
@@ -500,6 +543,7 @@ public final class HtmlDocSerializerContext extends 
HtmlSerializerContext {
                                .append("aside", aside)
                                .append("footer", footer)
                                .append("style", style)
+                               .append("head", head)
                                .append("stylesheet", stylesheet)
                                .append("nowrap", nowrap)
                                .append("template", template)

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
index d56040d..43a2d69 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
@@ -30,7 +30,7 @@ import org.apache.juneau.serializer.*;
 public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession 
{
 
        private final String header, nav, aside, footer, noResultsMessage;
-       private final String[] style, stylesheet, script, navlinks;
+       private final String[] style, stylesheet, script, navlinks, head;
        private final boolean nowrap;
        private final HtmlDocTemplate template;
 
@@ -55,6 +55,7 @@ public class HtmlDocSerializerSession extends 
HtmlStrippedDocSerializerSession {
                        style = ctx.style;
                        stylesheet = ctx.stylesheet;
                        script = ctx.script;
+                       head = ctx.head;
                        nowrap = ctx.nowrap;
                        noResultsMessage = ctx.noResultsMessage;
                        template = 
ClassUtils.newInstance(HtmlDocTemplate.class, ctx.template);
@@ -67,6 +68,7 @@ public class HtmlDocSerializerSession extends 
HtmlStrippedDocSerializerSession {
                        style = p.getStringArray(HTMLDOC_style, ctx.style);
                        stylesheet = p.getStringArray(HTMLDOC_stylesheet, 
ctx.stylesheet);
                        script = p.getStringArray(HTMLDOC_script, ctx.script);
+                       head = p.getStringArray(HTMLDOC_head, ctx.head);
                        nowrap = p.getBoolean(HTMLDOC_nowrap, ctx.nowrap);
                        noResultsMessage = 
p.getString(HTMLDOC_noResultsMessage, ctx.noResultsMessage);
                        template = 
ClassUtils.newInstance(HtmlDocTemplate.class, 
p.getWithDefault(HTMLDOC_template, ctx.template));
@@ -110,6 +112,18 @@ public class HtmlDocSerializerSession extends 
HtmlStrippedDocSerializerSession {
        }
 
        /**
+        * Returns the {@link HtmlDocSerializerContext#HTMLDOC_head} setting 
value in this context.
+        *
+        * @return
+        *      The {@link HtmlDocSerializerContext#HTMLDOC_head} setting value 
in this context.
+        *      An empty array if not specified.
+        *      Never <jk>null</jk>.
+        */
+       public final String[] getHead() {
+               return head;
+       }
+
+       /**
         * Returns the {@link HtmlDocSerializerContext#HTMLDOC_nowrap} setting 
value in this context.
         *
         * @return The {@link HtmlDocSerializerContext#HTMLDOC_nowrap} setting 
value in this context.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
index be06ac1..ffaabb5 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
@@ -24,6 +24,10 @@ public class HtmlDocTemplateBasic implements HtmlDocTemplate 
{
 
        @Override /* HtmlDocTemplate */
        public void head(HtmlDocSerializerSession session, HtmlWriter w, Object 
o) throws Exception {
+               
+               for (String h : session.getHead()) 
+                       w.appendln(2, h);
+               
                if (hasStyle(session)) {
                        w.sTag(2, "style").nl(2);
                        style(session, w, o);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
 
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
index 2e24226..f9da289 100644
--- 
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
+++ 
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
@@ -71,15 +71,17 @@ public class VarResolverSession {
        /**
         * Resolve all variables in the specified string.
         *
-        * @param s The string to resolve variables in.
+        * @param s 
+        *      The string to resolve variables in.
         * @return
         *      The new string with all variables resolved, or the same string 
if no variables were found.
-        *      Null input results in a blank string.
+        *      <br>Returns <jk>null</jk> if the input was <jk>null</jk>.
         */
        public String resolve(String s) {
 
-               if (s == null)
-                       return "";
+               if (s == null || s.isEmpty())
+                       return s;
+
                if (s.indexOf('$') == -1 && s.indexOf('\\') == -1)
                        return s;
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-doc/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-doc/src/main/javadoc/overview.html 
b/juneau-doc/src/main/javadoc/overview.html
index 582a15a..351e1af 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -7469,6 +7469,18 @@
                <ul class='spaced-list'>
                        <li>
                                Annotation 
<code><ja>@HtmlDoc</ja>(links)</code> renamed to {@link 
org.apache.juneau.rest.annotation.HtmlDoc#navlinks() navlinks}.
+                       <li>
+                               New annotation {@link 
org.apache.juneau.rest.annotation.HtmlDoc#head()}.
+                               <br>Allows you to specify arbitrary HTML 
content in the <xt>&lt;head&gt;</xt> section of the page.
+                       <li>
+                               Removed annotation 
<code><ja>@HtmlDoc</ja>(favIcon)</code>.
+                               <br>This was a discouraged way of defining 
fav-icons anyway, and with the addition of 
+                               <code><ja>@HtmlDoc</ja>(head)</code>, you can 
define them using:
+                               <p class='bcode'>
+       head={
+               <js>"&lt;link rel='icon' 
href='$U{servlet:/htdocs/juneau.png}'/&gt;"</js>
+       }
+                               </p>
                </ul>
        </div>
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java
 
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java
index c351b52..8f0ea69 100644
--- 
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java
+++ 
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java
@@ -61,6 +61,9 @@ import org.apache.juneau.transforms.*;
                        "       <p>It also shows examples of HtmlRender classes 
and @BeanProperty(format) annotations.</p>",
                        "       <p>It also shows how the Queryable converter 
and query widget can be used to create searchable interfaces.</p>",
                        "</div>"
+               },
+               head={
+                       "<link rel='icon' href='$U{servlet:/htdocs/cat.png}'/>"
                }
        )
 )

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/CallMethod.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/CallMethod.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/CallMethod.java
index 192af23..7f31520 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/CallMethod.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/CallMethod.java
@@ -68,7 +68,7 @@ class CallMethod implements Comparable<CallMethod>  {
        private final RestContext context;
        private final BeanContext beanContext;
        final String htmlHeader, htmlNav, htmlAside, htmlFooter, htmlStyle, 
htmlStylesheet, htmlScript, htmlNoResultsMessage;
-       final String[] htmlNavLinks;
+       final String[] htmlNavLinks, htmlHead;
        final boolean htmlNoWrap;
        final HtmlDocTemplate htmlTemplate;
        private final Map<String,Widget> widgets;
@@ -111,6 +111,7 @@ class CallMethod implements Comparable<CallMethod>  {
                this.htmlStyle = b.htmlStyle;
                this.htmlStylesheet = b.htmlStylesheet;
                this.htmlScript = b.htmlScript;
+               this.htmlHead = b.htmlHead;
                this.htmlNoWrap = b.htmlNoWrap;
                this.htmlTemplate = b.htmlTemplate;
                this.htmlNoResultsMessage = b.htmlNoResultsMessage;
@@ -120,7 +121,7 @@ class CallMethod implements Comparable<CallMethod>  {
        private static class Builder  {
                private String httpMethod, defaultCharset, description, tags, 
summary, externalDocs, htmlNav, htmlAside,
                        htmlFooter, htmlStyle, htmlStylesheet, htmlScript, 
htmlHeader, htmlNoResultsMessage;
-               private String[] htmlNavLinks;
+               private String[] htmlNavLinks, htmlHead;
                private boolean htmlNoWrap;
                private HtmlDocTemplate htmlTemplate;
                private UrlPathPattern pathPattern;
@@ -191,6 +192,7 @@ class CallMethod implements Comparable<CallMethod>  {
                                htmlFooter = 
resolveNewlineSeparatedAnnotation(hd.footer(), context.getHtmlFooter());
                                htmlStyle = 
resolveNewlineSeparatedAnnotation(hd.style(), context.getHtmlStyle());
                                htmlScript = 
resolveNewlineSeparatedAnnotation(hd.script(), context.getHtmlScript());
+                               htmlHead = resolveContent(hd.head(), 
context.getHtmlHead());
                                htmlNavLinks = resolveLinks(hd.navlinks(), 
context.getHtmlNavLinks());
                                htmlStylesheet = hd.stylesheet().isEmpty() ? 
context.getHtmlStylesheet() : hd.stylesheet();
                                htmlNoWrap = hd.nowrap() ? hd.nowrap() : 
context.getHtmlNoWrap();

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
index 4903229..5fdb378 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
@@ -141,10 +141,10 @@ public class RestCallHandler {
                        StreamResource r = null;
                        if (pathInfo != null) {
                                String p = pathInfo.substring(1);
-                               if (p.equals("favicon.ico"))
-                                       r = context.getFavIcon();
-                               else if (context.isStaticFile(p))
+                               if (context.isStaticFile(p))
                                        r = context.resolveStaticFile(p);
+                               else if (p.equals("favicon.ico"))
+                                       res.setOutput(null);
                        }
 
                        if (r != null) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
index ba3fff9..d08bf42 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
@@ -17,7 +17,6 @@ import static org.apache.juneau.internal.ReflectionUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.rest.RestUtils.*;
 
-import java.io.*;
 import java.lang.reflect.Method;
 import java.util.*;
 
@@ -112,11 +111,10 @@ public class RestConfig implements ServletConfig {
        List<Object> responseHandlers = new ArrayList<Object>();
        List<Object> childResources = new ArrayList<Object>();
        List<MediaType> supportedContentTypes, supportedAcceptTypes;
-       Object favIcon;
        List<Object> staticFiles;
        RestContext parentContext;
        String path, htmlHeader, htmlNav, htmlAside, htmlFooter, htmlStyle, 
htmlStylesheet, htmlScript, htmlNoResultsMessage;
-       String[] htmlNavLinks;
+       String[] htmlNavLinks, htmlHead;
        String clientVersionHeader = "X-Client-Version";
        String contextPath;
 
@@ -224,8 +222,6 @@ public class RestConfig implements ServletConfig {
                                serializerListener(r.serializerListener());
                                parserListener(r.parserListener());
                                contextPath(r.contextPath());
-                               if (! r.favicon().isEmpty())
-                                       setFavIcon(c, r.favicon());
                                if (! r.staticFiles().isEmpty())
                                        addStaticFiles(c, r.staticFiles());
                                if (! r.path().isEmpty())
@@ -266,6 +262,7 @@ public class RestConfig implements ServletConfig {
                                
setHtmlStyle(resolveNewlineSeparatedAnnotation(hd.style(), htmlStyle));
                                
setHtmlScript(resolveNewlineSeparatedAnnotation(hd.script(), htmlScript));
                                setHtmlNavLinks(resolveLinks(hd.navlinks(), 
htmlNavLinks));
+                               setHtmlHead(resolveContent(hd.head(), 
htmlHead));
 
                                if (! hd.stylesheet().isEmpty())
                                        setHtmlStylesheet(hd.stylesheet());
@@ -1017,49 +1014,6 @@ public class RestConfig implements ServletConfig {
        }
 
        /**
-        * Specifies the icon contents that make up the contents of the page 
<js>"/resource-path/favicon.ico"</js>.
-        *
-        * <p>
-        * This is the programmatic equivalent to the {@link 
RestResource#favicon() @RestResource.favicon()} annotation.
-        *
-        * <p>
-        * The object type can be any of the following:
-        * <ul>
-        *      <li>{@link InputStream}
-        *      <li>{@link File}
-        *      <li><code><jk>byte</jk>[]</code>
-        * </ul>
-        *
-        * @param favIcon The contents that make up the 
<code>favicon.ico</code> page.
-        * @return This object (for method chaining).
-        */
-       public RestConfig setFavIcon(Object favIcon) {
-               this.favIcon = favIcon;
-               return this;
-       }
-
-       /**
-        * Specifies the icon contents that make up the contents of the page 
<js>"/resource-path/favicon.ico"</js>.
-        *
-        * <p>
-        * This is the programmatic equivalent to the {@link 
RestResource#favicon() @RestResource.favicon()} annotation.
-        *
-        * <p>
-        * Use this method to specify a resource located in the classpath.
-        * This call uses the {@link Class#getResourceAsStream(String)} method 
to retrieve the stylesheet contents.
-        *
-        * @param resourceClass The resource class used to resolve the resource 
stream.
-        * @param resourcePath
-        *      The path passed to the {@link 
Class#getResourceAsStream(String)} method.
-        *      Can also be a path starting with <js>"file://"</js> denoting a 
location to pull from the file system.
-        * @return This object (for method chaining).
-        */
-       public RestConfig setFavIcon(Class<?> resourceClass, String 
resourcePath) {
-               this.favIcon = new Pair<Class<?>,String>(resourceClass, 
resourcePath);
-               return this;
-       }
-
-       /**
         * Appends to the static files resource map.
         *
         * <p>
@@ -1470,6 +1424,20 @@ public class RestConfig implements ServletConfig {
        }
 
        /**
+        * Adds to the HTML head section contents.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#head() 
@HtmlDoc.head()} annotation.
+        *
+        * @param value The HTML head section content.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlHead(String...value) {
+               this.htmlHead = value;
+               return this;
+       }
+
+       /**
         * Shorthand method for forcing the rendered HTML content to be no-wrap.
         *
         * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index bd23730..d113059 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -79,7 +79,8 @@ public final class RestContext extends Context {
                htmlFooter,
                htmlNoResultsMessage;
        private final String[]
-               htmlNavLinks;
+               htmlNavLinks,
+               htmlHead;
        private final boolean htmlNoWrap;
        private final HtmlDocTemplate htmlTemplate;
        private final Map<String,Widget> htmlWidgets;
@@ -106,7 +107,6 @@ public final class RestContext extends Context {
        private final RestGuard[] guards;
        private final ResponseHandler[] responseHandlers;
        private final MimetypesFileTypeMap mimetypesFileTypeMap;
-       private final StreamResource favIcon;
        private final Map<String,String> staticFilesMap;
        private final String[] staticFilesPrefixes;
        private final MessageBundle msgs;
@@ -197,7 +197,6 @@ public final class RestContext extends Context {
                        this.guards = b.guards.toArray(new 
RestGuard[b.guards.size()]);
                        this.responseHandlers = 
toObjectArray(b.responseHandlers, ResponseHandler.class);
                        this.mimetypesFileTypeMap = b.mimetypesFileTypeMap;
-                       this.favIcon = b.favIcon;
                        this.staticFilesMap = 
Collections.unmodifiableMap(b.staticFilesMap);
                        this.staticFilesPrefixes = b.staticFilesPrefixes;
                        this.msgs = b.messageBundle;
@@ -214,6 +213,7 @@ public final class RestContext extends Context {
                        this.htmlStyle = b.htmlStyle;
                        this.htmlStylesheet = b.htmlStylesheet;
                        this.htmlScript = b.htmlScript;
+                       this.htmlHead = b.htmlHead;
                        this.htmlFooter = b.htmlFooter;
                        this.htmlNoWrap = b.htmlNoWrap;
                        this.htmlNoResultsMessage = b.htmlNoResultsMessage;
@@ -484,7 +484,7 @@ public final class RestContext extends Context {
                EncoderGroup encoders;
                String clientVersionHeader = "", defaultCharset, paramFormat, 
htmlHeader, htmlNav, htmlAside, htmlStyle,
                                htmlStylesheet, htmlScript, htmlFooter, 
htmlNoResultsMessage;
-               String[] htmlNavLinks;
+               String[] htmlNavLinks, htmlHead;
                boolean htmlNoWrap;
                HtmlDocTemplate htmlTemplate;
 
@@ -496,7 +496,6 @@ public final class RestContext extends Context {
                List<RestGuard> guards = new ArrayList<RestGuard>();
                List<ResponseHandler> responseHandlers = new 
ArrayList<ResponseHandler>();
                MimetypesFileTypeMap mimetypesFileTypeMap;
-               StreamResource favIcon;
                Map<String,String> staticFilesMap;
                String[] staticFilesPrefixes;
                MessageBundle messageBundle;
@@ -589,19 +588,6 @@ public final class RestContext extends Context {
 
                        VarResolver vr = sc.getVarResolverBuilder().build();
 
-                       if (sc.favIcon != null) {
-                               Object o = sc.favIcon;
-                               InputStream is = null;
-                               if (o instanceof Pair) {
-                                       Pair<Class<?>,String> p = 
(Pair<Class<?>,String>)o;
-                                       is = 
ReflectionUtils.getResource(p.first(), vr.resolve(p.second()));
-                               } else {
-                                       is = toInputStream(o);
-                               }
-                               if (is != null)
-                                       favIcon = new 
StreamResource(MediaType.forString("image/x-icon"), is);
-                       }
-
                        staticFilesMap = new LinkedHashMap<String,String>();
                        if (sc.staticFiles != null) {
                                for (Object o : sc.staticFiles) {
@@ -633,6 +619,7 @@ public final class RestContext extends Context {
                        htmlStyle = sc.htmlStyle;
                        htmlStylesheet = sc.htmlStylesheet;
                        htmlScript = sc.htmlScript;
+                       htmlHead = sc.htmlHead;
                        htmlFooter = sc.htmlFooter;
                        htmlNoWrap = sc.htmlNoWrap;
                        htmlNoResultsMessage = sc.htmlNoResultsMessage;
@@ -998,6 +985,18 @@ public final class RestContext extends Context {
        }
 
        /**
+        * The HTML page head content.
+        *
+        * <p>
+        * Defined by the {@link HtmlDoc#head()} annotation or {@link 
RestConfig#setHtmlHead(String[])} method.
+        *
+        * @return The HTML page head content.
+        */
+       public String[] getHtmlHead() {
+               return htmlHead;
+       }
+
+       /**
         * The HTML page nowrap setting.
         *
         * <p>
@@ -1753,25 +1752,6 @@ public final class RestContext extends Context {
        }
 
        /**
-        * Returns the favicon of the resource.
-        *
-        * <p>
-        * This is the icon served up under <js>"/favicon.ico"</jk> recognized 
by browsers.
-        *
-        * <p>
-        * The favicon is defined via one of the following:
-        * <ul>
-        *      <li>{@link RestResource#favicon() @RestResource.favicon()} 
annotation.
-        *      <li>{@link RestConfig#setFavIcon(Object)}/{@link 
RestConfig#setFavIcon(Class, String)} methods.
-        * </ul>
-        *
-        * @return The favicon of this resource.  Can be <jk>null</jk>.
-        */
-       protected StreamResource getFavIcon() {
-               return favIcon;
-       }
-
-       /**
         * Returns <jk>true</jk> if the specified path refers to a static file.
         *
         * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index bdb0e4a..861009f 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -325,6 +325,8 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                                } else if (c2 == 'h') {
                                        if ("header".equals(name))
                                                return cm.htmlHeader == null ? 
null : resolveVars(cm.htmlHeader);
+                                       if ("head.list".equals(name))
+                                               return resolveVars(cm.htmlHead);
                                } else if (c2 == 'n') {
                                        if ("nav".equals(name))
                                                return cm.htmlNav == null ? 
null : resolveVars(cm.htmlNav);
@@ -1057,6 +1059,22 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        }
 
        /**
+        * Shortcut for calling {@link #resolveVars(String[])} on all elements 
in the array.
+        *
+        * @param input The input strings to resolve variables in.
+        * @return A copy of the array with variables resolved.
+        */
+       public String[] resolveVars(String[] input) {
+               VarResolverSession vs = getVarResolverSession();
+               if (input == null || input.length == 0)
+                       return input;
+               input = Arrays.copyOf(input, input.length);
+               for (int i = 0; i < input.length; i++)
+                       input[i] = vs.resolve(input[i]);
+               return input;
+       }
+
+       /**
         * Returns an instance of a {@link ReaderResource} that represents the 
contents of a resource text file from the
         * classpath.
         *

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index 0da444f..fffd0c1 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -728,6 +728,37 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
        }
 
        /**
+        * Sets the HTML head section contents.
+        *
+        * <p>
+        * The format of this value is HTML.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#head() 
@HtmlDoc.head()} annotation.
+        *
+        * @param value
+        *      The HTML head section contents.
+        *      <p>
+        *      <ul class='doctree'>
+        *              <li class='info'>
+        *                      <b>Tip:</b>  Use {@link StringMessage} to 
generate value with delayed serialization so as not to
+        *                              waste string concatenation cycles on 
non-HTML views.
+        *      </ul>
+        * @return This object (for method chaining).
+        */
+       public RestResponse setHtmlHead(Object...value) {
+               properties.put(HtmlDocSerializerContext.HTMLDOC_head, value);
+               return this;
+       }
+
+       /**
         * Shorthand method for forcing the rendered HTML content to be no-wrap.
         *
         * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
index 5751caa..1733d51 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
@@ -151,9 +151,6 @@ import org.apache.juneau.xml.*;
  *             Provides a default HTML stylesheet by setting {@link 
HtmlDoc#stylesheet() @HtmlDoc.stylesheet()}
  *             to <js>"styles/juneau.css"</js>.
  *     <li>
- *             Provides a default favicon by setting {@link 
RestResource#favicon() @RestResource.favicon()} to
- *             <js>"juneau.ico"</js>.
- *     <li>
  *             Provides a default classpath entry "htdocs" by setting
  *             {@link RestResource#staticFiles() @RestResource.staticFiles()} 
to <js>"{htdocs:'htdocs'}"</js>.
  *             This allows files inside the 
<code>[servletPackage].htdocs</code> package to be served up under the URL
@@ -192,12 +189,12 @@ import org.apache.juneau.xml.*;
                        "<h2>$R{methodSummary,$R{servletDescription}}</h2>",
                        "<a href='http://juneau.apache.org'><img 
src='$U{servlet:/htdocs/juneau.png}' 
style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/></a>"
                },
-               stylesheet="servlet:/styles/light.css"
+               stylesheet="servlet:/styles/light.css",
+               head={
+                       "<link rel='icon' 
href='$U{servlet:/htdocs/juneau.png}'/>"
+               }
        ),
 
-       // The location on the classpath or file system of the fav-icon.
-       favicon="htdocs/juneau.png",
-
        // These are static files that are served up by the servlet under the 
specified sub-paths.
        staticFiles="{htdocs:'htdocs',styles:'styles'}"
 )

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
index 03ccbc2..aa90a63 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
@@ -223,4 +223,21 @@ public final class RestUtils {
                }
                return list.toArray(new String[list.size()]);
        }
+
+       static String[] resolveContent(String[] content, String[] 
parentContent) {
+               if (content.length == 0)
+                       return parentContent;
+
+               List<String> list = new ArrayList<String>();
+               for (String l : content) {
+                       if ("INHERIT".equals(l)) {
+                               list.addAll(Arrays.asList(parentContent));
+                       } else if ("NONE".equals(l)) {
+                               return new String[0];
+                       } else {
+                               list.add(l);
+                       }
+               }
+               return list.toArray(new String[list.size()]);
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
index 61ab2f6..ef6d275 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
@@ -426,6 +426,48 @@ public @interface HtmlDoc {
        String[] script() default {};
 
        /**
+        * Adds arbitrary content to the HTML <xt>&lt;head&gt;</xt> element on 
the page.
+        *
+        * <p>
+        * The format of this value is HTML.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode'>
+        *      <ja>@RestResource</ja>(
+        *              htmldoc=<ja>@HtmlDoc</ja>(
+        *                      head={
+        *                              <jc>// Add a shortcut link in the 
browser tab</jc>
+        *                              <js>"<link rel='icon' 
href='$U{servlet:/htdocs/mypageicon.ico}'>"</js>,
+        *
+        *                              <jc>// Reload the page every 5 seconds 
</jc>
+        *                              <js>"<meta http-equiv='refresh' 
content='5'>"</js>
+        *                      }
+        *              )
+        *      )
+        * </p>
+        *
+        * <h6 class='topic'>Other Notes</h6>
+        * <ul class='spaced-list'>
+        *      <li>
+        *              This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        *              <br>See {@link RestContext#getVarResolver()} for the 
list of supported variables.
+        *      <li>
+        *              A value of <js>"NONE"</js> can be used to force no 
value.
+        *      <li>
+        *              The head content from the parent can be included by 
adding the literal <js>"INHERIT"</js> as a value.
+        *      <li>
+        *              The programmatic equivalent to this annotation are the
+        *              {@link RestConfig#setHtmlHead(String[])} and {@link 
RestResponse#setHtmlHead(String[])} methods.
+        *      <li>
+        *              On methods, this value is inherited from the 
<ja>@HtmlDoc</ja> annotation on the servlet/resource class.
+        *      <li>
+        *              On servlet/resource classes, this value is inherited 
from the <ja>@HtmlDoc</ja> annotation on the
+        *              parent class.
+        * </ul>
+        */
+       String[] head() default {};
+
+       /**
         * Shorthand method for forcing the rendered HTML content to be no-wrap.
         *
         * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21a80b82/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
index 76e6123..66e9561 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
@@ -506,44 +506,6 @@ public @interface RestResource {
        String config() default "";
 
        /**
-        * The favicon to use for HTML views.
-        *
-        * <p>
-        * The name is a path to an icon file located in either the classpath 
or working directory.
-        * The resulting favicon becomes available in the servlet via the URL 
<js>"[servlet-path]/favicon.ico"</js>.
-        *
-        * <p>
-        * If the file cannot be located, the request to 
<js>"[servlet-path]/favicon.ico"</js> will return
-        * {@link HttpServletResponse#SC_NOT_FOUND}.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode'>
-        *      <jk>package</jk> com.foo.mypackage;
-        *
-        *      <ja>@RestResource</ja>(
-        *              favicon=<js>"mydocs/myicon.ico"</js>
-        *      )
-        *      <jk>public class</jk> MyResource <jk>extends</jk> 
RestServletDefault {
-        *      }
-        * </p>
-        *
-        * <p>
-        * In this example, the servlet will attempt to find the 
<code>myicon.ico</code> file in the following ordered
-        * locations:
-        * <ol>
-        *      <li><code>com.foo.mypackage.mydocs</code> package.
-        *      <li><code>org.apache.juneau.rest.mydocs</code> package (since 
<code>RestServletDefault</code> is in
-        *              <code>org.apache.juneau.rest</code>).
-        *      <li><code>[working-dir]/mydocs</code> directory.
-        * </ol>
-        *
-        * <p>
-        * The programmatic equivalent to this annotation are the {@link 
RestConfig#setFavIcon(Object)}/
-        * {@link RestConfig#setFavIcon(Class, String)} methods.
-        */
-       String favicon() default "";
-
-       /**
         * Defines paths and locations of statically served files.
         *
         * <p>


Reply via email to