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/05/21 05:17:19 UTC
[2/2] incubator-juneau git commit: HtmlRender support.
HtmlRender support.
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/e1a50566
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/e1a50566
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/e1a50566
Branch: refs/heads/master
Commit: e1a505668d7aa4d2aa816f697a8203dfbc4bd8c8
Parents: 9b04bb9
Author: JamesBognar <ja...@apache.org>
Authored: Sun May 21 01:17:14 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Sun May 21 01:17:14 2017 -0400
----------------------------------------------------------------------
.../org/apache/juneau/jena/RdfSerializer.java | 4 +-
.../juneau/jena/RdfSerializerSession.java | 14 +-
.../apache/juneau/utils/StringUtilsTest.java | 28 +
.../utils/UriContextResolutionComboTest.java | 630 +++++++++++++++++++
.../juneau/utils/UriContextUriComboTest.java | 234 +++++++
.../org/apache/juneau/xml/XmlContentTest.java | 8 +-
.../main/java/org/apache/juneau/BeanMap.java | 11 +
.../main/java/org/apache/juneau/UriContext.java | 421 +++++++++++++
.../java/org/apache/juneau/UriRelativity.java | 29 +
.../java/org/apache/juneau/UriResolution.java | 34 +
.../apache/juneau/csv/CsvSerializerSession.java | 14 +-
.../juneau/html/HtmlBeanPropertyMeta.java | 78 ++-
.../apache/juneau/html/HtmlDocSerializer.java | 4 +-
.../juneau/html/HtmlDocSerializerSession.java | 16 +-
.../java/org/apache/juneau/html/HtmlRender.java | 149 +++++
.../juneau/html/HtmlSchemaDocSerializer.java | 4 +-
.../org/apache/juneau/html/HtmlSerializer.java | 38 +-
.../juneau/html/HtmlSerializerSession.java | 16 +-
.../java/org/apache/juneau/html/HtmlWriter.java | 7 +-
.../apache/juneau/html/SimpleHtmlWriter.java | 2 +-
.../org/apache/juneau/html/annotation/Html.java | 35 ++
.../juneau/html/doc-files/HtmlRender_1.png | Bin 0 -> 60161 bytes
.../org/apache/juneau/internal/StringUtils.java | 102 +++
.../juneau/json/JsonSchemaSerializer.java | 4 +-
.../org/apache/juneau/json/JsonSerializer.java | 4 +-
.../juneau/json/JsonSerializerSession.java | 16 +-
.../java/org/apache/juneau/json/JsonWriter.java | 7 +-
.../juneau/msgpack/MsgPackSerializer.java | 4 +-
.../msgpack/MsgPackSerializerSession.java | 14 +-
.../apache/juneau/serializer/Serializer.java | 12 +-
.../juneau/serializer/SerializerSession.java | 45 +-
.../juneau/serializer/SerializerWriter.java | 12 +-
.../juneau/serializer/WriterSerializer.java | 2 +-
.../org/apache/juneau/uon/UonSerializer.java | 4 +-
.../apache/juneau/uon/UonSerializerSession.java | 16 +-
.../java/org/apache/juneau/uon/UonWriter.java | 7 +-
.../urlencoding/UrlEncodingSerializer.java | 6 +-
.../UrlEncodingSerializerSession.java | 14 +-
.../apache/juneau/xml/XmlSchemaSerializer.java | 8 +-
.../org/apache/juneau/xml/XmlSerializer.java | 4 +-
.../apache/juneau/xml/XmlSerializerSession.java | 16 +-
.../java/org/apache/juneau/xml/XmlWriter.java | 7 +-
.../src/main/javadoc/doc-files/HtmlRender_1.png | Bin 0 -> 60161 bytes
juneau-core/src/main/javadoc/overview.html | 3 +
.../juneau/examples/rest/FileSpaceResource.java | 148 +++++
.../juneau/examples/rest/RootResources.java | 1 +
.../apache/juneau/examples/rest/htdocs/ok.png | Bin 0 -> 455 bytes
.../juneau/examples/rest/htdocs/severe.png | Bin 0 -> 335 bytes
.../juneau/examples/rest/htdocs/warning.png | Bin 0 -> 444 bytes
.../juneau/rest/client/RestClientBuilder.java | 2 +-
.../apache/juneau/rest/jaxrs/BaseProvider.java | 4 +-
.../juneau/rest/test/HtmlPropertiesTest.java | 1 -
.../org/apache/juneau/rest/RestRequest.java | 17 +
.../juneau/rest/response/DefaultHandler.java | 4 +-
54 files changed, 2112 insertions(+), 148 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
index 37b7d2c..734f38a 100644
--- a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
+++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
@@ -450,7 +450,7 @@ public class RdfSerializer extends WriterSerializer {
//--------------------------------------------------------------------------------
@Override /* Serializer */
- public RdfSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- return new RdfSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ public RdfSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ return new RdfSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
index 199f144..55060ef 100644
--- a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
+++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
@@ -54,19 +54,21 @@ public final class RdfSerializerSession extends SerializerSession {
* Create a new session using properties specified in the context.
*
* @param ctx The context creating this session object.
- * The context contains all the configuration settings for this object.
+ * The context contains all the configuration settings for this object.
* @param output The output object. See {@link JsonSerializerSession#getWriter()} for valid class types.
* @param op The override properties.
- * These override any context properties defined in the context.
+ * These override any context properties defined in the context.
* @param javaMethod The java method that called this serializer, usually the method in a REST servlet.
* @param locale The session locale.
- * If <jk>null</jk>, then the locale defined on the context is used.
+ * If <jk>null</jk>, then the locale defined on the context is used.
* @param timeZone The session timezone.
- * If <jk>null</jk>, then the timezone defined on the context is used.
+ * If <jk>null</jk>, then the timezone defined on the context is used.
* @param mediaType The session media type (e.g. <js>"application/json"</js>).
+ * @param uriContext The URI context.
+ * Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
*/
- protected RdfSerializerSession(RdfSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ protected RdfSerializerSession(RdfSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ super(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
ObjectMap jenaSettings = new ObjectMap();
jenaSettings.put("rdfXml.tab", isUseWhitespace() ? 2 : 0);
jenaSettings.put("rdfXml.attributeQuoteChar", Character.toString(getQuoteChar()));
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java b/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
index f74d75e..c7c3052 100755
--- a/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
@@ -717,4 +717,32 @@ public class StringUtilsTest {
assertObjectEquals("{'a=':'1'}", splitMap("a\\==1", ',', '=', true));
assertObjectEquals("{'a\\\\':'1'}", splitMap("a\\\\=1", ',', '=', true));
}
+
+ //====================================================================================================
+ // isAbsoluteUri(String)
+ //====================================================================================================
+ @Test
+ public void testIsAbsoluteUri() {
+ assertFalse(isAbsoluteUri(null));
+ assertFalse(isAbsoluteUri(""));
+ assertTrue(isAbsoluteUri("http://foo"));
+ assertTrue(isAbsoluteUri("x://x"));
+ assertFalse(isAbsoluteUri("xX://x"));
+ assertFalse(isAbsoluteUri("x ://x"));
+ assertFalse(isAbsoluteUri("x: //x"));
+ assertFalse(isAbsoluteUri("x:/ /x"));
+ assertFalse(isAbsoluteUri("x:x//x"));
+ assertFalse(isAbsoluteUri("x:/x/x"));
+ }
+
+ //====================================================================================================
+ // getAuthorityUri(String)
+ //====================================================================================================
+ @Test
+ public void testGetAuthorityUri() {
+ assertEquals("http://foo", getAuthorityUri("http://foo"));
+ assertEquals("http://foo:123", getAuthorityUri("http://foo:123"));
+ assertEquals("http://foo:123", getAuthorityUri("http://foo:123/"));
+ assertEquals("http://foo:123", getAuthorityUri("http://foo:123/bar"));
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextResolutionComboTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextResolutionComboTest.java b/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextResolutionComboTest.java
new file mode 100644
index 0000000..e69a635
--- /dev/null
+++ b/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextResolutionComboTest.java
@@ -0,0 +1,630 @@
+// ***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.TestUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.junit.*;
+import org.junit.runner.*;
+import org.junit.runners.*;
+
+/**
+ * Verifies that the resolveUri() methods in UriContext work correctly.
+ */
+@RunWith(Parameterized.class)
+public class UriContextResolutionComboTest {
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> getInput() {
+ return Arrays.asList(new Object[][] {
+
+ // Happy cases - All URL parts known.
+ {
+ input(
+ "Happy-1",
+ "http://host:port","/context","/resource","/path",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar"
+ )
+ },
+ {
+ input(
+ "Happy-2",
+ "http://host:port","/context","/resource","/path",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123"
+ )
+ },
+ {
+ input(
+ "Happy-3",
+ "http://host:port","/context","/resource","/path",
+ "/foobar",
+ "http://host:port/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "Happy-4",
+ "http://host:port","/context","/resource","/path",
+ "/",
+ "http://host:port",
+ "/"
+ )
+ },
+ {
+ input(
+ "Happy-5",
+ "http://host:port","/context","/resource","/path",
+ "foobar",
+ "http://host:port/context/resource/foobar",
+ "/context/resource/foobar"
+ )
+ },
+ {
+ input(
+ "Happy-6",
+ "http://host:port","/context","/resource","/path",
+ "",
+ "http://host:port/context/resource/path",
+ "/context/resource/path"
+ )
+ },
+ {
+ input(
+ "Happy-7",
+ "http://host:port","/context","/resource","/path",
+ "context:/foo",
+ "http://host:port/context/foo",
+ "/context/foo"
+ )
+ },
+ {
+ input(
+ "Happy-8",
+ "http://host:port","/context","/resource","/path",
+ "context:/",
+ "http://host:port/context",
+ "/context"
+ )
+ },
+ {
+ input(
+ "Happy-9",
+ "http://host:port","/context","/resource","/path",
+ "servlet:/foo",
+ "http://host:port/context/resource/foo",
+ "/context/resource/foo"
+ )
+ },
+ {
+ input(
+ "Happy-10",
+ "http://host:port","/context","/resource","/path",
+ "servlet:/",
+ "http://host:port/context/resource",
+ "/context/resource"
+ )
+ },
+
+ // Multiple context and resource parts
+ {
+ input(
+ "MultiContextResource-1",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-2",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-3",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "/foobar",
+ "http://host:port/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-4",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "/",
+ "http://host:port",
+ "/"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-5",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "foobar",
+ "http://host:port/c1/c2/r1/r2/p1/foobar",
+ "/c1/c2/r1/r2/p1/foobar"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-6",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "",
+ "http://host:port/c1/c2/r1/r2/p1/p2",
+ "/c1/c2/r1/r2/p1/p2"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-7",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "context:/foo",
+ "http://host:port/c1/c2/foo",
+ "/c1/c2/foo"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-8",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "context:/",
+ "http://host:port/c1/c2",
+ "/c1/c2"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-9",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "servlet:/foo",
+ "http://host:port/c1/c2/r1/r2/foo",
+ "/c1/c2/r1/r2/foo"
+ )
+ },
+ {
+ input(
+ "MultiContextResource-10",
+ "http://host:port","/c1/c2","/r1/r2","/p1/p2",
+ "servlet:/",
+ "http://host:port/c1/c2/r1/r2",
+ "/c1/c2/r1/r2"
+ )
+ },
+
+ // No authority given
+ {
+ input(
+ "NoAuthority-1",
+ "","/context","/resource","/path",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthority-2",
+ "","/context","/resource","/path",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123"
+ )
+ },
+ {
+ input(
+ "NoAuthority-3",
+ "","/context","/resource","/path",
+ "/foobar",
+ "/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthority-4",
+ "","/context","/resource","/path",
+ "/",
+ "/",
+ "/"
+ )
+ },
+ {
+ input(
+ "NoAuthority-5",
+ "","/context","/resource","/path",
+ "foobar",
+ "/context/resource/foobar",
+ "/context/resource/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthority-6",
+ "","/context","/resource","/path",
+ "",
+ "/context/resource/path",
+ "/context/resource/path"
+ )
+ },
+ {
+ input(
+ "NoAuthority-7",
+ "","/context","/resource","/path",
+ "context:/foo",
+ "/context/foo",
+ "/context/foo"
+ )
+ },
+ {
+ input(
+ "NoAuthority-8",
+ "","/context","/resource","/path",
+ "context:/",
+ "/context",
+ "/context"
+ )
+ },
+ {
+ input(
+ "NoAuthority-9",
+ "","/context","/resource","/path",
+ "servlet:/foo",
+ "/context/resource/foo",
+ "/context/resource/foo"
+ )
+ },
+ {
+ input(
+ "NoAuthority-10",
+ "","/context","/resource","/path",
+ "servlet:/",
+ "/context/resource",
+ "/context/resource"
+ )
+ },
+
+ // No authority or context given
+ {
+ input(
+ "NoAuthorityOrContext-1",
+ "","","/resource","/path",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-2",
+ "","","/resource","/path",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-3",
+ "","","/resource","/path",
+ "/foobar",
+ "/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-4",
+ "","","/resource","/path",
+ "/",
+ "/",
+ "/"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-5",
+ "","","/resource","/path",
+ "foobar",
+ "/resource/foobar",
+ "/resource/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-6",
+ "","","/resource","/path",
+ "",
+ "/resource/path",
+ "/resource/path"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-7",
+ "","","/resource","/path",
+ "context:/foo",
+ "/foo",
+ "/foo"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-8",
+ "","","/resource","/path",
+ "context:/",
+ "/",
+ "/"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-9",
+ "","","/resource","/path",
+ "servlet:/foo",
+ "/resource/foo",
+ "/resource/foo"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContext-10",
+ "","","/resource","/path",
+ "servlet:/",
+ "/resource",
+ "/resource"
+ )
+ },
+
+ // No authority or context or resource given
+ {
+ input(
+ "NoAuthorityOrContextOrResource-1",
+ "","","","/path",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-2",
+ "","","","/path",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-3",
+ "","","","/path",
+ "/foobar",
+ "/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-4",
+ "","","","/path",
+ "/",
+ "/",
+ "/"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-5",
+ "","","","/path",
+ "foobar",
+ "/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-6",
+ "","","","/path",
+ "",
+ "/path",
+ "/path"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-7",
+ "","","","/path",
+ "context:/foo",
+ "/foo",
+ "/foo"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-8",
+ "","","","/path",
+ "context:/",
+ "/",
+ "/"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-9",
+ "","","","/path",
+ "servlet:/foo",
+ "/foo",
+ "/foo"
+ )
+ },
+ {
+ input(
+ "NoAuthorityOrContextOrResource-10",
+ "","","","/path",
+ "servlet:/",
+ "/",
+ "/"
+ )
+ },
+
+ // No context or resource given.
+ {
+ input(
+ "NoContextOrResource-1",
+ "http://host:port","","","/path",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar",
+ "http://foo.com:123/foobar"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-2",
+ "http://host:port","","","/path",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-3",
+ "http://host:port","","","/path",
+ "/foobar",
+ "http://host:port/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-4",
+ "http://host:port","","","/path",
+ "/",
+ "http://host:port",
+ "/"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-5",
+ "http://host:port","","","/path",
+ "foobar",
+ "http://host:port/foobar",
+ "/foobar"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-6",
+ "http://host:port","","","/path",
+ "",
+ "http://host:port/path",
+ "/path"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-7",
+ "http://host:port","","","/path",
+ "context:/foo",
+ "http://host:port/foo",
+ "/foo"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-8",
+ "http://host:port","","","/path",
+ "context:/",
+ "http://host:port",
+ "/"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-9",
+ "http://host:port","","","/path",
+ "servlet:/foo",
+ "http://host:port/foo",
+ "/foo"
+ )
+ },
+ {
+ input(
+ "NoContextOrResource-10",
+ "http://host:port","","","/path",
+ "servlet:/",
+ "http://host:port",
+ "/"
+ )
+ },
+ });
+ }
+
+ public static Input input(String label, String authority, String context, String resource, String path, String uri, String expectedAbsolute, String expectedRootRelative) {
+ return new Input(label, authority, context, resource, path, uri, expectedAbsolute, expectedRootRelative);
+ }
+
+ public static class Input {
+ private final UriContext uriContext;
+ private final String label, uri, expectedAbsolute, expectedRootRelative;
+
+ public Input(String label, String authority, String context, String resource, String path, String uri, String expectedAbsolute, String expectedRootRelative) {
+ this.label = label;
+ this.uriContext = new UriContext(authority, context, resource, path);
+ this.uri = uri;
+ this.expectedAbsolute = expectedAbsolute;
+ this.expectedRootRelative = expectedRootRelative;
+ }
+ }
+
+ private Input in;
+
+ public UriContextResolutionComboTest(Input in) throws Exception {
+ this.in = in;
+ }
+
+ @Test
+ public void testAbsolute() {
+ assertEquals(in.expectedAbsolute, in.uriContext.resolveAbsolute(in.uri), "{0}: testAbsolute() failed", in.label);
+ }
+
+ @Test
+ public void testRootRelative() {
+ assertEquals(in.expectedRootRelative, in.uriContext.resolveRootRelative(in.uri), "{0}: testRootRelative() failed", in.label);
+ }
+
+ @Test
+ public void testAbsoluteAppend() {
+ assertEquals(in.expectedAbsolute, in.uriContext.appendAbsolute(new StringBuilder(), in.uri).toString(), "{0}: testAbsolute() failed", in.label);
+ }
+
+ @Test
+ public void testRootRelativeAppend() {
+ assertEquals(in.expectedRootRelative, in.uriContext.appendRootRelative(new StringBuilder(), in.uri).toString(), "{0}: testRootRelative() failed", in.label);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextUriComboTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextUriComboTest.java b/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextUriComboTest.java
new file mode 100644
index 0000000..b3a3b60
--- /dev/null
+++ b/juneau-core-test/src/test/java/org/apache/juneau/utils/UriContextUriComboTest.java
@@ -0,0 +1,234 @@
+// ***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.TestUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.junit.*;
+import org.junit.runner.*;
+import org.junit.runners.*;
+
+/**
+ * Verifies that the getUri() methods in UriContext work correctly.
+ */
+@RunWith(Parameterized.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class UriContextUriComboTest {
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> getInput() {
+ return Arrays.asList(new Object[][] {
+
+ // Happy cases - All URL parts known.
+ {
+ input(
+ "Happy-1",
+ "http://foo.com:123","/context","/resource","/path",
+ "http://foo.com:123",
+ "http://foo.com:123/context",
+ "http://foo.com:123/context/resource",
+ "http://foo.com:123/context/resource/path",
+ "/context",
+ "/context/resource",
+ "/context/resource/path"
+ )
+ },
+ {
+ input(
+ "Happy-2",
+ "http://foo.com:123","/c1/c2","/r1/r2","/p1/p2",
+ "http://foo.com:123",
+ "http://foo.com:123/c1/c2",
+ "http://foo.com:123/c1/c2/r1/r2",
+ "http://foo.com:123/c1/c2/r1/r2/p1/p2",
+ "/c1/c2",
+ "/c1/c2/r1/r2",
+ "/c1/c2/r1/r2/p1/p2"
+ )
+ },
+ {
+ input(
+ "NoAuthority-1",
+ "","/context","/resource","/path",
+ "/",
+ "/context",
+ "/context/resource",
+ "/context/resource/path",
+ "/context",
+ "/context/resource",
+ "/context/resource/path"
+ )
+ },
+ {
+ input(
+ "NoContext-1",
+ "http://foo.com:123","","/resource","/path",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123/resource",
+ "http://foo.com:123/resource/path",
+ "/",
+ "/resource",
+ "/resource/path"
+ )
+ },
+ {
+ input(
+ "NoResource-1",
+ "http://foo.com:123","/context","","/path",
+ "http://foo.com:123",
+ "http://foo.com:123/context",
+ "http://foo.com:123/context",
+ "http://foo.com:123/context/path",
+ "/context",
+ "/context",
+ "/context/path"
+ )
+ },
+ {
+ input(
+ "NoPath-1",
+ "http://foo.com:123","/context","/resource","",
+ "http://foo.com:123",
+ "http://foo.com:123/context",
+ "http://foo.com:123/context/resource",
+ "http://foo.com:123/context/resource",
+ "/context",
+ "/context/resource",
+ "/context/resource"
+ )
+ },
+ {
+ input(
+ "NoAuthorityNoContext-1",
+ "","","/resource","/path",
+ "/",
+ "/",
+ "/resource",
+ "/resource/path",
+ "/",
+ "/resource",
+ "/resource/path"
+ )
+ },
+ {
+ input(
+ "NoContextNoResource-1",
+ "http://foo.com:123","","","/path",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123",
+ "http://foo.com:123/path",
+ "/",
+ "/",
+ "/path"
+ )
+ },
+ {
+ input(
+ "NoAuthorityNoContextNoResource-1",
+ "","","","/path",
+ "/",
+ "/",
+ "/",
+ "/path",
+ "/",
+ "/",
+ "/path"
+ )
+ },
+ {
+ input(
+ "Nothing-1",
+ "","","","",
+ "/",
+ "/",
+ "/",
+ "/",
+ "/",
+ "/",
+ "/"
+ )
+ },
+ });
+ }
+
+ public static Input input(String label, String authority, String context, String resource, String path,
+ String eAbsoluteAuthority, String eAbsoluteContext, String eAbsoluteResource, String eAbsolutePath,
+ String eRootRelativeContext, String eRootRelativeResource, String eRootRelativePath) {
+ return new Input(label, authority, context, resource, path, eAbsoluteAuthority, eAbsoluteContext, eAbsoluteResource, eAbsolutePath, eRootRelativeContext, eRootRelativeResource, eRootRelativePath);
+ }
+
+ public static class Input {
+ private final UriContext uriContext;
+ private final String label, eAbsoluteAuthority, eAbsoluteContext, eAbsoluteResource, eAbsolutePath, eRootRelativeContext, eRootRelativeResource, eRootRelativePath;
+
+ public Input(String label, String authority, String context, String resource, String path,
+ String eAbsoluteAuthority, String eAbsoluteContext, String eAbsoluteResource, String eAbsolutePath,
+ String eRootRelativeContext, String eRootRelativeResource, String eRootRelativePath) {
+ this.label = label;
+ this.uriContext = new UriContext(authority, context, resource, path);
+ this.eAbsoluteAuthority = eAbsoluteAuthority;
+ this.eAbsoluteContext = eAbsoluteContext;
+ this.eAbsoluteResource = eAbsoluteResource;
+ this.eAbsolutePath = eAbsolutePath;
+ this.eRootRelativeContext = eRootRelativeContext;
+ this.eRootRelativeResource = eRootRelativeResource;
+ this.eRootRelativePath = eRootRelativePath;
+ }
+ }
+
+ private Input in;
+
+ public UriContextUriComboTest(Input in) throws Exception {
+ this.in = in;
+ }
+
+ @Test
+ public void a1_testAbsoluteAuthority() {
+ assertEquals(in.eAbsoluteAuthority, in.uriContext.getAbsoluteAuthority(), "{0}: testAbsoluteAuthority() failed", in.label);
+ }
+
+ @Test
+ public void a2_testAbsoluteContext() {
+ assertEquals(in.eAbsoluteContext, in.uriContext.getAbsoluteContextRoot(), "{0}: testAbsoluteContext() failed", in.label);
+ }
+
+ @Test
+ public void a3_testAbsoluteResource() {
+ assertEquals(in.eAbsoluteResource, in.uriContext.getAbsoluteServletPath(), "{0}: testAbsoluteResource() failed", in.label);
+ }
+
+ @Test
+ public void a4_testAbsolutePath() {
+ assertEquals(in.eAbsolutePath, in.uriContext.getAbsolutePathInfo(), "{0}: testAbsolutePath() failed", in.label);
+ }
+
+ @Test
+ public void a5_testRootRelativeContext() {
+ assertEquals(in.eRootRelativeContext, in.uriContext.getRootRelativeContextRoot(), "{0}: testRootRelativeContext() failed", in.label);
+ }
+
+ @Test
+ public void a6_testRootRelativeResource() {
+ assertEquals(in.eRootRelativeResource, in.uriContext.getRootRelativeServletPath(), "{0}: testRootRelativeResource() failed", in.label);
+ }
+
+ @Test
+ public void a7_testRootRelativePath() {
+ assertEquals(in.eRootRelativePath, in.uriContext.getRootRelativePathInfo(), "{0}: testRootRelativePath() failed", in.label);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java b/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java
index 6f0738e..65e23e7 100755
--- a/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java
@@ -46,7 +46,7 @@ public class XmlContentTest {
t.f2 = null;
sw = new StringWriter();
- session = s1.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null);
+ session = s1.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null, null);
s1.serialize(session, t);
r = sw.toString();
assertEquals("<A f1='f1'>_x0000_</A>", r);
@@ -54,7 +54,7 @@ public class XmlContentTest {
assertEqualObjects(t, t2);
sw = new StringWriter();
- session = s2.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null);
+ session = s2.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null, null);
s2.serialize(session, t);
r = sw.toString();
assertEquals("<A f1='f1'>_x0000_</A>\n", r);
@@ -154,7 +154,7 @@ public class XmlContentTest {
t.f2 = null;
sw = new StringWriter();
- session = s1.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null);
+ session = s1.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null, null);
s1.serialize(session, t);
r = sw.toString();
assertEquals("<A f1='f1'>_x0000_</A>", r);
@@ -162,7 +162,7 @@ public class XmlContentTest {
assertEqualObjects(t, t2);
sw = new StringWriter();
- session = s2.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null);
+ session = s2.createSession(sw, new ObjectMap("{"+SERIALIZER_trimNullProperties+":false}"), null, null, null, null, null);
s2.serialize(session, t);
r = sw.toString();
assertEquals("<A f1='f1'>_x0000_</A>\n", r);
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanMap.java b/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
index e6a1566..af5634e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
@@ -440,6 +440,17 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T
}
/**
+ * Given a string containing variables of the form <code>"{property}"</code>, replaces those variables with
+ * property values in this bean.
+ *
+ * @param s The string containing variables.
+ * @return A new string with variables replaced, or the same string if no variables were found.
+ */
+ public String resolveVars(String s) {
+ return StringUtils.replaceVars(s, this);
+ }
+
+ /**
* Returns a simple collection of properties for this bean map.
* @return A simple collection of properties for this bean map.
*/
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/UriContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/UriContext.java b/juneau-core/src/main/java/org/apache/juneau/UriContext.java
new file mode 100644
index 0000000..99ddd7f
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/UriContext.java
@@ -0,0 +1,421 @@
+// ***************************************************************************************************************************
+// * 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;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.io.*;
+
+/**
+ * Represents a URL broken into authority/context-root/servlet-path/path-info parts.
+ * <p>
+ * A typical request against a URL takes the following form:
+ * <p class='bcode'>
+ * http://host:port/context-root/servlet-path/path-info
+ * | authority | context | resource | path |
+ * +--------------------------------------------------+
+ * </p>
+ * <p>
+ * This class allows you to convert URL strings to absolute (e.g. <js>"http://host:port/foo/bar"</js>) or root-relative
+ * (e.g. <js>"/foo/bar"</js>) URLs.
+ * <p>
+ * Two special protocols are used to represent context-root-relative and servlet-relative URIs:
+ * <js>"context:/"</js> and <js>"servlet:/"</js>.
+ *
+ * The following list shows the types of URLs that can be resolved with this class:
+ * <ul>
+ * <li><js>"foo://foo"</js> - Absolute URI.
+ * <li><js>"/foo"</js> - Root-relative URI.
+ * <li><js>"/"</js> - Root URI.
+ * <li><js>"context:/foo"</js> - Context-root-relative URI.
+ * <li><js>"context:/"</js> - Context-root URI.
+ * <li><js>"servlet:/foo"</js> - Servlet-path-relative URI.
+ * <li><js>"servlet:/"</js> - Servlet-path URI.
+ * <li><js>"foo"</js> - Path-info-relative URI.
+ * <li><js>""</js> - Path-info URI.
+ * </ul>
+ *
+ * The following class shows how
+ */
+public class UriContext {
+
+ private final String authority, contextRoot, servletPath, pathInfo, parentPath;
+
+ // Lazy-initialized fields.
+ private String aContextRoot, rContextRoot, aServletPath, rResource, aPathInfo, rPath;
+
+
+ /**
+ * Constructor.
+ * <p>
+ * Leading and trailing slashes are trimmed of all parameters.
+ * <p>
+ * Any parameter can be <jk>null</jk>. Blanks and nulls are equivalent.
+ *
+ * @param authority - The authority portion of URL (e.g. <js>"http://hostname:port"</js>)
+ * @param contextRoot - The context root of the application (e.g. <js>"/context-root"</js>, or <js>"context-root"</js>)
+ * @param servletPath - The servlet path (e.g. <js>"/servlet-path"</js>, or <js>"servlet-path"</js>)
+ * @param pathInfo - The path info (e.g. <js>"/path-info"</js>, or <js>"path-info"</js>)
+ */
+ public UriContext(String authority, String contextRoot, String servletPath, String pathInfo) {
+ this.authority = nullIfEmpty(trimSlashes(authority));
+ this.contextRoot = nullIfEmpty(trimSlashes(contextRoot));
+ this.servletPath = nullIfEmpty(trimSlashes(servletPath));
+ this.pathInfo = nullIfEmpty(trimSlashes(pathInfo));
+ this.parentPath = this.pathInfo == null || this.pathInfo.indexOf('/') == -1 ? null : this.pathInfo.substring(0, this.pathInfo.lastIndexOf('/'));
+ }
+
+ /**
+ * Returns the absolute URI of just the authority portion of this URI context.
+ * <p>
+ * Example: <js>"http://hostname:port"</js>
+ * <p>
+ * If the authority is null/empty, returns <js>"/"</js>.
+ *
+ * @return The absolute URI of just the authority portion of this URI context.
+ * Never <jk>null</jk>.
+ */
+ public String getAbsoluteAuthority() {
+ return authority == null ? "/" : authority;
+ }
+
+ /**
+ * Returns the absolute URI of the context-root portion of this URI context.
+ * <p>
+ * Example: <js>"http://hostname:port/context-root"</js>
+ *
+ * @return The absolute URI of the context-root portion of this URI context.
+ * Never <jk>null</jk>.
+ */
+ public String getAbsoluteContextRoot() {
+ if (aContextRoot == null) {
+ if (authority == null)
+ aContextRoot = getRootRelativeContextRoot();
+ else
+ aContextRoot = (contextRoot == null ? authority : (authority + '/' + contextRoot));
+ }
+ return aContextRoot;
+ }
+
+ /**
+ * Returns the root-relative URI of the context portion of this URI context.
+ * <p>
+ * Example: <js>"/context-root"</js>
+ *
+ * @return The root-relative URI of the context portion of this URI context.
+ * Never <jk>null</jk>.
+ */
+ public String getRootRelativeContextRoot() {
+ if (rContextRoot == null)
+ rContextRoot = contextRoot == null ? "/" : ('/' + contextRoot);
+ return rContextRoot;
+ }
+
+ /**
+ * Returns the absolute URI of the resource portion of this URI context.
+ * <p>
+ * Example: <js>"http://hostname:port/context-root/servlet-path"</js>
+ *
+ * @return The absolute URI of the resource portion of this URI context.
+ * Never <jk>null</jk>.
+ */
+ public String getAbsoluteServletPath() {
+ if (aServletPath == null) {
+ if (authority == null)
+ aServletPath = getRootRelativeServletPath();
+ else {
+ if (contextRoot == null)
+ aServletPath = (servletPath == null ? authority : authority + '/' + servletPath);
+ else
+ aServletPath = (servletPath == null ? (authority + '/' + contextRoot) : (authority + '/' + contextRoot + '/' + servletPath));
+ }
+ }
+ return aServletPath;
+ }
+
+ /**
+ * Returns the root-relative URI of the resource portion of this URI context.
+ * <p>
+ * Example: <js>"/context-root/servlet-path"</js>
+ *
+ * @return The root-relative URI of the resource portion of this URI context.
+ * Never <jk>null</jk>.
+ */
+ public String getRootRelativeServletPath() {
+ if (rResource == null) {
+ if (contextRoot == null)
+ rResource = (servletPath == null ? "/" : ('/' + servletPath));
+ else
+ rResource = (servletPath == null ? ('/' + contextRoot) : ('/' + contextRoot + '/' + servletPath));
+ }
+ return rResource;
+ }
+
+ /**
+ * Returns the parent of the URL returned by {@link #getAbsoluteServletPath()}.
+ *
+ * @return The parent of the URL returned by {@link #getAbsoluteServletPath()}.
+ */
+ public String getAbsoluteServletPathParent() {
+ return getParent(getAbsoluteServletPath());
+ }
+
+ /**
+ * Returns the parent of the URL returned by {@link #getRootRelativeServletPath()}.
+ *
+ * @return The parent of the URL returned by {@link #getRootRelativeServletPath()}.
+ */
+ public String getRootRelativeServletPathParent() {
+ return getParent(getRootRelativeServletPath());
+ }
+
+ /**
+ * Returns the absolute URI of the path portion of this URI context.
+ * <p>
+ * Example: <js>"http://hostname:port/context-root/servlet-path/path-info"</js>
+ *
+ * @return The absolute URI of the path portion of this URI context.
+ * Never <jk>null</jk>.
+ */
+ public String getAbsolutePathInfo() {
+ if (aPathInfo == null) {
+ if (authority == null)
+ aPathInfo = getRootRelativePathInfo();
+ else {
+ if (contextRoot == null) {
+ if (servletPath == null)
+ aPathInfo = (pathInfo == null ? authority : (authority + '/' + pathInfo));
+ else
+ aPathInfo = (pathInfo == null ? (authority + '/' + servletPath) : (authority + '/' + servletPath + '/' + pathInfo));
+ } else {
+ if (servletPath == null)
+ aPathInfo = (pathInfo == null ? authority + '/' + contextRoot : (authority + '/' + contextRoot + '/' + pathInfo));
+ else
+ aPathInfo = (pathInfo == null ? (authority + '/' + contextRoot + '/' + servletPath) : (authority + '/' + contextRoot + '/' + servletPath + '/' + pathInfo));
+ }
+ }
+ }
+ return aPathInfo;
+ }
+
+ /**
+ * Returns the root-relative URI of the path portion of this URI context.
+ * <p>
+ * Example: <js>"/context-root/servlet-path/path-info"</js>
+ *
+ * @return The root-relative URI of the path portion of this URI context.
+ * Never <jk>null</jk>.
+ */
+ public String getRootRelativePathInfo() {
+ if (rPath == null) {
+ if (contextRoot == null) {
+ if (servletPath == null)
+ rPath = (pathInfo == null ? "/" : ('/' + pathInfo));
+ else
+ rPath = (pathInfo == null ? ('/' + servletPath) : ('/' + servletPath + '/' + pathInfo));
+ } else {
+ if (servletPath == null)
+ rPath = (pathInfo == null ? ('/' + contextRoot) : ('/' + contextRoot + '/' + pathInfo));
+ else
+ rPath = (pathInfo == null ? ('/' + contextRoot + '/' + servletPath) : ('/' + contextRoot + '/' + servletPath + '/' + pathInfo));
+ }
+ }
+ return rPath;
+ }
+
+ /**
+ * Returns the parent of the URL returned by {@link #getAbsolutePathInfo()}.
+ *
+ * @return The parent of the URL returned by {@link #getAbsolutePathInfo()}.
+ */
+ public String getAbsolutePathInfoParent() {
+ return getParent(getAbsolutePathInfo());
+ }
+
+ /**
+ * Returns the parent of the URL returned by {@link #getRootRelativePathInfo()}.
+ *
+ * @return The parent of the URL returned by {@link #getRootRelativePathInfo()}.
+ */
+ public String getRootRelativePathInfoParent() {
+ return getParent(getRootRelativePathInfo());
+ }
+
+ /**
+ * Converts the specified URI to absolute form based on values in this context.
+ *
+ * @param uri The URI to convert to absolute form.
+ * @return The converted URI.
+ */
+ public String resolveAbsolute(String uri) {
+ if (isAbsoluteUri(uri))
+ return uri;
+ return appendAbsolute(new StringBuilder(), uri).toString();
+ }
+
+ /**
+ * Converts the specified URI to root-relative form based on values in this context.
+ *
+ * @param uri The URI to convert to root-relative form.
+ * @return The converted URI.
+ */
+ public String resolveRootRelative(String uri) {
+ if (isAbsoluteUri(uri))
+ return uri;
+ if (startsWith(uri, '/'))
+ return uri;
+ return appendRootRelative(new StringBuilder(), uri).toString();
+ }
+
+ /**
+ * Same as {@link #resolveAbsolute(String)} except appends result to the specified appendable.
+ *
+ * @param a The appendable to append the URL to.
+ * @param uri The URI to convert to absolute form.
+ * @return The same appendable passed in.
+ */
+ public Appendable appendAbsolute(Appendable a, String uri) {
+
+ try {
+ uri = nullIfEmpty(uri);
+
+ // Absolute paths are not changed.
+ if (isAbsoluteUri(uri))
+ return a.append(uri);
+
+ // Root-relative path
+ if (startsWith(uri, '/')) {
+ if (authority != null){
+ a.append(authority);
+ if (uri.length() == 1)
+ return a;
+ }
+ return a.append(uri);
+
+ // Context-relative path
+ } else if (uri != null && uri.startsWith("context:/")) {
+ if (authority != null)
+ a.append(authority);
+ if (contextRoot != null)
+ a.append('/').append(contextRoot);
+ if (uri.length() > 9)
+ a.append('/').append(uri.substring(9));
+ else if (contextRoot == null && authority == null)
+ a.append('/');
+
+ // Resource-relative path
+ } else if (uri != null && uri.startsWith("servlet:/")) {
+ if (authority != null)
+ a.append(authority);
+ if (contextRoot != null)
+ a.append('/').append(contextRoot);
+ if (servletPath != null)
+ a.append('/').append(servletPath);
+ if (uri.length() > 9)
+ a.append('/').append(uri.substring(9));
+ else if (servletPath == null && contextRoot == null && authority == null)
+ a.append('/');
+
+ // Relative path
+ } else {
+ if (authority != null)
+ a.append(authority);
+ if (contextRoot != null)
+ a.append('/').append(contextRoot);
+ if (servletPath != null)
+ a.append('/').append(servletPath);
+ if (uri == null) {
+ if (pathInfo != null)
+ a.append('/').append(pathInfo);
+ } else {
+ if (parentPath != null)
+ a.append('/').append(parentPath);
+ a.append('/').append(uri);
+ }
+ }
+
+ return a;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Same as {@link #resolveRootRelative(String)} except appends result to the specified appendable.
+ *
+ * @param a The appendable to append the URL to.
+ * @param uri The URI to convert to root-relative form.
+ * @return The same appendable passed in.
+ */
+ public Appendable appendRootRelative(Appendable a, String uri) {
+
+ try {
+ uri = nullIfEmpty(uri);
+
+ // Absolute paths are not changed.
+ if (isAbsoluteUri(uri))
+ return a.append(uri);
+
+ // Root-relative path
+ if (startsWith(uri, '/')) {
+ return a.append(uri);
+
+ // Context-relative path
+ } else if (uri != null && uri.startsWith("context:/")) {
+ if (contextRoot != null)
+ a.append('/').append(contextRoot);
+ if (uri.length() > 9)
+ a.append('/').append(uri.substring(9));
+ else if (contextRoot == null)
+ a.append('/');
+
+ // Resource-relative path
+ } else if (uri != null && uri.startsWith("servlet:/")) {
+ if (contextRoot != null)
+ a.append('/').append(contextRoot);
+ if (servletPath != null)
+ a.append('/').append(servletPath);
+ if (uri.length() > 9)
+ a.append('/').append(uri.substring(9));
+ else if (servletPath == null && contextRoot == null)
+ a.append('/');
+
+ // Relative path
+ } else {
+ if (contextRoot != null)
+ a.append('/').append(contextRoot);
+ if (servletPath != null)
+ a.append('/').append(servletPath);
+ if (uri == null) {
+ if (pathInfo != null)
+ a.append('/').append(pathInfo);
+ } else {
+ if (parentPath != null)
+ a.append('/').append(parentPath);
+ a.append('/').append(uri);
+ }
+ }
+
+ return a;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static String getParent(String uri) {
+ int i = uri.lastIndexOf('/');
+ if (i <= 1)
+ return "/";
+ return uri.substring(0, i);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/UriRelativity.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/UriRelativity.java b/juneau-core/src/main/java/org/apache/juneau/UriRelativity.java
new file mode 100644
index 0000000..95fc46b
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/UriRelativity.java
@@ -0,0 +1,29 @@
+// ***************************************************************************************************************************
+// * 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;
+
+/**
+ * Identifies how relative URIs should resolve against.
+ */
+public enum UriRelativity {
+
+ /**
+ * Relative URIs should be considered relative to the servlet URI.
+ */
+ RESOURCE,
+
+ /**
+ * Relative URIs should be considered relative to the request URI.
+ */
+ PATH_INFO;
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/UriResolution.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/UriResolution.java b/juneau-core/src/main/java/org/apache/juneau/UriResolution.java
new file mode 100644
index 0000000..aacfe6d
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/UriResolution.java
@@ -0,0 +1,34 @@
+// ***************************************************************************************************************************
+// * 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;
+
+/**
+ * Identifies the possible types of URL resolution.
+ */
+public enum UriResolution {
+
+ /**
+ * Resolve to an absolute URL (e.g. <js>"http://host:port/context-root/servlet-path/path-info"</js>).
+ */
+ ABSOLUTE,
+
+ /**
+ * Resolve to a root-relative URL (e.g. <js>"/context-root/servlet-path/path-info"</js>).
+ */
+ ROOT_RELATIVE,
+
+ /**
+ * Don't do any URL resolution.
+ */
+ NONE;
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
index 163928b..16a6c14 100644
--- a/juneau-core/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
@@ -30,18 +30,20 @@ public final class CsvSerializerSession extends SerializerSession {
* Create a new session using properties specified in the context.
*
* @param ctx The context creating this session object.
- * The context contains all the configuration settings for this object.
+ * The context contains all the configuration settings for this object.
* @param output The output object.
* @param op The override properties.
- * These override any context properties defined in the context.
+ * These override any context properties defined in the context.
* @param javaMethod The java method that called this serializer, usually the method in a REST servlet.
* @param locale The session locale.
- * If <jk>null</jk>, then the locale defined on the context is used.
+ * If <jk>null</jk>, then the locale defined on the context is used.
* @param timeZone The session timezone.
- * If <jk>null</jk>, then the timezone defined on the context is used.
+ * If <jk>null</jk>, then the timezone defined on the context is used.
* @param mediaType The session media type (e.g. <js>"application/json"</js>).
+ * @param uriContext The URI context.
+ * Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
*/
- protected CsvSerializerSession(CsvSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ protected CsvSerializerSession(CsvSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ super(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
index a2c3a6c..63ecbb4 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
@@ -18,36 +18,58 @@ import org.apache.juneau.html.annotation.*;
/**
* Metadata on bean properties specific to the HTML serializers and parsers pulled from the {@link Html @Html} annotation on the bean property.
*/
-public class HtmlBeanPropertyMeta extends BeanPropertyMetaExtended {
+@SuppressWarnings("rawtypes")
+public final class HtmlBeanPropertyMeta extends BeanPropertyMetaExtended {
- private boolean asXml, noTables, noTableHeaders, asPlainText;
+ private final boolean asXml, noTables, noTableHeaders, asPlainText;
+ private final HtmlRender render;
+ private final String link;
/**
* Constructor.
*
* @param bpm The metadata of the bean property of this additional metadata.
+ * @throws Exception If render class could not be instantiated.
*/
- public HtmlBeanPropertyMeta(BeanPropertyMeta bpm) {
+ public HtmlBeanPropertyMeta(BeanPropertyMeta bpm) throws Exception {
super(bpm);
+ Builder b = new Builder();
if (bpm.getField() != null)
- findHtmlInfo(bpm.getField().getAnnotation(Html.class));
+ b.findHtmlInfo(bpm.getField().getAnnotation(Html.class));
if (bpm.getGetter() != null)
- findHtmlInfo(bpm.getGetter().getAnnotation(Html.class));
+ b.findHtmlInfo(bpm.getGetter().getAnnotation(Html.class));
if (bpm.getSetter() != null)
- findHtmlInfo(bpm.getSetter().getAnnotation(Html.class));
+ b.findHtmlInfo(bpm.getSetter().getAnnotation(Html.class));
+
+ this.asXml = b.asXml;
+ this.noTables = b.noTables;
+ this.noTableHeaders = b.noTableHeaders;
+ this.asPlainText = b.asPlainText;
+ this.render = b.render.newInstance();
+ this.link = b.link;
}
- private void findHtmlInfo(Html html) {
- if (html == null)
- return;
- if (html.asXml())
- asXml = html.asXml();
- if (html.noTables())
- noTables = html.noTables();
- if (html.noTableHeaders())
- noTableHeaders = html.noTableHeaders();
- if (html.asPlainText())
- asPlainText = html.asPlainText();
+ private static class Builder {
+ boolean asXml, noTables, noTableHeaders, asPlainText;
+ Class<? extends HtmlRender> render = HtmlRender.class;
+ String link;
+
+ void findHtmlInfo(Html html) {
+ if (html == null)
+ return;
+ if (html.asXml())
+ asXml = html.asXml();
+ if (html.noTables())
+ noTables = html.noTables();
+ if (html.noTableHeaders())
+ noTableHeaders = html.noTableHeaders();
+ if (html.asPlainText())
+ asPlainText = html.asPlainText();
+ if (html.render() != HtmlRender.class)
+ render = html.render();
+ if (! html.link().isEmpty())
+ link = html.link();
+ }
}
/**
@@ -85,4 +107,26 @@ public class HtmlBeanPropertyMeta extends BeanPropertyMetaExtended {
public boolean isNoTableHeaders() {
return noTableHeaders;
}
+
+ /**
+ * Returns the render class for rendering the style and contents of this property value in HTML.
+ * <p>
+ * This value is specified via the {@link Html#render()} annotation.
+ *
+ * @return The render class, never <jk>null</jk>.
+ */
+ public HtmlRender getRender() {
+ return render;
+ }
+
+ /**
+ * Adds a hyperlink to this value in HTML.
+ * <p>
+ * This value is specified via the {@link Html#link()} annotation.
+ *
+ * @return The link string, or <jk>null</jk> if not specified.
+ */
+ public String getLink() {
+ return link;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
index d97afe4..68e19e2 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
@@ -75,8 +75,8 @@ public class HtmlDocSerializer extends HtmlStrippedDocSerializer {
//--------------------------------------------------------------------------------
@Override /* Serializer */
- public HtmlDocSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- return new HtmlDocSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ public HtmlDocSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ return new HtmlDocSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
}
@Override /* Serializer */
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
index 0e334d1..f04d2b7 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
@@ -41,20 +41,22 @@ public final class HtmlDocSerializerSession extends HtmlSerializerSession {
* Create a new session using properties specified in the context.
*
* @param ctx The context creating this session object.
- * The context contains all the configuration settings for this object.
+ * The context contains all the configuration settings for this object.
* @param output The output object. See {@link JsonSerializerSession#getWriter()} for valid class types.
* @param op The override properties.
- * These override any context properties defined in the context.
+ * These override any context properties defined in the context.
* @param javaMethod The java method that called this serializer, usually the method in a REST servlet.
* @param locale The session locale.
- * If <jk>null</jk>, then the locale defined on the context is used.
+ * If <jk>null</jk>, then the locale defined on the context is used.
* @param timeZone The session timezone.
- * If <jk>null</jk>, then the timezone defined on the context is used.
+ * If <jk>null</jk>, then the timezone defined on the context is used.
* @param mediaType The session media type (e.g. <js>"application/json"</js>).
+ * @param uriContext The URI context.
+ * Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
- protected HtmlDocSerializerSession(HtmlDocSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ protected HtmlDocSerializerSession(HtmlDocSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ super(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
if (op == null || op.isEmpty()) {
title = ctx.title;
text = ctx.text;
@@ -131,6 +133,6 @@ public final class HtmlDocSerializerSession extends HtmlSerializerSession {
Object output = getOutput();
if (output instanceof HtmlWriter)
return (HtmlWriter)output;
- return new HtmlWriter(super.getWriter(), isUseWhitespace(), isTrimStrings(), getQuoteChar(), getRelativeUriBase(), getAbsolutePathUriBase());
+ return new HtmlWriter(super.getWriter(), isUseWhitespace(), isTrimStrings(), getQuoteChar(), getRelativeUriBase(), getAbsolutePathUriBase(), getUriContext());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlRender.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlRender.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlRender.java
new file mode 100644
index 0000000..b30c67e
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlRender.java
@@ -0,0 +1,149 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.html;
+
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Allows custom rendering of bean property values when serialized as HTML.
+ * <p>
+ * Associated with bean properties using the {@link Html#render() @Html.render()} annotation.
+ * <p>
+ * Using this class, you can alter the CSS style and HTML content of the bean property.
+ * <p>
+ * The following example shows two render classes that customize the appearance of the <code>pctFull</code> and
+ * <code>status</code> columns shown below:
+ * <p>
+ * <img class='bordered' src='doc-files/HtmlRender_1.png'>
+ *
+ * <p class='bcode'>
+ *
+ * <jc>// Our bean class</jc>
+ * <jk>public class</jk> FileSpace {
+ *
+ * <jk>private final</jk> String <jf>drive</jf>;
+ * <jk>private final long</jk> <jf>total</jf>, <jf>available</jf>;
+ *
+ * <jk>public</jk> FileSpace(String drive, <jk>long</jk> total, <jk>long</jk> available) {
+ * <jk>this</jk>.<jf>drive</jf> = drive;
+ * <jk>this</jk>.<jf>total</jf> = total;
+ * <jk>this</jk>.<jf>available</jf> = available;
+ * }
+ *
+ * <ja>@Html</ja>(link=<js>"drive/{drive}"</js>)
+ * <jk>public</jk> String getDrive() {
+ * <jk>return</jk> <jf>drive</jf>;
+ * }
+ *
+ * <jk>public long</jk> getTotal() {
+ * <jk>return</jk> <jf>total</jf>;
+ * }
+ *
+ * <jk>public long</jk> getAvailable() {
+ * <jk>return</jk> <jf>available</jf>;
+ * }
+ *
+ * <ja>@Html</ja>(render=FileSpacePctRender.<jk>class</jk>)
+ * <jk>public float</jk> getPctFull() {
+ * <jk>return</jk> ((100 * <jf>available</jf>) / <jf>total</jf>);
+ * }
+ *
+ * <ja>@Html</ja>(render=FileSpaceStatusRender.<jk>class</jk>)
+ * <jk>public</jk> FileSpaceStatus getStatus() {
+ * <jk>float</jk> pf = getPctFull();
+ * <jk>if</jk> (pf < 80)
+ * <jk>return</jk> FileSpaceStatus.<jsf>OK</jsf>;
+ * <jk>if</jk> (pf < 90)
+ * <jk>return</jk> FileSpaceStatus.<jsf>WARNING</jsf>;
+ * <jk>return</jk> FileSpaceStatus.<jsf>SEVERE</jsf>;
+ * }
+ * }
+ *
+ * <jc>// Possible values for the getStatus() method</jc>
+ * <jk>public static enum</jk> FileSpaceStatus {
+ * <jsf>OK</jsf>, <jsf>WARNING</jsf>, <jsf>SEVERE</jsf>;
+ * }
+ *
+ * <jc>// Custom render for getPctFull() method</jc>
+ * <jk>public static class</jk> FileSpacePctRender <jk>extends</jk> HtmlRender<Float> {
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> String getStyle(SerializerSession session, Float value) {
+ * <jk>if</jk> (value < 80)
+ * <jk>return</jk> <js>"background-color:lightgreen;text-align:center"</js>;
+ * <jk>if</jk> (value < 90)
+ * <jk>return</jk> <js>"background-color:yellow;text-align:center"</js>;
+ * <jk>return</jk> <js>"background-color:red;text-align:center;border:;animation:color_change 0.5s infinite alternate"</js>;
+ * }
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> Object getContent(SerializerSession session, Float value) {
+ * <jk>if</jk> (value >= 90)
+ * <jk>return</jk> <jsm>div</jsm>(
+ * String.<jsm>format</jsm>(<js>"%.0f%%"</js>, value),
+ * <jsm>style</jsm>(<js>"@keyframes color_change { from { background-color: red; } to { background-color: yellow; }"</js>)
+ * );
+ * <jk>return</jk> String.<jsm>format</jsm>(<js>"%.0f%%"</js>, value);
+ * }
+ * }
+ *
+ * <jc>// Custom render for getStatus() method</jc>
+ * <jk>public static class</jk> FileSpaceStatusRender <jk>extends</jk> HtmlRender<FileSpaceStatus> {
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> String getStyle(SerializerSession session, FileSpaceStatus value) {
+ * <jk>return</jk> <js>"text-align:center"</js>;
+ * }
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> Object getContent(SerializerSession session, FileSpaceStatus value) {
+ * <jk>switch</jk> (value) {
+ * <jk>case</jk> <jsf>OK</jsf>: <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/ok.png"</js>));
+ * <jk>case</jk> <jsf>WARNING</jsf>: <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/warning.png"</js>));
+ * <jk>default</jk>: <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/severe.png"</js>));
+ * }
+ * }
+ * }
+ * </p>
+ * @param <T> The bean property type.
+ */
+public class HtmlRender<T> {
+
+ /**
+ * Returns the CSS style of the element containing the bean property value.
+ *
+ * @param session The current serializer session.
+ * Can be used to retrieve properties and session-level information.
+ * @param value The bean property value.
+ * @return The CSS style string, or <jk>null</jk> if no style should be added.
+ */
+ public String getStyle(SerializerSession session, T value) {
+ return null;
+ }
+
+ /**
+ * Returns the delegate value for the specified bean property value.
+ * <p>
+ * The default implementation simply returns the same value.
+ * A typical use is to return an HTML element using one of the HTML5 DOM beans.
+ *
+ * @param session The current serializer session.
+ * Can be used to retrieve properties and session-level information.
+ * @param value The bean property value.
+ * @return The new bean property value.
+ */
+ public Object getContent(SerializerSession session, T value) {
+ return value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
index bc17387..fabcdaa 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
@@ -74,8 +74,8 @@ public final class HtmlSchemaDocSerializer extends HtmlDocSerializer {
}
@Override /* Serializer */
- public HtmlDocSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- return new HtmlDocSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ public HtmlDocSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ return new HtmlDocSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
}
@Override /* ISchemaSerializer */
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
index c3d1088..91b8f16 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
@@ -400,6 +400,7 @@ public class HtmlSerializer extends XmlSerializer {
out.eTag(i, "table").nl();
}
+ @SuppressWarnings({ "rawtypes", "unchecked" })
private void serializeBeanMap(HtmlSerializerSession session, HtmlWriter out, BeanMap<?> m, ClassMeta<?> eType, BeanPropertyMeta ppMeta) throws Exception {
int i = session.getIndent();
@@ -420,6 +421,9 @@ public class HtmlSerializer extends XmlSerializer {
for (BeanPropertyValue p : m.getValues(session.isTrimNulls())) {
BeanPropertyMeta pMeta = p.getMeta();
ClassMeta<?> cMeta = p.getClassMeta();
+ HtmlBeanPropertyMeta hbpMeta = pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class);
+ String link = hbpMeta.getLink();
+ HtmlRender render = hbpMeta.getRender();
String key = p.getName();
Object value = p.getValue();
@@ -432,11 +436,20 @@ public class HtmlSerializer extends XmlSerializer {
out.sTag(i+1, "tr").nl();
out.sTag(i+2, "td").text(key).eTag("td").nl();
- out.sTag(i+2, "td");
+ out.oTag(i+2, "td");
+ String style = render.getStyle(session, value);
+ if (style != null)
+ out.attr("style", style);
+ out.cTag();
+
try {
- ContentResult cr = serializeAnything(session, out, value, cMeta, key, 2, pMeta, false);
+ if (link != null)
+ out.oTag(i+3, "a").attrUri("href", m.resolveVars(link)).cTag();
+ ContentResult cr = serializeAnything(session, out, render.getContent(session, value), cMeta, key, 2, pMeta, false);
if (cr == CR_NORMAL)
out.i(i+2);
+ if (link != null)
+ out.eTag("a");
} catch (SerializeException e) {
throw e;
} catch (Error e) {
@@ -533,10 +546,23 @@ public class HtmlSerializer extends XmlSerializer {
for (Object k : th) {
BeanMapEntry p = m2.getProperty(session.toString(k));
BeanPropertyMeta pMeta = p.getMeta();
- out.sTag(i+2, "td");
- ContentResult cr = serializeAnything(session, out, p.getValue(), pMeta.getClassMeta(), p.getKey().toString(), 2, pMeta, false);
+ HtmlBeanPropertyMeta hpMeta = pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class);
+ String link = hpMeta.getLink();
+ HtmlRender render = hpMeta.getRender();
+
+ Object value = p.getValue();
+ out.oTag(i+2, "td");
+ String style = render.getStyle(session, value);
+ if (style != null)
+ out.attr("style", style);
+ out.cTag();
+ if (link != null)
+ out.oTag(i+3, "a").attrUri("href", m2.resolveVars(link)).cTag();
+ ContentResult cr = serializeAnything(session, out, render.getContent(session, value), pMeta.getClassMeta(), p.getKey().toString(), 2, pMeta, false);
if (cr == CR_NORMAL)
out.i(i+2);
+ if (link != null)
+ out.eTag("a");
out.eTag("td").nl();
}
}
@@ -689,8 +715,8 @@ public class HtmlSerializer extends XmlSerializer {
//--------------------------------------------------------------------------------
@Override /* Serializer */
- public HtmlSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- return new HtmlSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ public HtmlSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ return new HtmlSerializerSession(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
}
@Override /* Serializer */
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index 3faf271..48b16dd 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -52,19 +52,21 @@ public class HtmlSerializerSession extends XmlSerializerSession {
* Create a new session using properties specified in the context.
*
* @param ctx The context creating this session object.
- * The context contains all the configuration settings for this object.
+ * The context contains all the configuration settings for this object.
* @param output The output object. See {@link JsonSerializerSession#getWriter()} for valid class types.
* @param op The override properties.
- * These override any context properties defined in the context.
+ * These override any context properties defined in the context.
* @param javaMethod The java method that called this serializer, usually the method in a REST servlet.
* @param locale The session locale.
- * If <jk>null</jk>, then the locale defined on the context is used.
+ * If <jk>null</jk>, then the locale defined on the context is used.
* @param timeZone The session timezone.
- * If <jk>null</jk>, then the timezone defined on the context is used.
+ * If <jk>null</jk>, then the timezone defined on the context is used.
* @param mediaType The session media type (e.g. <js>"application/json"</js>).
+ * @param uriContext The URI context.
+ * Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
*/
- protected HtmlSerializerSession(HtmlSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
- super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+ protected HtmlSerializerSession(HtmlSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+ super(ctx, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
String labelParameter;
if (op == null || op.isEmpty()) {
anchorText = Enum.valueOf(AnchorText.class, ctx.uriAnchorText);
@@ -91,7 +93,7 @@ public class HtmlSerializerSession extends XmlSerializerSession {
Object output = getOutput();
if (output instanceof HtmlWriter)
return (HtmlWriter)output;
- return new HtmlWriter(super.getWriter(), isUseWhitespace(), isTrimStrings(), getQuoteChar(), getRelativeUriBase(), getAbsolutePathUriBase());
+ return new HtmlWriter(super.getWriter(), isUseWhitespace(), isTrimStrings(), getQuoteChar(), getRelativeUriBase(), getAbsolutePathUriBase(), getUriContext());
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
index 95b6092..30114c3 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
@@ -14,6 +14,7 @@ package org.apache.juneau.html;
import java.io.*;
+import org.apache.juneau.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.xml.*;
@@ -31,9 +32,11 @@ public class HtmlWriter extends XmlWriter {
* @param quoteChar The quote character to use (i.e. <js>'\''</js> or <js>'"'</js>)
* @param uriContext The web application context path (e.g. "/contextRoot").
* @param uriAuthority The web application URI authority (e.g. "http://hostname:9080")
+ * @param uriContext2 The URI context.
+ * Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
*/
- public HtmlWriter(Writer out, boolean useWhitespace, boolean trimStrings, char quoteChar, String uriContext, String uriAuthority) {
- super(out, useWhitespace, trimStrings, quoteChar, uriContext, uriAuthority, false, null);
+ public HtmlWriter(Writer out, boolean useWhitespace, boolean trimStrings, char quoteChar, String uriContext, String uriAuthority, UriContext uriContext2) {
+ super(out, useWhitespace, trimStrings, quoteChar, uriContext, uriAuthority, uriContext2, false, null);
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/SimpleHtmlWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/SimpleHtmlWriter.java b/juneau-core/src/main/java/org/apache/juneau/html/SimpleHtmlWriter.java
index 2ae07f8..b0b6cc3 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/SimpleHtmlWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/SimpleHtmlWriter.java
@@ -28,7 +28,7 @@ public class SimpleHtmlWriter extends HtmlWriter {
* Constructor.
*/
public SimpleHtmlWriter() {
- super(new StringWriter(), true, false, '\'', null, null);
+ super(new StringWriter(), true, false, '\'', null, null, null);
}
@Override /* Object */
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/annotation/Html.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/annotation/Html.java b/juneau-core/src/main/java/org/apache/juneau/html/annotation/Html.java
index c63cd2e..dcfc53c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/annotation/Html.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/annotation/Html.java
@@ -53,4 +53,39 @@ public @interface Html {
* Default is <jk>false</jk>.
*/
boolean noTableHeaders() default false;
+
+ /**
+ * Associates an {@link HtmlRender} with a bean property for custom HTML rendering of the property.
+ * <p>
+ * This annotation applies to bean properties only.
+ */
+ @SuppressWarnings("rawtypes")
+ Class<? extends HtmlRender> render() default HtmlRender.class;
+
+ /**
+ * Adds a hyperlink to a bean property when rendered as HTML.
+ * <p>
+ * The text can contain any bean property values resolved through variables of the form <js>"{property-name}"</js>.
+ * <p>
+ * The URLs can be any of the following forms:
+ * <ul>
+ * <li>Absolute - e.g. <js>"http://host:123/myContext/myServlet/myPath"</js>
+ * <li>Context-root-relative - e.g. <js>"/myContext/myServlet/myPath"</js>
+ * <li>Context-relative - e.g. <js>"context:/myServlet/myPath"</js>
+ * <li>Servlet-relative - e.g. <js>"servlet:/myPath"</js>
+ * <li>Path-info-relative - e.g. <js>"myPath"</js>
+ * </ul>
+ *
+ * <h6 class='figure'>Example:</h6>
+ * <p class='bcode'>
+ * <jk>public class</jk> FileSpace {
+ *
+ * <ja>@Html</ja>(link=<js>"servlet:/drive/{drive}"</js>)
+ * <jk>public</jk> String getDrive() {
+ * ...;
+ * }
+ * }
+ * </p>
+ */
+ String link() default "";
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/html/doc-files/HtmlRender_1.png
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/doc-files/HtmlRender_1.png b/juneau-core/src/main/java/org/apache/juneau/html/doc-files/HtmlRender_1.png
new file mode 100644
index 0000000..f070aea
Binary files /dev/null and b/juneau-core/src/main/java/org/apache/juneau/html/doc-files/HtmlRender_1.png differ