Repository: incubator-juneau
Updated Branches:
  refs/heads/master 9b04bb9c6 -> e1a505668


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java 
b/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
index 8d324fe..ac232a3 100644
--- a/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
+++ b/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -1332,4 +1332,106 @@ public final class StringUtils {
                        return 0;
                return s.charAt(i);
        }
+
+       /**
+        * Efficiently determines whether a URL is of the pattern "xxx://xxx"
+        *
+        * @param s The string to test.
+        * @return <jk>true</jk> if it's an absolute path.
+        */
+       public static boolean isAbsoluteUri(String s) {
+
+               if (isEmpty(s))
+                       return false;
+
+               // Use a state machine for maximum performance.
+               
+               int S1 = 1;  // Looking for http
+               int S2 = 2;  // Found http, looking for :
+               int S3 = 3;  // Found :, looking for /
+               int S4 = 4;  // Found /, looking for /
+               int S5 = 5;  // Found /, looking for x
+
+               int state = S1;
+               for (int i = 0; i < s.length(); i++) {
+                       char c = s.charAt(i);
+                       if (state == S1) {
+                               if (c >= 'a' && c <= 'z')
+                                       state = S2;
+                               else
+                                       return false;
+                       } else if (state == S2) {
+                               if (c == ':')
+                                       state = S3;
+                               else if (c < 'a' || c > 'z')
+                                       return false;
+                       } else if (state == S3) {
+                               if (c == '/')
+                                       state = S4;
+                               else
+                                       return false;
+                       } else if (state == S4) {
+                               if (c == '/')
+                                       state = S5;
+                               else
+                                       return false;
+                       } else if (state == S5) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Given an absolute URI, returns just the authority portion (e.g. 
<js>"http://hostname:port";</js>)
+        *
+        * @param s The URI string.
+        * @return Just the authority portion of the URI.
+        */
+       public static String getAuthorityUri(String s) {
+
+               // Use a state machine for maximum performance.
+
+               int S1 = 1;  // Looking for http
+               int S2 = 2;  // Found http, looking for :
+               int S3 = 3;  // Found :, looking for /
+               int S4 = 4;  // Found /, looking for /
+               int S5 = 5;  // Found /, looking for x
+               int S6 = 6;  // Found x, looking for /
+
+               int state = S1;
+               for (int i = 0; i < s.length(); i++) {
+                       char c = s.charAt(i);
+                       if (state == S1) {
+                               if (c >= 'a' && c <= 'z')
+                                       state = S2;
+                               else
+                                       return s;
+                       } else if (state == S2) {
+                               if (c == ':')
+                                       state = S3;
+                               else if (c < 'a' || c > 'z')
+                                       return s;
+                       } else if (state == S3) {
+                               if (c == '/')
+                                       state = S4;
+                               else
+                                       return s;
+                       } else if (state == S4) {
+                               if (c == '/')
+                                       state = S5;
+                               else
+                                       return s;
+                       } else if (state == S5) {
+                               if (c != '/')
+                                       state = S6;
+                               else
+                                       return s;
+                       } else if (state == S6) {
+                               if (c == '/')
+                                       return s.substring(0, i);
+                       }
+               }
+               return s;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
index df974ea..a85fbfe 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
@@ -71,8 +71,8 @@ public final class JsonSchemaSerializer extends 
JsonSerializer {
        
//--------------------------------------------------------------------------------
 
        @Override /* Serializer */
-       public JsonSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
-               return new JsonSerializerSession(ctx, op, output, javaMethod, 
locale, timeZone, mediaType);
+       public JsonSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
+               return new JsonSerializerSession(ctx, op, output, javaMethod, 
locale, timeZone, mediaType, uriContext);
        }
 
        @Override /* JsonSerializer */

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
index 71859f4..e857b15 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
@@ -381,8 +381,8 @@ public class JsonSerializer extends WriterSerializer {
        
//--------------------------------------------------------------------------------
 
        @Override /* Serializer */
-       public JsonSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
-               return new JsonSerializerSession(ctx, op, output, javaMethod, 
locale, timeZone, mediaType);
+       public JsonSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
+               return new JsonSerializerSession(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/json/JsonSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
index ef1a975..cb6783d 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
@@ -37,19 +37,21 @@ public final class JsonSerializerSession 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 JsonSerializerSession(JsonSerializerContext ctx, ObjectMap 
op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, 
MediaType mediaType) {
-               super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+       protected JsonSerializerSession(JsonSerializerContext 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()) {
                        simpleMode = ctx.simpleMode;
                        escapeSolidus = ctx.escapeSolidus;
@@ -94,6 +96,6 @@ public final class JsonSerializerSession extends 
SerializerSession {
                Object output = getOutput();
                if (output instanceof JsonWriter)
                        return (JsonWriter)output;
-               return new JsonWriter(super.getWriter(), isUseWhitespace(), 
isEscapeSolidus(), getQuoteChar(), isSimpleMode(), isTrimStrings(), 
getRelativeUriBase(), getAbsolutePathUriBase());
+               return new JsonWriter(super.getWriter(), isUseWhitespace(), 
isEscapeSolidus(), getQuoteChar(), isSimpleMode(), isTrimStrings(), 
getRelativeUriBase(), getAbsolutePathUriBase(), getUriContext());
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/json/JsonWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/json/JsonWriter.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonWriter.java
index 38b923a..d08439c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/JsonWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/json/JsonWriter.java
@@ -14,6 +14,7 @@ package org.apache.juneau.json;
 
 import java.io.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
 
@@ -62,9 +63,11 @@ public final class JsonWriter extends SerializerWriter {
         * @param trimStrings If <jk>true</jk>, strings will be trimmed before 
being serialized.
         * @param relativeUriBase The base (e.g. 
<js>https://localhost:9443/contextPath";</js>) for relative URIs (e.g. 
<js>"my/path"</js>).
         * @param absolutePathUriBase The base (e.g. 
<js>https://localhost:9443";</js>) for relative URIs with absolute paths (e.g. 
<js>"/contextPath/my/path"</js>).
+        * @param uriContext The URI context.
+        *      Identifies the current request URI used for resolution of URIs 
to absolute or root-relative form.
         */
-       protected JsonWriter(Writer out, boolean useWhitespace, boolean 
escapeSolidus, char quoteChar, boolean laxMode, boolean trimStrings, String 
relativeUriBase, String absolutePathUriBase) {
-               super(out, useWhitespace, trimStrings, quoteChar, 
relativeUriBase, absolutePathUriBase);
+       protected JsonWriter(Writer out, boolean useWhitespace, boolean 
escapeSolidus, char quoteChar, boolean laxMode, boolean trimStrings, String 
relativeUriBase, String absolutePathUriBase, UriContext uriContext) {
+               super(out, useWhitespace, trimStrings, quoteChar, 
relativeUriBase, absolutePathUriBase, uriContext);
                this.laxMode = laxMode;
                this.escapeSolidus = escapeSolidus;
                this.ec = escapeSolidus ? encodedChars2 : encodedChars;

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
index e0108ea..c47b630 100644
--- a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
@@ -211,8 +211,8 @@ public class MsgPackSerializer extends 
OutputStreamSerializer {
        
//--------------------------------------------------------------------------------
 
        @Override /* Serializer */
-       public MsgPackSerializerSession createSession(Object output, ObjectMap 
op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
-               return new MsgPackSerializerSession(ctx, op, output, 
javaMethod, locale, timeZone, mediaType);
+       public MsgPackSerializerSession createSession(Object output, ObjectMap 
op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
+               return new MsgPackSerializerSession(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/msgpack/MsgPackSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
index 08cc539..5cf5897 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
@@ -36,19 +36,21 @@ public final class MsgPackSerializerSession 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#getOutputStream()} 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 MsgPackSerializerSession(MsgPackSerializerContext ctx, 
ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone 
timeZone, MediaType mediaType) {
-               super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+       protected MsgPackSerializerSession(MsgPackSerializerContext 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()) {
                        addBeanTypeProperties = ctx.addBeanTypeProperties;
                } else {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/serializer/Serializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/serializer/Serializer.java 
b/juneau-core/src/main/java/org/apache/juneau/serializer/Serializer.java
index a323caa..d5af30a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/serializer/Serializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/serializer/Serializer.java
@@ -84,7 +84,7 @@ public abstract class Serializer extends CoreObject {
         * Serializes a POJO to the specified output stream or writer.
         * <p>
         * This method should NOT close the context object.
-        * @param session The serializer session object return by {@link 
#createSession(Object, ObjectMap, Method, Locale, TimeZone, MediaType)}.<br>
+        * @param session The serializer session object return by {@link 
#createSession(Object, ObjectMap, Method, Locale, TimeZone, MediaType, 
UriContext)}.<br>
         * If <jk>null</jk>, session is created using {@link 
#createSession(Object)}.
         * @param o The object to serialize.
         *
@@ -112,7 +112,7 @@ public abstract class Serializer extends CoreObject {
        /**
         * Serialize the specified object using the specified session.
         *
-        * @param session The serializer session object return by {@link 
#createSession(Object, ObjectMap, Method, Locale, TimeZone, MediaType)}.<br>
+        * @param session The serializer session object return by {@link 
#createSession(Object, ObjectMap, Method, Locale, TimeZone, MediaType, 
UriContext)}.<br>
         * If <jk>null</jk>, session is created using {@link 
#createSession(Object)}.
         * @param o The object to serialize.
         * @throws SerializeException If a problem occurred trying to convert 
the output.
@@ -183,10 +183,12 @@ public abstract class Serializer extends CoreObject {
         * @param timeZone The session timezone.
         * 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.
         * @return The new session.
         */
-       public SerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
-               return new SerializerSession(ctx, op, output, javaMethod, 
locale, timeZone, mediaType);
+       public SerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
+               return new SerializerSession(ctx, op, output, javaMethod, 
locale, timeZone, mediaType, uriContext);
        }
 
        /**
@@ -209,7 +211,7 @@ public abstract class Serializer extends CoreObject {
         * @return The new session.
         */
        protected SerializerSession createSession(Object output) {
-               return createSession(output, null, null, null, null, 
getPrimaryMediaType());
+               return createSession(output, null, null, null, null, 
getPrimaryMediaType(), null);
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerSession.java
index bbe17fc..1a70524 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerSession.java
@@ -54,6 +54,7 @@ public class SerializerSession extends BeanSession {
                abridged;
        private final char quoteChar;
        private final String relativeUriBase, absolutePathUriBase;
+       private final UriContext uriContext;
 
        /** The current indentation depth into the model. */
        public int indent;
@@ -73,32 +74,35 @@ public class SerializerSession extends BeanSession {
         * 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.
-        * <br>Character-based serializers can handle the following output 
class types:
-        * <ul>
-        *      <li>{@link Writer}
-        *      <li>{@link OutputStream} - Output will be written as UTF-8 
encoded stream.
-        *      <li>{@link File} - Output will be written as system-default 
encoded stream.
-        * </ul>
-        * <br>Stream-based serializers can handle the following output class 
types:
-        * <ul>
-        *      <li>{@link OutputStream}
-        *      <li>{@link File}
-        * </ul>
+        *      <br>Character-based serializers can handle the following output 
class types:
+        *      <ul>
+        *              <li>{@link Writer}
+        *              <li>{@link OutputStream} - Output will be written as 
UTF-8 encoded stream.
+        *              <li>{@link File} - Output will be written as 
system-default encoded stream.
+        *      </ul>
+        *      <br>Stream-based serializers can handle the following output 
class types:
+        *      <ul>
+        *              <li>{@link OutputStream}
+        *              <li>{@link File}
+        *      </ul>
         * @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.
         */
-       public SerializerSession(SerializerContext ctx, ObjectMap op, Object 
output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType 
mediaType) {
+       public SerializerSession(SerializerContext ctx, ObjectMap op, Object 
output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType 
mediaType, UriContext uriContext) {
                super(ctx, op, locale, timeZone, mediaType);
                this.javaMethod = javaMethod;
                this.output = output;
+               this.uriContext = uriContext != null ? uriContext : new 
UriContext(null, null, null, null);
                if (op == null || op.isEmpty()) {
                        maxDepth = ctx.maxDepth;
                        initialDepth = ctx.initialDepth;
@@ -240,6 +244,15 @@ public class SerializerSession extends BeanSession {
        }
 
        /**
+        * Returns the URI context passed in to this constructor.
+        *
+        * @return The URI context passed in to this constructor.
+        */
+       public final UriContext getUriContext() {
+               return uriContext;
+       }
+
+       /**
         * Returns the {@link SerializerContext#SERIALIZER_maxDepth} setting 
value for this session.
         *
         * @return The {@link SerializerContext#SERIALIZER_maxDepth} setting 
value for this session.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
index 4d1b75a..3f8f8d5 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
@@ -15,6 +15,7 @@ package org.apache.juneau.serializer;
 import java.io.*;
 import java.net.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
 
 /**
@@ -48,21 +49,28 @@ public class SerializerWriter extends Writer {
        /** The base (e.g. <js>https://localhost:9443";</js>) for relative URIs 
with absolute paths (e.g. <js>"/contextPath/my/path"</js>). */
        protected final String absolutePathUriBase;
 
+       /** The URI context of the request. (i.e. the REST request URL broken 
down into authority/context/servlet/pathInfo parts. */
+       protected final UriContext uriContext;
+
        /**
         * @param out The writer being wrapped.
-        * @param useWhitespace If <jk>true</jk>, calling {@link #cr(int)} will 
create an indentation and calling {@link #s()} will write a space character.
+        * @param useWhitespace If <jk>true</jk>, calling {@link #cr(int)} will 
create an indentation and calling
+        *      {@link #s()} will write a space character.
         * @param trimStrings If <jk>true</jk>, strings should be trimmed 
before they're serialized.
         * @param quoteChar The character to write when {@link #q()} is called.
         * @param relativeUriBase The base (e.g. 
<js>https://localhost:9443/contextPath";</js>) for relative URIs (e.g. 
<js>"my/path"</js>).
         * @param absolutePathUriBase The base (e.g. 
<js>https://localhost:9443";</js>) for relative URIs with absolute paths (e.g. 
<js>"/contextPath/my/path"</js>).
+        * @param uriContext The URI context.
+        *      Identifies the current request URI used for resolution of URIs 
to absolute or root-relative form.
         */
-       public SerializerWriter(Writer out, boolean useWhitespace, boolean 
trimStrings, char quoteChar, String relativeUriBase, String 
absolutePathUriBase) {
+       public SerializerWriter(Writer out, boolean useWhitespace, boolean 
trimStrings, char quoteChar, String relativeUriBase, String 
absolutePathUriBase, UriContext uriContext) {
                this.out = out;
                this.useWhitespace = useWhitespace;
                this.trimStrings = trimStrings;
                this.quoteChar = quoteChar;
                this.relativeUriBase = relativeUriBase;
                this.absolutePathUriBase = absolutePathUriBase;
+               this.uriContext = uriContext != null ? uriContext : new 
UriContext(null, null, null, null);
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
index 21d5f9c..e379415 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
@@ -29,7 +29,7 @@ import org.apache.juneau.utils.*;
  * This class is typically the parent class of all character-based serializers.
  * It has 2 abstract methods to implement...
  * <ul class='spaced-list'>
- *     <li>{@link #createSession(Object, ObjectMap, Method, Locale, TimeZone, 
MediaType)}
+ *     <li>{@link #createSession(Object, ObjectMap, Method, Locale, TimeZone, 
MediaType, UriContext)}
  *     <li>{@link #doSerialize(SerializerSession, Object)}
  * </ul>
  *

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
index 16317d6..b358920 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
@@ -376,8 +376,8 @@ public class UonSerializer extends WriterSerializer {
        
//--------------------------------------------------------------------------------
 
        @Override /* Serializer */
-       public UonSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
-               return new UonSerializerSession(ctx, null, op, output, 
javaMethod, locale, timeZone, mediaType);
+       public UonSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
+               return new UonSerializerSession(ctx, null, 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/uon/UonSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
index 1e3b68c..0f9b5a1 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
@@ -38,20 +38,22 @@ public class UonSerializerSession 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 encode Override the {@link 
UonSerializerContext#UON_encodeChars} setting.
         * @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 UonSerializerSession(UonSerializerContext ctx, Boolean 
encode, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone 
timeZone, MediaType mediaType) {
-               super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+       protected UonSerializerSession(UonSerializerContext ctx, Boolean 
encode, 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()) {
                        encodeChars = encode == null ? ctx.encodeChars : encode;
                        addBeanTypeProperties = ctx.addBeanTypeProperties;
@@ -85,6 +87,6 @@ public class UonSerializerSession extends SerializerSession {
                Object output = getOutput();
                if (output instanceof UonWriter)
                        return (UonWriter)output;
-               return new UonWriter(this, super.getWriter(), 
isUseWhitespace(), isEncodeChars(), isTrimStrings(), getRelativeUriBase(), 
getAbsolutePathUriBase());
+               return new UonWriter(this, super.getWriter(), 
isUseWhitespace(), isEncodeChars(), isTrimStrings(), getRelativeUriBase(), 
getAbsolutePathUriBase(), getUriContext());
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java 
b/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
index d897e6d..85f9cd0 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
@@ -14,6 +14,7 @@ package org.apache.juneau.uon;
 
 import java.io.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
 
@@ -54,9 +55,11 @@ public final class UonWriter extends SerializerWriter {
         * @param trimStrings If <jk>true</jk>, strings should be trimmed 
before they're serialized.
         * @param relativeUriBase The base (e.g. 
<js>https://localhost:9443/contextPath";</js>) for relative URIs (e.g. 
<js>"my/path"</js>).
         * @param absolutePathUriBase The base (e.g. 
<js>https://localhost:9443";</js>) for relative URIs with absolute paths (e.g. 
<js>"/contextPath/my/path"</js>).
+        * @param uriContext The URI context.
+        *      Identifies the current request URI used for resolution of URIs 
to absolute or root-relative form.
         */
-       protected UonWriter(UonSerializerSession session, Writer out, boolean 
useWhitespace, boolean encodeChars, boolean trimStrings, String 
relativeUriBase, String absolutePathUriBase) {
-               super(out, useWhitespace, trimStrings, '\'', relativeUriBase, 
absolutePathUriBase);
+       protected UonWriter(UonSerializerSession session, Writer out, boolean 
useWhitespace, boolean encodeChars, boolean trimStrings, String 
relativeUriBase, String absolutePathUriBase, UriContext uriContext) {
+               super(out, useWhitespace, trimStrings, '\'', relativeUriBase, 
absolutePathUriBase, uriContext);
                this.session = session;
                this.encodeChars = encodeChars;
        }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
 
b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index a93ca54..1814833 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -412,7 +412,7 @@ public class UrlEncodingSerializer extends UonSerializer {
                        }
 
                        StringWriter w = new StringWriter();
-                       UonSerializerSession s = new 
UrlEncodingSerializerSession(ctx, urlEncode, null, w, null, null, null, 
MediaType.UON);
+                       UonSerializerSession s = new 
UrlEncodingSerializerSession(ctx, urlEncode, null, w, null, null, null, 
MediaType.UON, null);
                        super.doSerialize(s, o);
                        return w.toString();
                } catch (Exception e) {
@@ -426,8 +426,8 @@ public class UrlEncodingSerializer extends UonSerializer {
        
//--------------------------------------------------------------------------------
 
        @Override /* Serializer */
-       public UrlEncodingSerializerSession createSession(Object output, 
ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType 
mediaType) {
-               return new UrlEncodingSerializerSession(ctx, null, op, output, 
javaMethod, locale, timeZone, mediaType);
+       public UrlEncodingSerializerSession createSession(Object output, 
ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType 
mediaType, UriContext uriContext) {
+               return new UrlEncodingSerializerSession(ctx, null, 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/urlencoding/UrlEncodingSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
index 1802dc2..a7a93e3 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
@@ -33,20 +33,22 @@ public class UrlEncodingSerializerSession extends 
UonSerializerSession {
         * 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 encode Overrides the {@link 
UonSerializerContext#UON_encodeChars} setting.
         * @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.
         */
-       public UrlEncodingSerializerSession(UrlEncodingSerializerContext ctx, 
Boolean encode, ObjectMap op, Object output, Method javaMethod, Locale locale, 
TimeZone timeZone, MediaType mediaType) {
-               super(ctx, encode, op, output, javaMethod, locale, timeZone, 
mediaType);
+       public UrlEncodingSerializerSession(UrlEncodingSerializerContext ctx, 
Boolean encode, ObjectMap op, Object output, Method javaMethod, Locale locale, 
TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
+               super(ctx, encode, op, output, javaMethod, locale, timeZone, 
mediaType, uriContext);
                if (op == null || op.isEmpty()) {
                        expandedParams = ctx.expandedParams;
                        plainTextParams = ctx.plainTextParams;

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
index a84d41f..0e42c27 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
@@ -95,7 +95,7 @@ public class XmlSchemaSerializer extends XmlSerializer {
        /**
         * Returns an XML-Schema validator based on the output returned by 
{@link #doSerialize(SerializerSession, Object)};
         *
-        * @param session The serializer session object return by {@link 
#createSession(Object, ObjectMap, Method, Locale, TimeZone, MediaType)}.<br>
+        * @param session The serializer session object return by {@link 
#createSession(Object, ObjectMap, Method, Locale, TimeZone, MediaType, 
UriContext)}.<br>
         * Can be <jk>null</jk>.
         * @param o The object to serialize.
         * @return The new validator.
@@ -266,7 +266,7 @@ public class XmlSchemaSerializer extends XmlSerializer {
                        this.defaultNs = defaultNs;
                        this.targetNs = targetNs;
                        this.session = session;
-                       w = new XmlWriter(sw, session.isUseWhitespace(), 
session.isTrimStrings(), session.getQuoteChar(), null, null, true, null);
+                       w = new XmlWriter(sw, session.isUseWhitespace(), 
session.isTrimStrings(), session.getQuoteChar(), null, null, null, true, null);
                        int i = session.getIndent();
                        w.oTag(i, "schema");
                        w.attr("xmlns", xs.getUri());
@@ -580,11 +580,11 @@ public class XmlSchemaSerializer extends XmlSerializer {
        }
 
        @Override /* Serializer */
-       public XmlSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
+       public XmlSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
                // This serializer must always have namespaces enabled.
                if (op == null)
                        op = new ObjectMap();
                op.put(XmlSerializerContext.XML_enableNamespaces, true);
-               return new XmlSerializerSession(ctx, op, output, javaMethod, 
locale, timeZone, mediaType);
+               return new XmlSerializerSession(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/xml/XmlSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
index 4b63fa5..cd46134 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -831,7 +831,7 @@ public class XmlSerializer extends WriterSerializer {
        }
 
        @Override /* Serializer */
-       public XmlSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
-               return new XmlSerializerSession(ctx, op, output, javaMethod, 
locale, timeZone, mediaType);
+       public XmlSerializerSession createSession(Object output, ObjectMap op, 
Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
+               return new XmlSerializerSession(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/xml/XmlSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
index 36b481a..ef08f48 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
@@ -50,19 +50,21 @@ public class XmlSerializerSession 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.
         */
-       public XmlSerializerSession(XmlSerializerContext ctx, ObjectMap op, 
Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType 
mediaType) {
-               super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
+       public XmlSerializerSession(XmlSerializerContext 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()) {
                        enableNamespaces = ctx.enableNamespaces;
                        autoDetectNamespaces = ctx.autoDetectNamespaces;
@@ -198,6 +200,6 @@ public class XmlSerializerSession extends SerializerSession 
{
                Object output = getOutput();
                if (output instanceof XmlWriter)
                        return (XmlWriter)output;
-               return new XmlWriter(super.getWriter(), isUseWhitespace(), 
isTrimStrings(), getQuoteChar(), getRelativeUriBase(), 
getAbsolutePathUriBase(), isEnableNamespaces(), getDefaultNamespace());
+               return new XmlWriter(super.getWriter(), isUseWhitespace(), 
isTrimStrings(), getQuoteChar(), getRelativeUriBase(), 
getAbsolutePathUriBase(), getUriContext(), isEnableNamespaces(), 
getDefaultNamespace());
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/java/org/apache/juneau/xml/XmlWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlWriter.java 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlWriter.java
index 6f5ac83..6b8caeb 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlWriter.java
@@ -14,6 +14,7 @@ package org.apache.juneau.xml;
 
 import java.io.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.xml.annotation.*;
 
@@ -39,11 +40,13 @@ public class XmlWriter extends SerializerWriter {
         * @param quoteChar The quote character to use for attributes.  Should 
be <js>'\''</js> or <js>'"'</js>.
         * @param relativeUriBase The base (e.g. 
<js>https://localhost:9443/contextPath";</js>) for relative URIs (e.g. 
<js>"my/path"</js>).
         * @param absolutePathUriBase The base (e.g. 
<js>https://localhost:9443";</js>) for relative URIs with absolute paths (e.g. 
<js>"/contextPath/my/path"</js>).
+        * @param uriContext The URI context.
+        *      Identifies the current request URI used for resolution of URIs 
to absolute or root-relative form.
         * @param enableNs Flag to indicate if XML namespaces are enabled.
         * @param defaultNamespace The default namespace if XML namespaces are 
enabled.
         */
-       public XmlWriter(Writer out, boolean useWhitespace, boolean 
trimStrings, char quoteChar, String relativeUriBase, String 
absolutePathUriBase, boolean enableNs, Namespace defaultNamespace) {
-               super(out, useWhitespace, trimStrings, quoteChar, 
relativeUriBase, absolutePathUriBase);
+       public XmlWriter(Writer out, boolean useWhitespace, boolean 
trimStrings, char quoteChar, String relativeUriBase, String 
absolutePathUriBase, UriContext uriContext, boolean enableNs, Namespace 
defaultNamespace) {
+               super(out, useWhitespace, trimStrings, quoteChar, 
relativeUriBase, absolutePathUriBase, uriContext);
                this.enableNs = enableNs;
                this.defaultNsPrefix = defaultNamespace == null ? null : 
defaultNamespace.name;
        }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/javadoc/doc-files/HtmlRender_1.png
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/javadoc/doc-files/HtmlRender_1.png 
b/juneau-core/src/main/javadoc/doc-files/HtmlRender_1.png
new file mode 100644
index 0000000..f070aea
Binary files /dev/null and 
b/juneau-core/src/main/javadoc/doc-files/HtmlRender_1.png differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-core/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/javadoc/overview.html 
b/juneau-core/src/main/javadoc/overview.html
index f9f7088..7a90651 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -6123,6 +6123,9 @@
                                        <li>{@link 
org.apache.juneau.ini.ConfigFile#getObjectWithDefault(String,Object,Class) 
getObjectWithDefault(String,Object,Class)} 
                                </ul>
                        <li>New ability to interact with config file sections 
with proxy interfaces with new method {@link 
org.apache.juneau.ini.ConfigFile#getSectionAsInterface(String,Class)}.
+                       <li>New {@link 
org.apache.juneau.html.annotation.Html#render() @Html.render()} annotation and 
{@link org.apache.juneau.html.HtmlRender} class that allows you
+                               to customize the HTML output and CSS style on 
bean properties:<br>
+                               <img class='bordered' 
src='doc-files/HtmlRender_1.png'>
                </ul>
 
                <h6 class='topic'>org.apache.juneau.rest</h6>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/FileSpaceResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/FileSpaceResource.java
 
b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/FileSpaceResource.java
new file mode 100644
index 0000000..9cdd5f4
--- /dev/null
+++ 
b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/FileSpaceResource.java
@@ -0,0 +1,148 @@
+// 
***************************************************************************************************************************
+// * 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.examples.rest;
+
+import static org.apache.juneau.dto.html5.HtmlBuilder.*;
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.html.*;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.microservice.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Sample REST resource that shows how to use the HtmlRender class.
+ */
+@RestResource(
+       path="/fileSpace",
+       title="Available file space resource",
+       description="Shows how to use HtmlRender class to customize HTML 
output.",
+       
pageLinks="{up:'$R{requestParentURI}',options:'?method=OPTIONS',source:'$C{Source/gitHub}/org/apache/juneau/examples/rest/EnhancedHtmlResource.java'}"
+)
+public class FileSpaceResource extends Resource {
+       private static final long serialVersionUID = 1L;
+
+       private static final FileSpace[] fileSpaces = {
+               new FileSpace("C:", 1000000000, 775000000),
+               new FileSpace("D:", 100000000, 87500000),
+               new FileSpace("E:", 100000000, 97500000),
+               new FileSpace("F:", 100000000, 5000000)
+       };
+       
+       /**
+        * Our bean class being serialized.
+        * Properties are listed to ensure order across all JVMs.
+        */
+       @Bean(properties="drive,total,available,pctFull,status")
+       public static class FileSpace {
+
+               private final String drive;
+               private final long total, available;
+               
+               public FileSpace(String drive, long total, long available) {
+                       this.drive = drive;
+                       this.total = total;
+                       this.available = available;
+               }
+
+               @Html(link="drive/{drive}")
+               public String getDrive() {
+                       return drive;
+               }
+
+               public long getTotal() {
+                       return total;
+               }
+
+               public long getAvailable() {
+                       return available;
+               }
+
+               @Html(render=FileSpacePctRender.class)
+               public float getPctFull() {
+                       return ((100 * available) / total);
+               }
+               
+               @Html(render=FileSpaceStatusRender.class)
+               public FileSpaceStatus getStatus() {
+                       float pf = getPctFull();
+                       if (pf < 80)
+                               return FileSpaceStatus.OK;
+                       if (pf < 90)
+                               return FileSpaceStatus.WARNING;
+                       return FileSpaceStatus.SEVERE;
+               }
+       }
+       
+       public static enum FileSpaceStatus {
+               OK, WARNING, SEVERE;
+       }
+       
+       public static class FileSpacePctRender extends HtmlRender<Float> {
+
+               @Override
+               public String getStyle(SerializerSession session, Float value) {
+                       if (value < 80)
+                               return 
"background-color:lightgreen;text-align:center";
+                       if (value < 90)
+                               return 
"background-color:yellow;text-align:center";
+                       return 
"background-color:red;text-align:center;border:;animation:color_change 0.5s 
infinite alternate";
+               }
+
+               @Override
+               public Object getContent(SerializerSession session, Float 
value) {
+                       if (value >= 90) 
+                               return div(
+                                       String.format("%.0f%%", value), 
+                                       style("@keyframes color_change { from { 
background-color: red; } to { background-color: yellow; }")
+                               );
+                       return String.format("%.0f%%", value);
+               }
+       }
+       
+       public static class FileSpaceStatusRender extends 
HtmlRender<FileSpaceStatus> {
+
+               @Override
+               public String getStyle(SerializerSession session, 
FileSpaceStatus value) {
+                       return "text-align:center";
+               }
+
+               @Override
+               public Object getContent(SerializerSession session, 
FileSpaceStatus value) {
+                       String resourceUri = 
session.getUriContext().getRootRelativeServletPath();
+                       switch (value) {
+                               case OK:  return img().src(resourceUri + 
"/htdocs/ok.png");
+                               case WARNING:  return img().src(resourceUri + 
"/htdocs/warning.png");
+                               default: return img().src(resourceUri + 
"/htdocs/severe.png");
+                       }
+               }
+       }
+
+       /** GET request handler */
+       @RestMethod(name="GET", path="/")
+       public FileSpace[] getFileSpaceMetrics() {
+               return fileSpaces;
+       }
+
+       @RestMethod(name="GET", path="drive/{drive}")
+       public FileSpace getFileSpaceMetric(String drive) throws RestException {
+               for (FileSpace fc : fileSpaces)
+                       if (fc.drive.equals(drive))
+                               return fc;
+               throw new RestException(HttpServletResponse.SC_NOT_FOUND, 
"Drive not found.");
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
----------------------------------------------------------------------
diff --git 
a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
 
b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
index 6ce7e38..726ae3b 100644
--- 
a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
+++ 
b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
@@ -43,6 +43,7 @@ import org.apache.juneau.rest.annotation.*;
                ConfigResource.class,
                LogsResource.class,
                DockerRegistryResource.class,
+               FileSpaceResource.class,
                ShutdownResource.class
        }
 )

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/ok.png
----------------------------------------------------------------------
diff --git 
a/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/ok.png
 
b/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/ok.png
new file mode 100644
index 0000000..31d84f7
Binary files /dev/null and 
b/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/ok.png
 differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/severe.png
----------------------------------------------------------------------
diff --git 
a/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/severe.png
 
b/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/severe.png
new file mode 100644
index 0000000..7b71e14
Binary files /dev/null and 
b/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/severe.png
 differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/warning.png
----------------------------------------------------------------------
diff --git 
a/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/warning.png
 
b/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/warning.png
new file mode 100644
index 0000000..7a8ab49
Binary files /dev/null and 
b/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/warning.png
 differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index c12b2c7..83961bc 100644
--- 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -936,7 +936,7 @@ public class RestClientBuilder extends CoreObjectBuilder {
         * @return This object (for method chaining).
         * @see SerializerContext#SERIALIZER_trimStrings
         */
-       public RestClientBuilder trimStringsS(boolean value) {
+       public RestClientBuilder trimStrings(boolean value) {
                return property(SERIALIZER_trimStrings, value);
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
 
b/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
index 645155b..8ff2e52 100644
--- 
a/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
+++ 
b/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
@@ -114,13 +114,13 @@ public class BaseProvider implements 
MessageBodyReader<Object>, MessageBodyWrite
                        if (s.isWriterSerializer()) {
                                WriterSerializer s2 = (WriterSerializer)s;
                                OutputStreamWriter w = new 
OutputStreamWriter(out, IOUtils.UTF8);
-                               SerializerSession session = s.createSession(w, 
mp, null, locale, timeZone, sm.getMediaType());
+                               SerializerSession session = s.createSession(w, 
mp, null, locale, timeZone, sm.getMediaType(), null);
                                s2.serialize(session, o);
                                w.flush();
                                w.close();
                        } else {
                                OutputStreamSerializer s2 = 
(OutputStreamSerializer)s;
-                               SerializerSession session = s.createSession(s2, 
mp, null, locale, timeZone, sm.getMediaType());
+                               SerializerSession session = s.createSession(s2, 
mp, null, locale, timeZone, sm.getMediaType(), null);
                                s2.serialize(session, o);
                                out.flush();
                                out.close();

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
 
b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
index 410060d..c3e3cf0 100644
--- 
a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
+++ 
b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HtmlPropertiesTest.java
@@ -101,7 +101,6 @@ public class HtmlPropertiesTest extends RestTestcase {
        public void testNormalInitTest3() throws Exception {
                RestClient client = TestMicroservice.DEFAULT_CLIENT;
                String s = 
client.doGet("/testHtmlProperties/NormalInit/test3").accept("text/html").getResponseAsString();
-               System.err.println(s);
                assertTrue(s.contains("NormalInit.test3-title"));
                assertTrue(s.contains("NormalInit.test3-text"));
                assertTrue(s.contains("NormalInit.test3-links"));

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
index b4b60ca..e622c8a 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -81,6 +81,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        private Map<String,String> defFormData;
        private RequestPathMatch pathParams;
        private boolean isPost;
+       private UriContext uriContext;
        private String servletURI, relativeServletURI;
        private String charset, defaultCharset;
        private RequestHeaders headers;
@@ -452,6 +453,22 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        
//--------------------------------------------------------------------------------
 
        /**
+        * Returns the URI context of the request.
+        * <p>
+        * The URI context contains all the information about the URI of the 
request, such
+        * as the servlet URI, context path, etc...
+        * 
+        * @return The URI context of the request.
+        */
+       public UriContext getUriContext() {
+               if (uriContext == null) {
+                       String authority = 
StringUtils.getAuthorityUri(super.getRequestURL().toString());
+                       uriContext = new UriContext(authority, 
super.getContextPath(), super.getServletPath(), super.getPathInfo());
+               }
+               return uriContext;
+       }
+
+       /**
         * Same as {@link HttpServletRequest#getPathInfo()} except returns the 
path undecoded.
         *
         * @return The undecoded portion of the URL after the resource URL path 
pattern match.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e1a50566/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
index b8df147..158aca7 100644
--- 
a/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
+++ 
b/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
@@ -60,13 +60,13 @@ public class DefaultHandler implements ResponseHandler {
                                if (! s.isWriterSerializer()) {
                                        OutputStreamSerializer s2 = 
(OutputStreamSerializer)s;
                                        OutputStream os = 
res.getNegotiatedOutputStream();
-                                       SerializerSession session = 
s.createSession(os, p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType);
+                                       SerializerSession session = 
s.createSession(os, p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType, req.getUriContext());
                                        s2.serialize(session, output);
                                        os.close();
                                } else {
                                        WriterSerializer s2 = 
(WriterSerializer)s;
                                        Writer w = res.getNegotiatedWriter();
-                                       SerializerSession session = 
s.createSession(w, p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType);
+                                       SerializerSession session = 
s.createSession(w, p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType, req.getUriContext());
                                        s2.serialize(session, output);
                                        w.close();
                                }

Reply via email to