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/10/09 22:57:52 UTC
[2/2] incubator-juneau git commit: Clean up how HtmlDoc properties
are defined.
Clean up how HtmlDoc properties are defined.
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/9c746e64
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/9c746e64
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/9c746e64
Branch: refs/heads/master
Commit: 9c746e647280eeb49cd78b5956eb5c1250cf71f3
Parents: d767cb6
Author: JamesBognar <ja...@apache.org>
Authored: Mon Oct 9 18:57:45 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Mon Oct 9 18:57:45 2017 -0400
----------------------------------------------------------------------
.../juneau/svl/ResolvingObjectMapTest.java | 121 +++++
.../main/java/org/apache/juneau/ObjectMap.java | 19 +-
.../juneau/html/HtmlDocSerializerContext.java | 61 +--
.../juneau/html/HtmlDocSerializerSession.java | 20 +-
.../juneau/html/HtmlDocTemplateBasic.java | 61 ++-
.../juneau/serializer/SerializerWriter.java | 17 +
.../apache/juneau/svl/ResolvingObjectMap.java | 119 +++++
.../apache/juneau/rest/test/HtmlDocTest.java | 20 +-
.../apache/juneau/rest/test/PropertiesTest.java | 10 -
.../java/org/apache/juneau/rest/CallMethod.java | 63 +--
.../org/apache/juneau/rest/HtmlDocBuilder.java | 151 +++++-
.../org/apache/juneau/rest/HtmlDocConfig.java | 456 -------------------
.../org/apache/juneau/rest/HtmlDocContext.java | 171 -------
.../java/org/apache/juneau/rest/RestConfig.java | 34 +-
.../org/apache/juneau/rest/RestContext.java | 29 +-
.../org/apache/juneau/rest/RestRequest.java | 123 +----
.../apache/juneau/rest/annotation/HtmlDoc.java | 32 +-
.../org/apache/juneau/rest/vars/UrlVar.java | 1 -
.../org/apache/juneau/rest/vars/WidgetVar.java | 18 +-
.../org/apache/juneau/rest/widget/Widget.java | 2 +-
20 files changed, 573 insertions(+), 955 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/svl/ResolvingObjectMapTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/svl/ResolvingObjectMapTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/svl/ResolvingObjectMapTest.java
new file mode 100644
index 0000000..17a1dee
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/svl/ResolvingObjectMapTest.java
@@ -0,0 +1,121 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.svl;
+
+import static org.junit.Assert.*;
+import static org.apache.juneau.TestUtils.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+
+public class ResolvingObjectMapTest {
+
+ //====================================================================================================
+ // test - Basic tests
+ //====================================================================================================
+ @Test
+ public void testBasic() throws Exception {
+ VarResolver vr = new VarResolverBuilder().defaultVars().vars(XVar.class).build();
+ ObjectMap m = new ResolvingObjectMap(vr.createSession());
+
+ m.put("foo", "$X{a}");
+ assertEquals(m.get("foo"), "1");
+
+ m.put("foo", new String[]{"$X{a}"});
+ assertObjectEquals("['1']", m.get("foo"));
+
+ m.put("foo", new AList<String>().append("$X{a}"));
+ assertObjectEquals("['1']", m.get("foo"));
+
+ m.put("foo", new AMap<String,String>().append("k1","$X{a}"));
+ assertObjectEquals("{k1:'1'}", m.get("foo"));
+ }
+
+ public static class XVar extends MapVar {
+ public XVar() {
+ super("X", new ObjectMap().append("a", 1).append("b", 2).append("c", 3));
+ }
+ }
+
+ //====================================================================================================
+ // testNulls
+ //====================================================================================================
+ @Test
+ public void testNulls() throws Exception {
+ VarResolver vr = new VarResolverBuilder().defaultVars().vars(XVar.class).build();
+ ObjectMap m = new ResolvingObjectMap(vr.createSession());
+
+ m.put("foo", null);
+ assertNull(m.get("foo"));
+
+ m.put("foo", new String[]{null});
+ assertObjectEquals("[null]", m.get("foo"));
+
+ m.put("foo", new AList<String>().append(null));
+ assertObjectEquals("[null]", m.get("foo"));
+
+ m.put("foo", new AMap<String,String>().append("k1",null));
+ assertObjectEquals("{k1:null}", m.get("foo"));
+ }
+
+ //====================================================================================================
+ // testNonStrings
+ //====================================================================================================
+ @Test
+ public void testNonStrings() throws Exception {
+ VarResolver vr = new VarResolverBuilder().defaultVars().vars(XVar.class).build();
+ ObjectMap m = new ResolvingObjectMap(vr.createSession());
+
+ m.put("foo", FooEnum.ONE);
+ assertObjectEquals("'ONE'", m.get("foo"));
+
+ m.put("foo", new Object[]{FooEnum.ONE});
+ assertObjectEquals("['ONE']", m.get("foo"));
+
+ m.put("foo", new AList<FooEnum>().append(FooEnum.ONE));
+ assertObjectEquals("['ONE']", m.get("foo"));
+
+ m.put("foo", new AMap<FooEnum,FooEnum>().append(FooEnum.ONE,FooEnum.ONE));
+ assertObjectEquals("{ONE:'ONE'}", m.get("foo"));
+ }
+
+ public static enum FooEnum {
+ ONE
+ }
+
+ //====================================================================================================
+ // testInner - Test inner maps
+ //====================================================================================================
+ @Test
+ public void testInner() throws Exception {
+ VarResolver vr = new VarResolverBuilder().defaultVars().vars(XVar.class).build();
+ ObjectMap m = new ResolvingObjectMap(vr.createSession());
+ ObjectMap m2 = new ObjectMap();
+ ObjectMap m3 = new ObjectMap();
+ m.setInner(m2);
+ m2.setInner(m3);
+
+ m3.put("foo", "$X{a}");
+ assertEquals(m.get("foo"), "1");
+
+ m3.put("foo", new String[]{"$X{a}"});
+ assertObjectEquals("['1']", m.get("foo"));
+
+ m3.put("foo", new AList<String>().append("$X{a}"));
+ assertObjectEquals("['1']", m.get("foo"));
+
+ m3.put("foo", new AMap<String,String>().append("k1","$X{a}"));
+ assertObjectEquals("{k1:'1'}", m.get("foo"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
index e3ab9bc..7eef2dd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
@@ -692,25 +692,16 @@ public class ObjectMap extends LinkedHashMap<String,Object> {
}
/**
- * Specialized method that calls {@link #getString(String)} and splits the results as a simple comma-delimited list.
+ * Returns the specified entry value converted to a {@link String}.
*
* <p>
- * If the value is already a collection, the individual entries are converted to strings using {@link #toString()}.
+ * Shortcut for <code>get(key, String[].<jk>class</jk>)</code>.
*
- * @param key the key.
- * @return
- * A list of tokens, trimmed of whitespace.
- * An empty list if entry not found.
- * Never <jk>null</jk>.
+ * @param key The key.
+ * @return The converted value, or <jk>null</jk> if the map contains no mapping for this key.
*/
public String[] getStringArray(String key) {
- Object s = get(key, Object.class);
- if (s == null)
- return new String[0];
- if (s instanceof Collection)
- return ArrayUtils.toStringArray((Collection<?>)s);
- String[] r = split(StringUtils.toString(s));
- return r;
+ return getStringArray(key, null);
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/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 6296ff3..ef2b964 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
@@ -85,7 +85,7 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.header"</js>
- * <li><b>Data type:</b> <code>String</code>
+ * <li><b>Data type:</b> <code>String[]</code>
* <li><b>Default:</b> <jk>null</jk>
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
@@ -104,11 +104,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
* )
* )
* </p>
- *
- * <p>
- * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string.
*/
- public static final String HTMLDOC_header = PREFIX + "header";
+ public static final String HTMLDOC_header = PREFIX + "header.list";
/**
* <b>Configuration property:</b> Page navigation links.
@@ -185,7 +182,7 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.nav"</js>
- * <li><b>Data type:</b> <code>String</code>
+ * <li><b>Data type:</b> <code>String[]</code>
* <li><b>Default:</b> <jk>null</jk>
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
@@ -207,18 +204,15 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <p>
* When this property is specified, the {@link #HTMLDOC_navlinks} property is ignored.
- *
- * <p>
- * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string.
*/
- public static final String HTMLDOC_nav = PREFIX + "nav";
+ public static final String HTMLDOC_nav = PREFIX + "nav.list";
/**
* <b>Configuration property:</b> Aside section contents.
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.aside"</js>
- * <li><b>Data type:</b> <code>String</code>
+ * <li><b>Data type:</b> <code>String[]</code>
* <li><b>Default:</b> <jk>null</jk>
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
@@ -245,18 +239,15 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
* )
* )
* </p>
- *
- * <p>
- * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string.
*/
- public static final String HTMLDOC_aside = PREFIX + "aside";
+ public static final String HTMLDOC_aside = PREFIX + "aside.list";
/**
* <b>Configuration property:</b> Footer section contents.
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.footer"</js>
- * <li><b>Data type:</b> <code>String</code>
+ * <li><b>Data type:</b> <code>String[]</code>
* <li><b>Default:</b> <jk>null</jk>
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
@@ -277,11 +268,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
* )
* )
* </p>
- *
- * <p>
- * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string.
*/
- public static final String HTMLDOC_footer = PREFIX + "footer";
+ public static final String HTMLDOC_footer = PREFIX + "footer.list";
/**
* <b>Configuration property:</b> No-results message.
@@ -330,8 +318,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.stylesheet"</js>
- * <li><b>Data type:</b> <code>List<String></code>
- * <li><b>Default:</b> empty list
+ * <li><b>Data type:</b> <code>String[]</code>
+ * <li><b>Default:</b> empty array
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
*
@@ -340,11 +328,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <p>
* Note that this stylesheet is controlled by the <code><ja>@RestResource</ja>.stylesheet()</code> annotation.
- *
- * <p>
- * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string.
*/
- public static final String HTMLDOC_stylesheet = PREFIX + "stylesheet";
+ public static final String HTMLDOC_stylesheet = PREFIX + "stylesheet.list";
/**
* <b>Configuration property:</b> Add to the {@link #HTMLDOC_stylesheet} property.
@@ -356,8 +341,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.style.list"</js>
- * <li><b>Data type:</b> <code>List<String></code>
- * <li><b>Default:</b> empty list
+ * <li><b>Data type:</b> <code>String[]</code>
+ * <li><b>Default:</b> empty array
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
*
@@ -399,8 +384,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.script.list"</js>
- * <li><b>Data type:</b> <code>List<String></code>
- * <li><b>Default:</b> empty list
+ * <li><b>Data type:</b> <code>String[]</code>
+ * <li><b>Default:</b> empty array
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
*
@@ -441,8 +426,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
*
* <ul>
* <li><b>Name:</b> <js>"HtmlDocSerializer.head.list"</js>
- * <li><b>Data type:</b> <code>List<String></code>
- * <li><b>Default:</b> empty list
+ * <li><b>Data type:</b> <code>String[]</code>
+ * <li><b>Default:</b> empty array
* <li><b>Session-overridable:</b> <jk>true</jk>
* </ul>
*
@@ -507,8 +492,8 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
public static final String HTMLDOC_template = PREFIX + "template";
- final String[] style, stylesheet, script, navlinks, head;
- final String header, nav, aside, footer, noResultsMessage;
+ final String[] style, stylesheet, script, navlinks, head, header, nav, aside, footer;
+ final String noResultsMessage;
final boolean nowrap;
final HtmlDocTemplate template;
@@ -526,10 +511,10 @@ public final class HtmlDocSerializerContext extends HtmlSerializerContext {
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);
- footer = ps.getProperty(HTMLDOC_footer, String.class, null);
+ header = ps.getProperty(HTMLDOC_header, String[].class, new String[0]);
+ nav = ps.getProperty(HTMLDOC_nav, String[].class, new String[0]);
+ aside = ps.getProperty(HTMLDOC_aside, String[].class, new String[0]);
+ footer = ps.getProperty(HTMLDOC_footer, String[].class, new String[0]);
nowrap = ps.getProperty(HTMLDOC_nowrap, boolean.class, false);
navlinks = ps.getProperty(HTMLDOC_navlinks, String[].class, new String[0]);
noResultsMessage = ps.getProperty(HTMLDOC_noResultsMessage, String.class, "<p>no results</p>");
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/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 bd59d78..007c260 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
@@ -29,8 +29,8 @@ 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, head;
+ private final String noResultsMessage;
+ private final String[] style, stylesheet, script, navlinks, head, header, nav, aside, footer;
private final boolean nowrap;
private final HtmlDocTemplate template;
@@ -47,10 +47,10 @@ public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession {
super(ctx, args);
ObjectMap p = getProperties();
- header = p.getString(HTMLDOC_header, ctx.nav);
- nav = p.getString(HTMLDOC_nav, ctx.nav);
- aside = p.getString(HTMLDOC_aside, ctx.aside);
- footer = p.getString(HTMLDOC_footer, ctx.footer);
+ header = p.getStringArray(HTMLDOC_header, ctx.nav);
+ nav = p.getStringArray(HTMLDOC_nav, ctx.nav);
+ aside = p.getStringArray(HTMLDOC_aside, ctx.aside);
+ footer = p.getStringArray(HTMLDOC_footer, ctx.footer);
navlinks = p.getStringArray(HTMLDOC_navlinks, ctx.navlinks);
style = p.getStringArray(HTMLDOC_style, ctx.style);
stylesheet = p.getStringArray(HTMLDOC_stylesheet, ctx.stylesheet);
@@ -145,7 +145,7 @@ public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession {
* <jk>null</jk> if not specified.
* Never an empty string.
*/
- public final String getHeader() {
+ public final String[] getHeader() {
return header;
}
@@ -180,7 +180,7 @@ public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession {
* <jk>null</jk> if not specified.
* Never an empty string.
*/
- public final String getNav() {
+ public final String[] getNav() {
return nav;
}
@@ -192,7 +192,7 @@ public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession {
* <jk>null</jk> if not specified.
* Never an empty string.
*/
- public final String getAside() {
+ public final String[] getAside() {
return aside;
}
@@ -204,7 +204,7 @@ public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession {
* <jk>null</jk> if not specified.
* Never an empty string.
*/
- public final String getFooter() {
+ public final String[] getFooter() {
return footer;
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/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 ffaabb5..86044b2 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,10 +24,11 @@ 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);
-
+
+ String[] head = session.getHead();
+ for (int i = 0; i < head.length; i++)
+ w.sIf(i > 0).appendln(2, head[i]);
+
if (hasStyle(session)) {
w.sTag(2, "style").nl(2);
style(session, w, o);
@@ -44,24 +45,22 @@ public class HtmlDocTemplateBasic implements HtmlDocTemplate {
public void style(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception {
String[] stylesheet = session.getStylesheet();
- if (! ArrayUtils.contains("NONE", stylesheet))
- for (String ss : stylesheet)
- w.append(3, "@import ").q().append(session.resolveUri(ss)).q().appendln("; ");
+ for (int i = 0; i < stylesheet.length; i++)
+ w.sIf(i > 0).append(3, "@import ").q().append(session.resolveUri(stylesheet[i])).q().appendln(";");
if (session.isNoWrap())
w.appendln(3, "div.data * {white-space:nowrap;} ");
- if (session.getStyle() != null)
- for (String style : session.getStyle())
- w.append(3, style).appendln(" ");
+ String[] style = session.getStyle();
+ for (int i = 0; i < style.length; i++)
+ w.sIf(i > 0 || stylesheet.length > 0).appendln(3, style[i]);
}
@Override /* HtmlDocTemplate */
public void script(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception {
-
- if (session.getScript() != null)
- for (String script : session.getScript())
- w.append(3, script);
+ String[] script = session.getScript();
+ for (int i = 0; i < script.length; i++)
+ w.sIf(i > 0).appendln(3, script[i]);
}
@Override /* HtmlDocTemplate */
@@ -103,18 +102,18 @@ public class HtmlDocTemplateBasic implements HtmlDocTemplate {
@Override /* HtmlDocTemplate */
public void header(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception {
// Write the title of the page.
- String header = session.getHeader();
- if (exists(header))
- w.append(3, header).nl(3);
+ String[] header = session.getHeader();
+ for (int i = 0; i < header.length; i++)
+ w.sIf(i > 0).appendln(3, header[i]);
}
@Override /* HtmlDocTemplate */
public void nav(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception {
- String nav = session.getNav();
- if (nav != null) {
- if (exists(nav))
- w.append(3, nav).nl(3);
+ String[] nav = session.getNav();
+ if (nav.length > 0) {
+ for (int i = 0; i < nav.length; i++)
+ w.sIf(i > 0).appendln(3, nav[i]);
} else {
String[] links = session.getNavLinks();
if (links.length > 0) {
@@ -142,9 +141,9 @@ public class HtmlDocTemplateBasic implements HtmlDocTemplate {
@Override /* HtmlDocTemplate */
public void aside(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception {
- String aside = session.getAside();
- if (exists(aside))
- w.append(4, aside);
+ String[] aside = session.getAside();
+ for (int i = 0; i < aside.length; i++)
+ w.sIf(i > 0).appendln(4, aside[i]);
}
@Override /* HtmlDocTemplate */
@@ -172,9 +171,9 @@ public class HtmlDocTemplateBasic implements HtmlDocTemplate {
@Override /* HtmlDocTemplate */
public void footer(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception {
- String footer = session.getFooter();
- if (exists(footer))
- w.append(3, footer).nl(3);
+ String[] footer = session.getFooter();
+ for (int i = 0; i < footer.length; i++)
+ w.sIf(i > 0).appendln(3, footer[i]);
}
@Override /* HtmlDocTemplate */
@@ -189,22 +188,22 @@ public class HtmlDocTemplateBasic implements HtmlDocTemplate {
@Override /* HtmlDocTemplate */
public boolean hasHeader(HtmlDocSerializerSession session) {
- return exists(session.getHeader());
+ return session.getHeader().length > 0;
}
@Override /* HtmlDocTemplate */
public boolean hasNav(HtmlDocSerializerSession session) {
- return exists(session.getNav()) || session.getNavLinks().length > 0;
+ return session.getNav().length > 0 || session.getNavLinks().length > 0;
}
@Override /* HtmlDocTemplate */
public boolean hasAside(HtmlDocSerializerSession session) {
- return exists(session.getAside());
+ return session.getAside().length > 0;
}
@Override /* HtmlDocTemplate */
public boolean hasFooter(HtmlDocSerializerSession session) {
- return exists(session.getFooter());
+ return session.getFooter().length > 0;
}
private static boolean exists(String s) {
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerWriter.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
index 41e76d7..8595fe8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
@@ -277,6 +277,23 @@ public class SerializerWriter extends Writer {
}
/**
+ * Writes a space if the boolean expression is <jk>true</jk> and {@code useWhitespace} is false.
+ *
+ * <p>
+ * Intended for cases in XML where text should be separated by either a space or newline.
+ * This ensures the text is separated by a space if whitespace is disabled.
+ *
+ * @param b The boolean flag.
+ * @return This object (for method chaining).
+ * @throws IOException If a problem occurred trying to write to the writer.
+ */
+ public SerializerWriter sIf(boolean b) throws IOException {
+ if (b && ! useWhitespace)
+ out.write(' ');
+ return this;
+ }
+
+ /**
* Writes a newline to the writer if the {@code useWhitespace} setting is enabled and the boolean flag is true.
*
* @param b The boolean flag.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/ResolvingObjectMap.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/ResolvingObjectMap.java b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/ResolvingObjectMap.java
new file mode 100644
index 0000000..0890e52
--- /dev/null
+++ b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/ResolvingObjectMap.java
@@ -0,0 +1,119 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.svl;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+
+/**
+ * Subclass of an {@link ObjectMap} that automatically resolves any SVL variables in values.
+ *
+ * <p>
+ * Resolves variables in the following values:
+ * <ul>
+ * <li>Values of type {@link CharSequence}.
+ * <li>Arrays containing values of type {@link CharSequence}.
+ * <li>Collections containing values of type {@link CharSequence}.
+ * <li>Maps containing values of type {@link CharSequence}.
+ * </ul>
+ *
+ * <p>
+ * All other data types are left as-is.
+ */
+@SuppressWarnings({"serial","unchecked","rawtypes"})
+public class ResolvingObjectMap extends ObjectMap {
+
+ private final VarResolverSession varResolver;
+
+ /**
+ * Constructor.
+ *
+ * @param varResolver The var resolver session to use for resolving SVL variables.
+ */
+ public ResolvingObjectMap(VarResolverSession varResolver) {
+ super();
+ this.varResolver = varResolver;
+ }
+
+ @Override /* Map */
+ public Object get(Object key) {
+ return resolve(super.get(key));
+ }
+
+ private Object resolve(Object o) {
+ if (o == null)
+ return null;
+ if (o instanceof CharSequence)
+ return varResolver.resolve(o.toString());
+ if (o.getClass().isArray()) {
+ if (! containsVars(o))
+ return o;
+ Object o2 = Array.newInstance(o.getClass().getComponentType(), Array.getLength(o));
+ for (int i = 0; i < Array.getLength(o); i++)
+ Array.set(o2, i, resolve(Array.get(o, i)));
+ return o2;
+ }
+ if (o instanceof Collection) {
+ try {
+ Collection c = (Collection)o;
+ if (! containsVars(c))
+ return o;
+ Collection c2 = c.getClass().newInstance();
+ for (Object o2 : c)
+ c2.add(resolve(o2));
+ return c2;
+ } catch (Exception e) {
+ return o;
+ }
+ }
+ if (o instanceof Map) {
+ try {
+ Map m = (Map)o;
+ if (! containsVars(m))
+ return o;
+ Map m2 = m.getClass().newInstance();
+ for (Map.Entry e : (Set<Map.Entry>)m.entrySet())
+ m2.put(e.getKey(), resolve(e.getValue()));
+ return m2;
+ } catch (Exception e) {
+ return o;
+ }
+ }
+ return o;
+ }
+
+ private static boolean containsVars(Object array) {
+ for (int i = 0; i < Array.getLength(array); i++) {
+ Object o = Array.get(array, i);
+ if (o instanceof CharSequence && o.toString().contains("$"))
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean containsVars(Collection c) {
+ for (Object o : c)
+ if (o instanceof CharSequence && o.toString().contains("$"))
+ return true;
+ return false;
+ }
+
+ private static boolean containsVars(Map m) {
+ for (Object o : m.values())
+ if (o instanceof CharSequence && o.toString().contains("$"))
+ return true;
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/HtmlDocTest.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/HtmlDocTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/HtmlDocTest.java
index d3c337b..976b83b 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/HtmlDocTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/HtmlDocTest.java
@@ -64,7 +64,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/test1");
assertEquals("header1a header1b", header(r));
assertEquals("script1a script1b", script(r));
- assertEquals("@import '/testHtmlDoc/stylesheet1'; style1a style1b ", style(r));
+ assertEquals("@import '/testHtmlDoc/stylesheet1'; style1a style1b", style(r));
assertEquals("nav1a nav1b", nav(r));
assertEquals("aside1a aside1b", aside(r));
assertEquals("footer1a footer1b", footer(r));
@@ -89,7 +89,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/test2");
assertEquals("header2a header2b", header(r));
assertEquals("script2a script2b", script(r));
- assertEquals("@import '/testHtmlDoc/stylesheet2'; style2a style2b ", style(r));
+ assertEquals("@import '/testHtmlDoc/stylesheet2'; style2a style2b", style(r));
assertEquals("nav2a nav2b", nav(r));
assertEquals("aside2a aside2b", aside(r));
assertEquals("footer2a footer2b", footer(r));
@@ -113,7 +113,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/test3");
assertEquals("header1a header1b header3a header3b", header(r));
assertEquals("script1a script1b script3a script3b", script(r));
- assertEquals("@import '/testHtmlDoc/stylesheet1'; style1a style1b style3a style3b ", style(r));
+ assertEquals("@import '/testHtmlDoc/stylesheet1'; style1a style1b style3a style3b", style(r));
assertEquals("nav1a nav1b nav3a nav3b", nav(r));
assertEquals("aside1a aside1b aside3a aside3b", aside(r));
assertEquals("footer1a footer1b footer3a footer3b", footer(r));
@@ -137,7 +137,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/test4");
assertEquals("header4a header1a header1b header4b", header(r));
assertEquals("script4a script1a script1b script4b", script(r));
- assertEquals("@import '/testHtmlDoc/stylesheet1'; style4a style1a style1b style4b ", style(r));
+ assertEquals("@import '/testHtmlDoc/stylesheet1'; style4a style1a style1b style4b", style(r));
assertEquals("nav4a nav1a nav1b nav4b", nav(r));
assertEquals("aside4a aside1a aside1b aside4b", aside(r));
assertEquals("footer4a footer1a footer1b footer4b", footer(r));
@@ -161,7 +161,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/test5");
assertEquals("header5a header5b header1a header1b", header(r));
assertEquals("script5a script5b script1a script1b", script(r));
- assertEquals("@import '/testHtmlDoc/stylesheet1'; style5a style5b style1a style1b ", style(r));
+ assertEquals("@import '/testHtmlDoc/stylesheet1'; style5a style5b style1a style1b", style(r));
assertEquals("nav5a nav5b nav1a nav1b", nav(r));
assertEquals("aside5a aside5b aside1a aside1b", aside(r));
assertEquals("footer5a footer5b footer1a footer1b", footer(r));
@@ -186,7 +186,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/testHtmlDoc2/test11");
assertEquals("header11a header11b header1a header1b", header(r));
assertEquals("script11a script11b", script(r));
- assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style11a style11b ", style(r));
+ assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style11a style11b", style(r));
assertEquals("nav1a nav1b nav11a nav11b", nav(r));
assertEquals("aside1a aside1b aside11a aside11b", aside(r));
assertEquals("footer11a footer1a footer1b footer11b", footer(r));
@@ -211,7 +211,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/testHtmlDoc2/test12");
assertEquals("header12a header12b", header(r));
assertEquals("script12a script12b", script(r));
- assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet12'; style12a style12b ", style(r));
+ assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet12'; style12a style12b", style(r));
assertEquals("nav12a nav12b", nav(r));
assertEquals("aside12a aside12b", aside(r));
assertEquals("footer12a footer12b", footer(r));
@@ -235,7 +235,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/testHtmlDoc2/test13");
assertEquals("header11a header11b header1a header1b header13a header13b", header(r));
assertEquals("script11a script11b script13a script13b", script(r));
- assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style11a style11b style13a style13b ", style(r));
+ assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style11a style11b style13a style13b", style(r));
assertEquals("nav1a nav1b nav11a nav11b nav13a nav13b", nav(r));
assertEquals("aside1a aside1b aside11a aside11b aside13a aside13b", aside(r));
assertEquals("footer11a footer1a footer1b footer11b footer13a footer13b", footer(r));
@@ -259,7 +259,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/testHtmlDoc2/test14");
assertEquals("header14a header11a header11b header1a header1b header14b", header(r));
assertEquals("script14a script11a script11b script14b", script(r));
- assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style14a style11a style11b style14b ", style(r));
+ assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style14a style11a style11b style14b", style(r));
assertEquals("nav14a nav1a nav1b nav11a nav11b nav14b", nav(r));
assertEquals("aside14a aside1a aside1b aside11a aside11b aside14b", aside(r));
assertEquals("footer14a footer11a footer1a footer1b footer11b footer14b", footer(r));
@@ -283,7 +283,7 @@ public class HtmlDocTest extends RestTestcase {
String r = get("/testHtmlDoc/testHtmlDoc2/test15");
assertEquals("header15a header15b header11a header11b header1a header1b", header(r));
assertEquals("script15a script15b script11a script11b", script(r));
- assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style15a style15b style11a style11b ", style(r));
+ assertEquals("@import '/testHtmlDoc/testHtmlDoc2/stylesheet11'; style15a style15b style11a style11b", style(r));
assertEquals("nav15a nav15b nav1a nav1b nav11a nav11b", nav(r));
assertEquals("aside15a aside15b aside1a aside1b aside11a aside11b", aside(r));
assertEquals("footer15a footer15b footer11a footer1a footer1b footer11b", footer(r));
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/PropertiesTest.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/PropertiesTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/PropertiesTest.java
index f52a564..96cbfb4 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/PropertiesTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/PropertiesTest.java
@@ -30,14 +30,4 @@ public class PropertiesTest extends RestTestcase {
String r = client.doGet(URL + "/testPropertiesDefinedOnMethod").getResponseAsString();
assertTrue(r.matches("A1=a1,A2=c,B1=b1,B2=c,C=c,R1a=.*/testProperties/testPropertiesDefinedOnMethod,R1b=.*/testProperties,R2=bar,R3=baz,R4=a1,R5=c,R6=c"));
}
-
- //====================================================================================================
- // Make sure attributes/parameters/headers are available through ctx.getProperties().
- //====================================================================================================
- @Test
- public void testProperties() throws Exception {
- RestClient client = TestMicroservice.DEFAULT_CLIENT;
- String r = client.doGet(URL + "/testProperties/a1?P=p1").header("H", "h1").getResponseAsString();
- assertEquals("A=a1,P=p1,H=h1", r);
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/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 55ec42c..7880746 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
@@ -28,9 +28,11 @@ import javax.servlet.http.*;
import org.apache.juneau.*;
import org.apache.juneau.dto.swagger.*;
import org.apache.juneau.encoders.*;
+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 +65,7 @@ class CallMethod implements Comparable<CallMethod> {
private final Response[] responses;
private final RestContext context;
private final BeanContext beanContext;
- private final HtmlDocContext htmlDocContext;
+ 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);
@@ -95,7 +97,7 @@ class CallMethod implements Comparable<CallMethod> {
this.priority = b.priority;
this.parameters = b.parameters;
this.responses = b.responses;
- this.htmlDocContext = new HtmlDocContext(method, context.getHtmlDocContext());
+ this.widgets = Collections.unmodifiableMap(b.widgets);
}
private static class Builder {
@@ -117,6 +119,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 {
String sig = method.getDeclaringClass().getName() + '.' + method.getName();
@@ -145,7 +148,7 @@ class CallMethod implements Comparable<CallMethod> {
urlEncodingParser = context.getUrlEncodingParser();
beanContext = context.getBeanContext();
encoders = context.getEncoders();
- properties = context.getProperties();
+ properties = new ObjectMap().setInner(context.getProperties());
defaultCharset = context.getDefaultCharset();
String paramFormat = context.getParamFormat();
@@ -154,6 +157,19 @@ class CallMethod implements Comparable<CallMethod> {
if (! m.paramFormat().isEmpty())
paramFormat = context.getVarResolver().resolve(m.paramFormat());
+ HtmlDocBuilder hdb = new HtmlDocBuilder(properties);
+
+ HtmlDoc hd = m.htmldoc();
+ hdb.process(hd);
+
+ widgets = new HashMap<String,Widget>(context.getWidgets());
+ for (Class<? extends Widget> wc : hd.widgets()) {
+ Widget w = ClassUtils.newInstance(Widget.class, wc);
+ widgets.put(w.getName(), w);
+ hdb.script("INHERIT", "$W{"+w.getName()+".script}");
+ hdb.style("INHERIT", "$W{"+w.getName()+".style}");
+ }
+
List<Inherit> si = Arrays.asList(m.serializersInherit());
List<Inherit> pi = Arrays.asList(m.parsersInherit());
@@ -461,10 +477,6 @@ class CallMethod implements Comparable<CallMethod> {
return null;
}
- HtmlDocContext getHtmlDocContext() {
- return htmlDocContext;
- }
-
/**
* Returns the localized Swagger tags for this Java method.
*/
@@ -749,9 +761,10 @@ class CallMethod implements Comparable<CallMethod> {
req.getPathMatch().put(pathPattern.getVars()[i], patternVals[i]);
req.getPathMatch().setRemainder(remainder);
- ObjectMap requestProperties = createRequestProperties(properties, req);
+ ObjectMap requestProperties = new ResolvingObjectMap(req.getVarResolverSession()).setInner(properties);
+
req.init(method, requestProperties, defaultRequestHeaders, defaultQuery, defaultFormData, defaultCharset,
- serializers, parsers, urlEncodingParser, beanContext, encoders, htmlDocContext.widgets, htmlDocContext);
+ serializers, parsers, urlEncodingParser, beanContext, encoders, widgets);
res.init(requestProperties, defaultCharset, serializers, urlEncodingSerializer, encoders);
// Class-level guards
@@ -828,38 +841,6 @@ class CallMethod implements Comparable<CallMethod> {
return SC_OK;
}
- /**
- * This method creates all the request-time properties.
- */
- ObjectMap createRequestProperties(final ObjectMap methodProperties, final RestRequest req) {
- @SuppressWarnings("serial")
- ObjectMap m = new ObjectMap() {
- @Override /* Map */
- public Object get(Object key) {
- Object o = super.get(key);
- if (o == null) {
- String k = key.toString();
- int i = k.indexOf('.');
- if (i != -1) {
- String prefix = k.substring(0, i);
- String remainder = k.substring(i+1);
- Object v = req.resolveProperty(CallMethod.this, prefix, remainder);
- if (v != null)
- return v;
- }
- o = req.getPathMatch().get(k);
- if (o == null)
- o = req.getHeader(k);
- }
- if (o instanceof String)
- o = req.getVarResolverSession().resolve(o.toString());
- return o;
- }
- };
- m.setInner(methodProperties);
- return m;
- }
-
@Override /* Object */
public String toString() {
return "SimpleMethod: name=" + httpMethod + ", path=" + pathPattern.getPatternString();
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocBuilder.java
index 99c6a3b..2eab1ec 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocBuilder.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocBuilder.java
@@ -14,8 +14,12 @@ package org.apache.juneau.rest;
import static org.apache.juneau.html.HtmlDocSerializerContext.*;
+import java.util.*;
+import java.util.regex.*;
+
import org.apache.juneau.*;
import org.apache.juneau.html.*;
+import org.apache.juneau.internal.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.utils.*;
@@ -23,7 +27,15 @@ import org.apache.juneau.utils.*;
* Programmatic interface for setting properties used by the HtmlDoc serializer.
*
* <p>
- * This class is instantiated by calling the {@link RestResponse#getHtmlDocBuilder()} method.
+ * Basically just a convenience wrapper around the servlet or method level properties for setting properties defined
+ * by the {@link HtmlDocSerializerContext} class.
+ *
+ * <p>
+ * This class is instantiated through the following methods.
+ * <ul>
+ * <li>{@link RestConfig#getHtmlDocBuilder()} - Set values programmatically during servlet initialization.
+ * <li>{@link RestResponse#getHtmlDocBuilder()} - Set values programmatically during a REST request.
+ * </ul>
*/
public class HtmlDocBuilder {
@@ -33,6 +45,33 @@ public class HtmlDocBuilder {
this.properties = properties;
}
+ void process(HtmlDoc hd) {
+ if (hd.header().length > 0)
+ header((Object[])hd.header());
+ if (hd.nav().length > 0)
+ nav((Object[])hd.nav());
+ if (hd.aside().length > 0)
+ aside((Object[])hd.aside());
+ if (hd.footer().length > 0)
+ footer((Object[])hd.footer());
+ if (hd.style().length > 0)
+ style((Object[])hd.style());
+ if (hd.script().length > 0)
+ script((Object[])hd.script());
+ if (hd.navlinks().length > 0)
+ navlinks((Object[])hd.navlinks());
+ if (hd.head().length > 0)
+ head((Object[])hd.head());
+ if (hd.stylesheet().length > 0)
+ stylesheet((Object[])hd.stylesheet());
+ if (! hd.noResultsMessage().isEmpty())
+ noResultsMessage(hd.noResultsMessage());
+ if (hd.nowrap())
+ nowrap(true);
+ if (hd.template() != HtmlDocTemplate.class)
+ template(hd.template());
+ }
+
/**
* Sets the HTML header section contents.
*
@@ -44,7 +83,8 @@ public class HtmlDocBuilder {
* to be whatever you want.
*
* <p>
- * A value of <js>"NONE"</js> can be used to force no header.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>A value of <js>"NONE"</js> can be used to force no value.
*
* <p>
* This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
@@ -64,8 +104,8 @@ public class HtmlDocBuilder {
* </ul>
* @return This object (for method chaining).
*/
- public HtmlDocBuilder header(Object value) {
- return set(HTMLDOC_header, value);
+ public HtmlDocBuilder header(Object...value) {
+ return set(HTMLDOC_header, resolveList(value, properties.getStringArray(HTMLDOC_header)));
}
/**
@@ -83,7 +123,8 @@ public class HtmlDocBuilder {
* <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.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>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}.
@@ -102,7 +143,7 @@ public class HtmlDocBuilder {
* @return This object (for method chaining).
*/
public HtmlDocBuilder navlinks(Object...value) {
- return set(HTMLDOC_navlinks, value);
+ return set(HTMLDOC_navlinks, resolveLinks(value, properties.getStringArray(HTMLDOC_navlinks)));
}
/**
@@ -125,7 +166,8 @@ public class HtmlDocBuilder {
* <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.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>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.
@@ -141,8 +183,8 @@ public class HtmlDocBuilder {
* </ul>
* @return This object (for method chaining).
*/
- public HtmlDocBuilder nav(Object value) {
- return set(HTMLDOC_nav, value);
+ public HtmlDocBuilder nav(Object...value) {
+ return set(HTMLDOC_nav, resolveList(value, properties.getStringArray(HTMLDOC_nav)));
}
/**
@@ -159,7 +201,8 @@ public class HtmlDocBuilder {
* <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.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>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.
@@ -175,8 +218,8 @@ public class HtmlDocBuilder {
* </ul>
* @return This object (for method chaining).
*/
- public HtmlDocBuilder aside(Object value) {
- return set(HTMLDOC_aside, value);
+ public HtmlDocBuilder aside(Object...value) {
+ return set(HTMLDOC_aside, resolveList(value, properties.getStringArray(HTMLDOC_aside)));
}
/**
@@ -193,7 +236,8 @@ public class HtmlDocBuilder {
* <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.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>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.
@@ -209,8 +253,8 @@ public class HtmlDocBuilder {
* </ul>
* @return This object (for method chaining).
*/
- public HtmlDocBuilder footer(Object value) {
- return set(HTMLDOC_footer, value);
+ public HtmlDocBuilder footer(Object...value) {
+ return set(HTMLDOC_footer, resolveList(value, properties.getStringArray(HTMLDOC_footer)));
}
/**
@@ -224,7 +268,8 @@ public class HtmlDocBuilder {
* <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.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>A value of <js>"NONE"</js> can be used to force no value.
*
* <p>
* This is the programmatic equivalent to the {@link HtmlDoc#style() @HtmlDoc.style()} annotation.
@@ -240,8 +285,8 @@ public class HtmlDocBuilder {
* </ul>
* @return This object (for method chaining).
*/
- public HtmlDocBuilder style(Object value) {
- return set(HTMLDOC_style, value);
+ public HtmlDocBuilder style(Object...value) {
+ return set(HTMLDOC_style, resolveList(value, properties.getStringArray(HTMLDOC_style)));
}
/**
@@ -275,8 +320,8 @@ public class HtmlDocBuilder {
* </ul>
* @return This object (for method chaining).
*/
- public HtmlDocBuilder stylesheet(Object value) {
- return set(HTMLDOC_stylesheet, value);
+ public HtmlDocBuilder stylesheet(Object...value) {
+ return set(HTMLDOC_stylesheet, resolveSet(value, properties.getStringArray(HTMLDOC_nav)));
}
/**
@@ -290,7 +335,8 @@ public class HtmlDocBuilder {
* <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.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>A value of <js>"NONE"</js> can be used to force no value.
*
* <p>
* This is the programmatic equivalent to the {@link HtmlDoc#script() @HtmlDoc.script()} annotation.
@@ -306,8 +352,8 @@ public class HtmlDocBuilder {
* </ul>
* @return This object (for method chaining).
*/
- public HtmlDocBuilder script(Object value) {
- return set(HTMLDOC_script, value);
+ public HtmlDocBuilder script(Object...value) {
+ return set(HTMLDOC_script, resolveList(value, properties.getStringArray(HTMLDOC_script)));
}
/**
@@ -321,7 +367,8 @@ public class HtmlDocBuilder {
* <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.
+ * A value of <js>"INHERIT"</js> means copy the values from the parent.
+ * <br>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.
@@ -337,7 +384,7 @@ public class HtmlDocBuilder {
* @return This object (for method chaining).
*/
public HtmlDocBuilder head(Object...value) {
- return set(HTMLDOC_head, value);
+ return set(HTMLDOC_head, resolveList(value, properties.getStringArray(HTMLDOC_head)));
}
/**
@@ -401,6 +448,60 @@ public class HtmlDocBuilder {
return set(HTMLDOC_template, value);
}
+ private static final Pattern INDEXED_LINK_PATTERN = Pattern.compile("(?s)(\\S*)\\[(\\d+)\\]\\:(.*)");
+
+ private static String[] resolveLinks(Object[] value, String[] prev) {
+ List<String> list = new ArrayList<String>();
+ for (Object v : value) {
+ String s = StringUtils.toString(v);
+ if ("INHERIT".equals(s)) {
+ list.addAll(Arrays.asList(prev));
+ } else if (s.indexOf('[') != -1 && INDEXED_LINK_PATTERN.matcher(s).matches()) {
+ Matcher lm = INDEXED_LINK_PATTERN.matcher(s);
+ lm.matches();
+ String key = lm.group(1);
+ int index = Math.min(list.size(), Integer.parseInt(lm.group(2)));
+ String remainder = lm.group(3);
+ list.add(index, key.isEmpty() ? remainder : key + ":" + remainder);
+ } else {
+ list.add(s);
+ }
+ }
+ return list.toArray(new String[list.size()]);
+ }
+
+ private static String[] resolveSet(Object[] value, String[] prev) {
+ Set<String> set = new HashSet<>();
+ for (Object v : value) {
+ String s = StringUtils.toString(v);
+ if ("INHERIT".equals(s)) {
+ if (prev != null)
+ set.addAll(Arrays.asList(prev));
+ } else if ("NONE".equals(s)) {
+ return new String[0];
+ } else {
+ set.add(s);
+ }
+ }
+ return set.toArray(new String[set.size()]);
+ }
+
+ private static String[] resolveList(Object[] value, String[] prev) {
+ List<String> set = new LinkedList<>();
+ for (Object v : value) {
+ String s = StringUtils.toString(v);
+ if ("INHERIT".equals(s)) {
+ if (prev != null)
+ set.addAll(Arrays.asList(prev));
+ } else if ("NONE".equals(s)) {
+ return new String[0];
+ } else {
+ set.add(s);
+ }
+ }
+ return set.toArray(new String[set.size()]);
+ }
+
private HtmlDocBuilder set(String key, Object value) {
properties.put(key, value);
return this;
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocConfig.java
----------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocConfig.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocConfig.java
deleted file mode 100644
index 0397198..0000000
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocConfig.java
+++ /dev/null
@@ -1,456 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
-// * with the License. You may obtain a copy of the License at *
-// * *
-// * http://www.apache.org/licenses/LICENSE-2.0 *
-// * *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
-// * specific language governing permissions and limitations under the License. *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest;
-
-import static org.apache.juneau.rest.RestUtils.*;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.html.*;
-import org.apache.juneau.internal.*;
-import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.widget.*;
-import org.apache.juneau.utils.*;
-
-/**
- * Programmatic interface for setting properties used by the HtmlDoc serializer.
- */
-public class HtmlDocConfig {
-
- String header, nav, aside, footer, style, stylesheet, script, noResultsMessage;
- String[] navlinks, head;
- boolean nowrap;
- Object template = HtmlDocTemplateBasic.class;
- List<Class<? extends Widget>> widgets = new ArrayList<Class<? extends Widget>>();
-
- HtmlDocConfig process(HtmlDoc hd) {
- for (Class<? extends Widget> cw : hd.widgets())
- widget(cw);
- header(resolveNewlineSeparatedAnnotation(hd.header(), header));
- nav(resolveNewlineSeparatedAnnotation(hd.nav(), nav));
- aside(resolveNewlineSeparatedAnnotation(hd.aside(), aside));
- footer(resolveNewlineSeparatedAnnotation(hd.footer(), footer));
- style(resolveNewlineSeparatedAnnotation(hd.style(), style));
- script(resolveNewlineSeparatedAnnotation(hd.script(), script));
- navlinks((Object[])resolveLinks(hd.navlinks(), navlinks));
- head((Object[])resolveContent(hd.head(), head));
-
- if (! hd.stylesheet().isEmpty())
- stylesheet(hd.stylesheet());
- if (! hd.noResultsMessage().isEmpty())
- noResultsMessage(hd.noResultsMessage());
- if (hd.nowrap())
- nowrap(true);
- if (hd.template() != HtmlDocTemplate.class)
- template(hd.template());
-
- return this;
- }
-
- /**
- * 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>
- * 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>).
- * <br>See {@link RestContext#getVarResolver()} for the list of supported variables.
- *
- * <p>
- * This is the programmatic equivalent to the {@link HtmlDoc#header() @HtmlDoc.header()} annotation.
- *
- * @param value
- * The HTML header section contents.
- * Object will be converted to a string using {@link Object#toString()}.
- * <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 HtmlDocConfig header(Object value) {
- header = StringUtils.toString(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>).
- * <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 field can also use URIs of any support type in {@link UriResolver}.
- *
- * <p>
- * This is the programmatic equivalent to the {@link HtmlDoc#navlinks() @HtmlDoc.navlinks()} annotation.
- *
- * @param value
- * The HTML nav section links links.
- * <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 HtmlDocConfig navlinks(Object...value) {
- navlinks = StringUtils.toStrings(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 #navlinks(Object[])} value will be ignored.
- *
- * <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#nav() @HtmlDoc.nav()} annotation.
- *
- * @param value
- * The HTML nav section contents.
- * Object will be converted to a string using {@link Object#toString()}.
- * <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 HtmlDocConfig nav(Object value) {
- this.nav = StringUtils.toString(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>).
- * <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#aside() @HtmlDoc.aside()} annotation.
- *
- * @param value
- * The HTML aside section contents.
- * Object will be converted to a string using {@link Object#toString()}.
- * <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 HtmlDocConfig aside(Object value) {
- this.aside = StringUtils.toString(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>).
- * <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#footer() @HtmlDoc.footer()} annotation.
- *
- * @param value
- * The HTML footer section contents.
- * Object will be converted to a string using {@link Object#toString()}.
- * <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 HtmlDocConfig footer(Object value) {
- this.footer = StringUtils.toString(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>).
- * <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#style() @HtmlDoc.style()} annotation.
- *
- * @param value
- * The HTML CSS style section contents.
- * Object will be converted to a string using {@link Object#toString()}.
- * <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 HtmlDocConfig style(Object value) {
- this.style = StringUtils.toString(value);
- return this;
- }
-
- /**
- * Sets the CSS URL in the HTML CSS style section.
- *
- * <p>
- * The format of this value is a comma-delimited list of URLs.
- *
- * <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}.
- * <br>See {@link RestContext#getVarResolver()} for the list of supported variables.
- *
- * <p>
- * This is the programmatic equivalent to the {@link HtmlDoc#stylesheet() @HtmlDoc.stylesheet()} annotation.
- *
- * @param value
- * The CSS URL in the HTML CSS style section.
- * Object will be converted to a string using {@link Object#toString()}.
- * <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 HtmlDocConfig stylesheet(Object value) {
- this.stylesheet = StringUtils.toString(value);
- return this;
- }
-
- /**
- * Sets the HTML script section contents.
- *
- * <p>
- * The format of this value is Javascript.
- *
- * <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#script() @HtmlDoc.script()} annotation.
- *
- * @param value
- * The HTML script section contents.
- * Object will be converted to a string using {@link Object#toString()}.
- * <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 HtmlDocConfig script(Object value) {
- this.script = StringUtils.toString(value);
- return this;
- }
-
- /**
- * 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 HtmlDocConfig head(Object...value) {
- this.head = StringUtils.toStrings(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 HtmlDocConfig nowrap(boolean value) {
- this.nowrap = 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 HtmlDocConfig noResultsMessage(Object value) {
- this.noResultsMessage = StringUtils.toString(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 HtmlDocConfig template(Class<? extends HtmlDocTemplate> value) {
- this.template = 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 HtmlDocConfig template(HtmlDocTemplate value) {
- this.template = value;
- return this;
- }
-
- /**
- * 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>
- * Widgets are inherited from parent to child, but can be overridden by reusing the widget name.
- *
- * @param value The widget class to add.
- * @return This object (for method chaining).
- */
- public HtmlDocConfig widget(Class<? extends Widget> value) {
- this.widgets.add(value);
- return this;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocContext.java
----------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocContext.java
deleted file mode 100644
index 9f3809e..0000000
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/HtmlDocContext.java
+++ /dev/null
@@ -1,171 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
-// * with the License. You may obtain a copy of the License at *
-// * *
-// * http://www.apache.org/licenses/LICENSE-2.0 *
-// * *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
-// * specific language governing permissions and limitations under the License. *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest;
-
-import static org.apache.juneau.rest.RestUtils.*;
-
-import java.util.*;
-
-import org.apache.juneau.html.*;
-import org.apache.juneau.internal.*;
-import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.widget.*;
-
-/**
- * Programmatic interface for set properties used by the HtmlDoc serializer.
- */
-public final class HtmlDocContext {
-
- final String header, nav, aside, style, stylesheet, script, footer, noResultsMessage;
- final String[] navlinks, head;
- final boolean nowrap;
- final HtmlDocTemplate template;
- final Map<String,Widget> widgets;
-
- HtmlDocContext(Object resource, RestConfig config) throws RestServletException {
- try {
- Builder b = new Builder(resource, config);
-
- this.header = b.header;
- this.nav = b.nav;
- this.aside = b.aside;
- this.style = b.style;
- this.stylesheet = b.stylesheet;
- this.script = b.script;
- this.footer = b.footer;
- this.noResultsMessage = b.noResultsMessage;
- this.navlinks = b.navlinks;
- this.head = b.head;
- this.nowrap = b.nowrap;
- this.widgets = Collections.unmodifiableMap(b.widgets);
- this.template = b.template;
- } catch (RestServletException e) {
- throw e;
- } catch (Exception e) {
- throw new RestServletException("Exception occurred while initializing resource ''{0}''", resource.getClass().getSimpleName()).initCause(e);
- }
- }
-
- HtmlDocContext(java.lang.reflect.Method method, HtmlDocContext pc) throws RestServletException {
- try {
- Builder b = new Builder(method, pc);
- this.header = b.header;
- this.nav = b.nav;
- this.aside = b.aside;
- this.style = b.style;
- this.stylesheet = b.stylesheet;
- this.script = b.script;
- this.footer = b.footer;
- this.noResultsMessage = b.noResultsMessage;
- this.navlinks = b.navlinks;
- this.head = b.head;
- this.nowrap = b.nowrap;
- this.widgets = Collections.unmodifiableMap(b.widgets);
- this.template = b.template;
- } catch (RestServletException e) {
- throw e;
- } catch (Exception e) {
- String sig = method.getDeclaringClass().getName() + '.' + method.getName();
- throw new RestServletException("Exception occurred while initializing method ''{0}''", sig).initCause(e);
- }
- }
-
-
- static class Builder {
-
- String header, nav, aside, style, stylesheet, script, footer, noResultsMessage;
- String[] navlinks, head;
- boolean nowrap;
- HtmlDocTemplate template;
- Map<String,Widget> widgets;
-
-
- Builder(java.lang.reflect.Method method, HtmlDocContext pc) throws Exception {
- String sig = method.getDeclaringClass().getName() + '.' + method.getName();
-
- try {
- RestMethod m = method.getAnnotation(RestMethod.class);
- if (m == null)
- throw new RestServletException("@RestMethod annotation not found on method ''{0}''", sig);
-
- HtmlDoc hd = m.htmldoc();
-
- widgets = new HashMap<String,Widget>(pc.widgets);
- for (Class<? extends Widget> wc : hd.widgets()) {
- Widget w = ClassUtils.newInstance(Widget.class, wc);
- widgets.put(w.getName(), w);
- }
-
- header = resolveNewlineSeparatedAnnotation(hd.header(), pc.header);
- nav = resolveNewlineSeparatedAnnotation(hd.nav(), pc.nav);
- aside = resolveNewlineSeparatedAnnotation(hd.aside(), pc.aside);
- footer = resolveNewlineSeparatedAnnotation(hd.footer(), pc.footer);
- style = resolveNewlineSeparatedAnnotation(hd.style(), pc.style);
- script = resolveNewlineSeparatedAnnotation(hd.script(), pc.script);
- head = resolveContent(hd.head(), pc.head);
- navlinks = resolveLinks(hd.navlinks(), pc.navlinks);
- stylesheet = hd.stylesheet().isEmpty() ? pc.stylesheet : hd.stylesheet();
- nowrap = hd.nowrap() ? hd.nowrap() : pc.nowrap;
- noResultsMessage = hd.noResultsMessage().isEmpty() ? pc.noResultsMessage : hd.noResultsMessage();
- template =
- hd.template() == HtmlDocTemplate.class
- ? pc.template
- : ClassUtils.newInstance(HtmlDocTemplate.class, hd.template());
- } catch (RestServletException e) {
- throw e;
- } catch (Exception e) {
- throw new RestServletException("Exception occurred while initializing method ''{0}''", sig).initCause(e);
- }
- }
-
-
- Builder(Object resource, RestConfig sc) throws Exception {
-
- HtmlDocConfig hdc = sc.htmlDocConfig;
-
- this.widgets = new LinkedHashMap<String,Widget>();
- for (Class<? extends Widget> wc : hdc.widgets) {
- Widget w = resolve(resource, Widget.class, wc);
- this.widgets.put(w.getName(), w);
- }
-
- header = hdc.header;
- navlinks = hdc.navlinks;
- nav = hdc.nav;
- aside = hdc.aside;
- style = hdc.style;
- stylesheet = hdc.stylesheet;
- script = hdc.script;
- head = hdc.head;
- footer = hdc.footer;
- nowrap = hdc.nowrap;
- noResultsMessage = hdc.noResultsMessage;
- template = resolve(resource, HtmlDocTemplate.class, hdc.template);
- }
- }
-
- //----------------------------------------------------------------------------------------------------
- // Utility methods
- //----------------------------------------------------------------------------------------------------
-
- /**
- * Takes in an object of type T or a Class<T> and either casts or constructs a T.
- */
- private static <T> T resolve(Object outer, Class<T> c, Object o, Object...cArgs) throws RestServletException {
- try {
- return ClassUtils.newInstanceFromOuter(outer, c, o, cArgs);
- } catch (Exception e) {
- throw new RestServletException("Exception occurred while constructing class ''{0}''", c).initCause(e);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/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 ca8e558..3255041 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
@@ -33,6 +33,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.*;
@@ -113,7 +114,8 @@ public class RestConfig implements ServletConfig {
String path;
String clientVersionHeader = "X-Client-Version";
String contextPath;
- HtmlDocConfig htmlDocConfig = new HtmlDocConfig();
+ HtmlDocBuilder htmlDocBuilder;
+ List<Class<? extends Widget>> widgets = new ArrayList<Class<? extends Widget>>();
Object resourceResolver = RestResourceResolverSimple.class;
Object logger = RestLogger.Normal.class;
@@ -156,6 +158,7 @@ public class RestConfig implements ServletConfig {
ConfigFileBuilder cfb = new ConfigFileBuilder();
properties = new ObjectMap();
+ htmlDocBuilder = new HtmlDocBuilder(properties);
configFile = cfb.build();
varResolverBuilder = new VarResolverBuilder()
.vars(
@@ -245,7 +248,11 @@ public class RestConfig implements ServletConfig {
if (! r.paramFormat().isEmpty())
setParamFormat(vr.resolve(r.paramFormat()));
- htmlDocConfig.process(r.htmldoc());
+ HtmlDoc hd = r.htmldoc();
+ for (Class<? extends Widget> cw : hd.widgets())
+ this.widgets.add(cw);
+
+ htmlDocBuilder.process(hd);
}
addResponseHandlers(
@@ -1176,12 +1183,27 @@ public class RestConfig implements ServletConfig {
}
/**
- * Returns the configuration settings specific to the HTML doc view.
+ * 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>
+ * Widgets are inherited from parent to child, but can be overridden by reusing the widget name.
*
- * @return The configuration settings specific to the HTML doc view.
+ * @param value The widget class to add.
+ * @return This object (for method chaining).
+ */
+ public RestConfig addWidget(Class<? extends Widget> value) {
+ this.widgets.add(value);
+ return this;
+ }
+
+ /**
+ * Returns an instance of an HTMLDOC builder for setting HTMLDOC-related properties.
+ *
+ * @return An instance of an HTMLDOC builder for setting HTMLDOC-related properties.
*/
- public HtmlDocConfig getHtmlDocConfig() {
- return htmlDocConfig;
+ public HtmlDocBuilder getHtmlDocBuilder() {
+ return htmlDocBuilder;
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9c746e64/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 ef9200b..5515e48 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
@@ -41,6 +41,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.svl.vars.*;
@@ -69,7 +70,7 @@ public final class RestContext extends Context {
fullPath,
contextPath;
- private final HtmlDocContext htmlDocContext;
+ private final Map<String,Widget> widgets;
private final Set<String> allowMethodParams;
@@ -190,7 +191,7 @@ public final class RestContext extends Context {
this.logger = b.logger;
this.fullPath = b.fullPath;
this.contextPath = nullIfEmpty(b.contextPath);
- this.htmlDocContext = new HtmlDocContext(resource, config);
+ this.widgets = Collections.unmodifiableMap(b.widgets);
//----------------------------------------------------------------------------------------------------
// Initialize the child resources.
@@ -471,6 +472,7 @@ public final class RestContext extends Context {
Set<String> allowMethodParams = new LinkedHashSet<String>();
RestLogger logger;
String fullPath;
+ Map<String,Widget> widgets;
Object resourceResolver;
String contextPath;
@@ -573,6 +575,18 @@ public final class RestContext extends Context {
logger = sc.logger == null ? new RestLogger.NoOp() : resolve(resource, RestLogger.class, sc.logger);
fullPath = (sc.parentContext == null ? "" : (sc.parentContext.fullPath + '/')) + sc.path;
+
+ HtmlDocBuilder hdb = new HtmlDocBuilder(sc.properties);
+
+ this.widgets = new LinkedHashMap<String,Widget>();
+
+ for (Class<? extends Widget> wc : sc.widgets) {
+ Widget w = resolve(resource, Widget.class, wc);
+ String n = w.getName();
+ this.widgets.put(n, w);
+ hdb.script("INHERIT", "$W{"+n+".script}");
+ hdb.style("INHERIT", "$W{"+n+".style}");
+ }
}
}
@@ -838,12 +852,15 @@ public final class RestContext extends Context {
}
/**
- * Returns the context values for the HTML doc view.
+ * The widgets used for resolving <js>"$W{...}"<js> variables.
+ *
+ * <p>
+ * Defined by the {@link HtmlDoc#widgets()} annotation or {@link RestConfig#addWidget(Class)} method.
*
- * @return The context values for the HTML doc view.
+ * @return The var resolver widgets as a map with keys being the name returned by {@link Widget#getName()}.
*/
- public HtmlDocContext getHtmlDocContext() {
- return htmlDocContext;
+ public Map<String,Widget> getWidgets() {
+ return widgets;
}
/**