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/09/08 23:25:37 UTC

svn commit: r21540 [21/27] - in /release/incubator/juneau: juneau-rest-client/ juneau-rest-client/.settings/ juneau-rest-client/bin/ juneau-rest-client/src/ juneau-rest-client/src/main/ juneau-rest-client/src/main/java/ juneau-rest-client/src/main/java...

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/package.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServiceProperties.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServiceProperties.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServiceProperties.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,44 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.remoteable;
+
+import org.apache.juneau.remoteable.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Configurable properties for the {@link RemoteableServlet} class.
+ *
+ * <p>
+ * Properties can be set on the {@link RestServlet} class using the {@link RestResource#properties} or
+ * {@link RestMethod#properties} annotations.
+ *
+ * <p>
+ * These properties can also be passed in as servlet init parameters.
+ *
+ * <p>
+ * These properties are only valid at the class level, not the method level.
+ * Setting them on {@link RestMethod#properties()} has no effect.
+ */
+public final class RemoteableServiceProperties {
+
+	/**
+	 * Only expose interfaces and methods annotated with {@link Remoteable @Remoteable} ({@link Boolean},
+	 * default=<jk>false</jk>).
+	 *
+	 * <p>
+	 * When enabled, the {@link RemoteableServlet} class will only work with annotated remoteable interfaces and methods.
+	 * Otherwise, all public methods can be executed through the service.
+	 */
+	public static final String REMOTEABLE_includeOnlyRemotableMethods = "RemoteableService.includeOnlyRemoteableMethods";
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServiceProperties.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,155 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.remoteable;
+
+import static javax.servlet.http.HttpServletResponse.*;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.dto.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Abstract class for defining Remoteable services.
+ *
+ * <p>
+ * Remoteable services are POJOs whose methods can be invoked remotely through proxy interfaces.
+ *
+ * <p>
+ * To implement a remoteable service, developers must simply subclass from this class and implement the
+ * {@link #getServiceMap()} method that maps java interfaces to POJO instances.
+ *
+ * See <a class='doclink' href='package-summary.html#TOC'>org.apache.juneau.rest.remoteable</a> for details.
+ */
+@SuppressWarnings("serial")
+public abstract class RemoteableServlet extends RestServletDefault {
+
+	private final Map<String,Class<?>> classNameMap = new ConcurrentHashMap<String,Class<?>>();
+
+	//--------------------------------------------------------------------------------
+	// Abstract methods
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * Returns the list of interfaces to their implementation objects.
+	 *
+	 * <p>
+	 * This class is called often and not cached, so any caching should occur in the subclass if necessary.
+	 *
+	 * @return The service map.
+	 * @throws Exception
+	 */
+	protected abstract Map<Class<?>,Object> getServiceMap() throws Exception;
+
+	//--------------------------------------------------------------------------------
+	// REST methods
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * [GET /] - Get the list of all remote interfaces.
+	 *
+	 * @param req The HTTP servlet request.
+	 * @return The list of links to the remote interfaces.
+	 * @throws Exception
+	 */
+	@RestMethod(name="GET", path="/")
+	public List<Link> getInterfaces(RestRequest req) throws Exception {
+		List<Link> l = new LinkedList<Link>();
+		boolean useAll = ! useOnlyAnnotated();
+		for (Class<?> c : getServiceMap().keySet()) {
+			if (useAll || getContext().getBeanContext().getClassMeta(c).isRemoteable())
+				l.add(new Link(c.getName(), "{0}/{1}", req.getRequestURI(), c.getName()));
+		}
+		return l;
+	}
+
+	/**
+	 * [GET /{javaInterface] - Get the list of all remoteable methods on the specified interface name.
+	 *
+	 * @param javaInterface The Java interface name.
+	 * @return The methods defined on the interface.
+	 * @throws Exception
+	 */
+	@RestMethod(name="GET", path="/{javaInterface}")
+	public Collection<String> listMethods(@Path String javaInterface) throws Exception {
+		return getMethods(javaInterface).keySet();
+	}
+
+	/**
+	 * [POST /{javaInterface}/{javaMethod}] - Invoke the specified service method.
+	 *
+	 * @param req The HTTP request.
+	 * @param javaInterface The Java interface name.
+	 * @param javaMethod The Java method name or signature.
+	 * @return The results from invoking the specified Java method.
+	 * @throws Exception
+	 */
+	@RestMethod(name="POST", path="/{javaInterface}/{javaMethod}")
+	public Object invoke(RestRequest req, @Path String javaInterface, @Path String javaMethod) throws Exception {
+
+		// Find the parser.
+		ReaderParser p = req.getBody().getReaderParser();
+		if (p == null)
+			throw new RestException(SC_UNSUPPORTED_MEDIA_TYPE, "Could not find parser for media type ''{0}''", req.getHeaders().getContentType());
+		Class<?> c = getInterfaceClass(javaInterface);
+
+		// Find the service.
+		Object service = getServiceMap().get(c);
+		if (service == null)
+			throw new RestException(SC_NOT_FOUND, "Service not found");
+
+		// Find the method.
+		java.lang.reflect.Method m = getMethods(javaInterface).get(javaMethod);
+		if (m == null)
+			throw new RestException(SC_NOT_FOUND, "Method not found");
+
+		// Parse the args and invoke the method.
+		Object[] params = p.parseArgs(req.getReader(), m.getGenericParameterTypes());
+		return m.invoke(service, params);
+	}
+
+
+	//--------------------------------------------------------------------------------
+	// Other methods
+	//--------------------------------------------------------------------------------
+
+	private boolean useOnlyAnnotated() {
+		return getProperties().getBoolean(RemoteableServiceProperties.REMOTEABLE_includeOnlyRemotableMethods, false);
+	}
+
+	private Map<String,java.lang.reflect.Method> getMethods(String javaInterface) throws Exception {
+		Class<?> c = getInterfaceClass(javaInterface);
+		ClassMeta<?> cm = getContext().getBeanContext().getClassMeta(c);
+		return (useOnlyAnnotated() ? cm.getRemoteableMethods() : cm.getPublicMethods());
+	}
+
+	/**
+	 * Return the <code>Class</code> given it's name if it exists in the services map.
+	 */
+	private Class<?> getInterfaceClass(String javaInterface) throws Exception {
+		Class<?> c = classNameMap.get(javaInterface);
+		if (c == null) {
+			for (Class<?> c2 : getServiceMap().keySet())
+				if (c2.getName().equals(javaInterface)) {
+					classNameMap.put(javaInterface, c2);
+					return c2;
+				}
+			throw new RestException(SC_NOT_FOUND, "Interface class not found");
+		}
+		return c;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/1.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/1.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/2.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/2.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/3.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/3.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/4.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/4.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/5.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/5.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/6.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/doc-files/6.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/package.html
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/package.html (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/package.html Fri Sep  8 23:25:34 2017
@@ -0,0 +1,366 @@
+<!DOCTYPE HTML>
+<!--
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ ***************************************************************************************************************************/
+ -->
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<style type="text/css">
+		/* For viewing in Page Designer */
+		@IMPORT url("../../../../../javadoc.css");
+
+		/* For viewing in REST interface */
+		@IMPORT url("../htdocs/javadoc.css");
+		body { 
+			margin: 20px; 
+		}	
+	</style>
+	<script>
+		/* Replace all @code and @link tags. */	
+		window.onload = function() {
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>');
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>');
+		}
+	</script>
+</head>
+<body>
+<p>Remoteable service API</p>
+
+<script>
+	function toggle(x) {
+		var div = x.nextSibling;
+		while (div != null && div.nodeType != 1)
+			div = div.nextSibling;
+		if (div != null) {
+			var d = div.style.display;
+			if (d == 'block' || d == '') {
+				div.style.display = 'none';
+				x.className += " closed";
+			} else {
+				div.style.display = 'block';
+				x.className = x.className.replace(/(?:^|\s)closed(?!\S)/g , '' );
+			}
+		}
+	}
+</script>
+
+<p>
+	Defines an API for remote proxy interfaces (e.g. Remoteable Services).
+</p>
+
+<a id='TOC'></a><h5 class='toc'>Table of Contents</h5>
+<ol class='toc'>
+	<li><p><a class='doclink' href='#Intro'>Remoteable Services</a></p>
+	<li><p><a class='doclink' href='#Client'>Client Side</a></p> 
+	<li><p><a class='doclink' href='#Server'>Server Side</a></p>
+	<li><p><a class='doclink' href='#RemoteableAnnotation'>@Remoteable Annotation</a></p>
+</ol>
+
+<!-- ======================================================================================================== -->
+<a id="Intro"></a>
+<h2 class='topic' onclick='toggle(this)'>1 - Remoteable Services</h2>
+<div class='topic'>
+	<p>
+		The Remoteable Service API allows for client side code to use interface proxies for calling methods on POJOs on 
+		the server side.
+	</p>
+	<p>
+		Proxy interfaces are retrieved using the {@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class)} 
+		method.
+		The remoteable servlet is a specialized subclass of {@link org.apache.juneau.rest.RestServlet} that provides a 
+		full-blown REST interface for calling remoteable services (e.g. POJOs) remotely. 
+	</p>
+	<p>
+		The following simplified example shows how a method on a POJO on a server can be called through an interface
+		on a client...
+	</p>
+	<p class='bcode'>
+	<jk>public interface</jk> IAddressBook {
+		Person createPerson(CreatePerson cp) <jk>throws</jk> Exception;
+		Person findPerson(<jk>int</jk> id);
+		Address findAddress(<jk>int</jk> id);
+		Person findPersonWithAddress(<jk>int</jk> id);
+	}
+	</p>			
+	<p>
+		The client side code for invoking this method is shown below...
+	</p>
+	<p class='bcode'>
+	<jc>// Create a RestClient using JSON for serialization, and point to the server-side remoteable servlet.</jc>
+	RestClient client = <jk>new</jk> RestClientBuilder()
+		.rootUrl(<js>"https://localhost:9080/juneau/sample/remoteable"</js>)
+		.build();
+	
+	<jc>// Create a proxy interface.</jc>
+	IAddressBook ab = client.getRemoteableProxy(IAddressBook.<jk>class</jk>);
+	
+	<jc>// Invoke a method on the server side and get the returned result.</jc>
+	Person p = ab.createPerson(
+		<jk>new</jk> CreatePerson(<js>"Test Person"</js>,
+			AddressBook.<jsm>toCalendar</jsm>(<js>"Aug 1, 1999"</js>),
+			<jk>new</jk> CreateAddress(<js>"Test street"</js>, <js>"Test city"</js>, <js>"Test state"</js>, 12345, <jk>true</jk>))
+	);
+	</p>
+	<p>
+		The requirements for a method to be callable through the remoteable service are:
+	</p>
+	<ul class='spaced-list'>
+		<li>
+			The method must be public.
+		<li>
+			The parameter and return types must be <a href='../../../../../overview-summary.html#Core.PojoCategories'>serializable and parsable</a>.
+	</ul>
+</div>
+
+<!-- ======================================================================================================== -->
+<a id="Client"></a>
+<h2 class='topic' onclick='toggle(this)'>2 - Client Side</h2>
+<div class='topic'>
+	<p>
+		Remoteable interface proxies are retrieved through the existing {@link org.apache.juneau.rest.client.RestClient} 
+		class.
+	</p>
+	<p>
+		It may seem that the client-side code would need to be complex.
+		In reality, it builds upon existing serializing, parsing, and REST capabilities in Juneau resulting in very 
+		little additional code.
+		The entire code for the <code>RestClient.getRemoteableProxy(Class)</code> method is shown below:
+	</p>
+	<p class='bcode'>
+	<jk>public</jk> &lt;T&gt; T getRemoteableProxy(<jk>final</jk> Class&lt;T&gt; interfaceClass) {
+		<jk>return</jk> (T)Proxy.newProxyInstance(
+			interfaceClass.getClassLoader(),
+			<jk>new</jk> Class[] { interfaceClass },
+			<jk>new</jk> InvocationHandler() {
+				<ja>@Override</ja>
+				<jk>public</jk> Object invoke(Object proxy, Method method, Object[] args) {
+					<jk>try</jk> {
+						String uri = <jf>remoteableServletUri</jf> + '/' + interfaceClass.getName() + '/' + ClassUtils.<jsm>getMethodSignature</jsm>(method);
+						<jk>return</jk> doPost(uri, args).getResponse(method.getReturnType());
+					} <jk>catch</jk> (Exception e) {
+						<jk>throw new</jk> RuntimeException(e);
+					}
+				}
+		});
+	}
+	</p>
+	<p>
+		Since we build upon the existing <code>RestClient</code> API, we inherit all of it's features.
+		For example, convenience methods for setting POJO filters and properties to customize the behavior of the 
+		serializers and parsers, and the ability to provide your own customized Apache <code>HttpClient</code> for 
+		handling various scenarios involving authentication and Internet proxies.
+	</p>
+</div>
+
+<!-- ======================================================================================================== -->
+<a id="Server"></a>
+<h2 class='topic' onclick='toggle(this)'>3 - Server Side</h2>
+<div class='topic'>
+	<p>
+		The server side is only slightly more complex, but boasts useful debugging and discovery capabilities.  
+	</p>
+	<p>
+		The {@link org.apache.juneau.rest.remoteable.RemoteableServlet} class is an implementation of 
+		{@link org.apache.juneau.rest.RestServlet} that provides a REST interface for invoking calls on POJOs.
+		The <code>RemoteableServlet</code> class is abstract and must implement a single method for providing the set 
+		of POJOs to expose as remote interfaces.  
+	</p>
+	<p>
+		The samples bundle includes a sample implementation of a remoteable service that can be used to interact with 
+		the address book POJO also included in the bundle.  
+		The method that must be implemented is {@link org.apache.juneau.rest.remoteable.RemoteableServlet#getServiceMap()}
+		that simply returns a mapping of Java interfaces (or classes) to POJO instances.
+	</p>
+	<p class='bcode'>
+	<ja>@RestResource</ja>(
+		path=<js>"/remoteable"</js>
+	)
+	<jk>public class</jk> SampleRemoteableServlet <jk>extends</jk> RemoteableServlet {
+	
+		<jc>// The POJO being manipulated (i.e. the remoteable service)</jc>
+		AddressBook <jf>addressBook</jf> = <jk>new</jk> AddressBook();
+	
+		<ja>@Override</ja> <jc>/* RemoteableServlet */</jc>
+		<jk>protected</jk> Map&lt;Class&lt;?&gt;,Object&gt; getServiceMap() <jk>throws</jk> Exception {
+			Map&lt;Class&lt;?&gt;,Object&gt; m = <jk>new</jk> LinkedHashMap&lt;Class&lt;?&gt;,Object&gt;();
+	
+			<jc>// In this simplified example, we expose the same POJO service under two different interfaces.
+			// One is IAddressBook which only exposes methods defined on that interface, and
+			// the other is AddressBook itself which exposes all public methods defined on the class itself.</jc>
+			m.put(IAddressBook.<jk>class</jk>, addressBook);
+			m.put(AddressBook.<jk>class</jk>, addressBook);
+			<jk>return</jk> m;
+		}
+	}
+	</p>
+	<p>
+		Since this class is a servlet, and can be deployed as such.  
+		In the sample code, it's listed as a child resource to <code>org.apache.juneau.rest.samples.RootResources</code>
+			which makes it available under the URL <code>/juneau/sample/remoteable</code>.
+	</p>
+	<p>
+		If you point your browser to that URL, you get a list of available interfaces:
+	</p>
+	<img class='bordered' src="doc-files/1.png">
+	<p>
+		Clicking the hyperlinks on each shows you the list of methods that can be invoked on that service.
+		Note that the <code>IAddressBook</code> link shows that you can only invoke methods defined on that
+		interface, whereas the <code>AddressBook</code> link shows ALL public methods defined on that class.
+		Since <code>AddressBook</code> extends from <code>LinkedList</code>, you may notice familiar collections
+		framework methods listed.
+	</p>
+	<img class='bordered' src="doc-files/2.png">
+	<img class='bordered' src="doc-files/3.png">
+	<p>
+		Let's see how we can interact with this interface through nothing more than REST calls to get a better idea on 
+		how this works.
+		We'll use the same method call as in the introduction.
+		First, we need to create the serialized form of the arguments:
+	</p>
+	<p class='bcode'>
+	Object[] args = <jk>new</jk> Object[] {
+		<jk>new</jk> CreatePerson(<js>"Test Person"</js>,
+			AddressBook.<jsm>toCalendar</jsm>(<js>"Aug 1, 1999"</js>),
+			<jk>new</jk> CreateAddress(<js>"Test street"</js>, <js>"Test city"</js>, <js>"Test state"</js>, 12345, <jk>true</jk>))
+	};
+	String asJson = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>.toString(args);
+	System.<jsf>err</jsf>.println(asJson);
+	</p>
+	<p>
+		That produces the following JSON output:
+	</p>
+	<p class='bcode'>
+	[
+		{
+			name: <js>'Test Person'</js>, 
+			birthDate: <js>'Aug 1, 1999'</js>, 
+			addresses: [
+				{
+					street: <js>'Test street'</js>, 
+					city: <js>'Test city'</js>, 
+					state: <js>'Test state'</js>, 
+					zip: 12345, 
+					isCurrent: <jk>true</jk>
+				}
+			]
+		}
+	]	
+	</p>
+	<p>
+		Note that in this example we're using JSON.  
+		However, various other content types can also be used such as XML, URL-Encoding, UON, or HTML.  
+		In practice however, JSON will preferred since it is often the most efficient.
+	</p>
+	<p>
+		Next, we can use a tool such as Poster to make the REST call.
+		Methods are invoked by POSTing the serialized object array to the URI of the interface method.
+		In this case, we want to POST our JSON to <code>/juneau/sample/remoteable/org.apache.juneau.examples.addressbook.IAddressBook/createPerson(org.apache.juneau.examples.addressbook.CreatePerson)</code>.
+		Make sure that we specify the <code>Content-Type</code> of the body as <code>text/json</code>.
+		We also want the results to be returned as JSON, so we set the <code>Accept</code> header to 
+		<code>text/json</code> as well.
+	</p>
+	<img class='bordered' src="doc-files/4.png">
+	<p>
+		When we execute the POST, we should see the following successful response whose body contains the returned 
+		<code>Person</code> bean serialized to JSON:
+	</p>
+	<img class='bordered' src="doc-files/5.png">
+	<p>
+		From there, we could use the following code snippet to reconstruct the response object from JSON:
+	</p>
+	<p class='bcode'>
+		String response = <js>"<i>output from above</i>"</js>;
+		Person p = JsonParser.<jsf>DEFAULT</jsf>.parse(response, Person.<jk>class</jk>);
+	</p>
+	<p>
+		If we alter our servlet to allow overloaded GET requests, we can invoke methods using nothing more than a 
+		browser...
+	</p>
+	<p class='bcode'>
+	<ja>@RestResource</ja>(
+		path=<js>"/remoteable"</js>,
+		properties={
+			<jc>// Allow us to use method=POST from a browser.</jc>
+			<ja>@Property</ja>(name=<jsf>REST_allowMethodParam</jsf>, value=<js>"*"</js>)
+		}
+	)
+	<jk>public class</jk> SampleRemoteableServlet <jk>extends</jk> RemoteableServlet {
+	</p>
+	<p>
+		For example, here we call the <code>findPerson(<jk>int</jk>)</code> method to retrieve a person and get the 
+		returned POJO (in this case as HTML since that's what's in the <code>Accept</code> header when calling from a 
+		browser):
+	</p>
+	<img class='bordered' src="doc-files/6.png">
+	<p>
+		When specifying the POST body as a <code>&amp;content</code> parameter, the method arguments should be in UON 
+		notation.
+		See {@link org.apache.juneau.uon.UonSerializer} for more information about this encoding.
+		Usually you can also pass in JSON if you specify <code>&amp;Content-Type=text/json</code> in the URL parameters
+		but passing in unencoded JSON in a URL may not work in all browsers.  
+		Therefore, UON is preferred.
+	</p>
+</div>
+
+<!-- ======================================================================================================== -->
+<a id="RemoteableAnnotation"></a>
+<h2 class='topic' onclick='toggle(this)'>4 - @Remoteable Annotation</h2>
+<div class='topic'>
+	<p>
+		What if you want fine-tuned control over which methods are exposed in an interface instead of just all public 
+		methods?
+		For this, the {@link org.apache.juneau.remoteable.Remoteable @Remoteable} annotation is provided.
+		It can be applied to individual interface methods to only expose those methods through the remoteable servlet.
+	</p>
+	<p>
+		For example, to expose only the first 2 methods in our <code>IAddressBook</code> interface...
+	</p>
+	<p class='bcode'>
+	<jk>public interface</jk> IAddressBook {
+		<ja>@Remoteable</ja> Person createPerson(CreatePerson cp) <jk>throws</jk> Exception;
+		<ja>@Remoteable</ja> Person findPerson(<jk>int</jk> id);
+		Address findAddress(<jk>int</jk> id);
+		Person findPersonWithAddress(<jk>int</jk> id);
+	}
+	</p>	
+	<p>
+		On the server side, the option to restrict access to only annotated methods is defined through a property:
+	</p>
+	<p class='bcode'>
+	<ja>@RestResource</ja>(
+		path=<js>"/remoteable"</js>,
+		properties={
+			<jc>// Only expose methods annotated with @Remoteable.</jc>
+			<ja>@Property</ja>(name=<jsf>REMOTEABLE_includeOnlyRemotableMethods</jsf>, value=<js>"true"</js>)
+		}
+	)
+	<jk>public class</jk> SampleRemoteableServlet <jk>extends</jk> RemoteableServlet {
+	</p>
+	<p>
+		The <ja>@Remoteable</ja> annotation can also be applied to the interface class to expose all public methods 
+		defined on that interface.
+	</p>
+	<p class='bcode'>
+	<ja>@Remoteable</ja>
+	<jk>public interface</jk> IAddressBook {
+		Person createPerson(CreatePerson cp) <jk>throws</jk> Exception;
+		Person findPerson(<jk>int</jk> id);
+		Address findAddress(<jk>int</jk> id);
+		Person findPersonWithAddress(<jk>int</jk> id);
+	}
+	</p>	
+</div>
+</body>
+</html>
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/package.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,93 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.response;
+
+import static javax.servlet.http.HttpServletResponse.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Response handler for POJOs not handled by other handlers.
+ *
+ * <p>
+ * This uses the serializers defined on the response to serialize the POJO.
+ *
+ * <p>
+ * The {@link Serializer} used is based on the <code>Accept</code> header on the request.
+ *
+ * <p>
+ * The <code>Content-Type</code> header is set to the mime-type defined on the selected serializer based on the
+ * <code>produces</code> value passed in through the constructor.
+ */
+public class DefaultHandler implements ResponseHandler {
+
+	@Override /* ResponseHandler */
+	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
+		SerializerGroup g = res.getSerializerGroup();
+		String accept = req.getHeaders().getString("Accept", "");
+		SerializerMatch sm = g.getSerializerMatch(accept);
+		if (sm != null) {
+			Serializer s = sm.getSerializer();
+			MediaType mediaType = res.getMediaType();
+			if (mediaType == null)
+				mediaType = sm.getMediaType();
+			res.setContentType(mediaType.toString());
+
+			try {
+				ObjectMap p = res.getProperties();
+				if (req.isPlainText()) {
+					res.setContentType("text/plain");
+				}
+				p.append("mediaType", mediaType).append("characterEncoding", res.getCharacterEncoding());
+
+				SerializerSession session = s.createSession(new SerializerSessionArgs(p, req.getJavaMethod(), req.getLocale(), req.getHeaders().getTimeZone(), mediaType, req.getUriContext()));
+
+				for (Map.Entry<String,String> h : session.getResponseHeaders().entrySet())
+					res.setHeader(h.getKey(), h.getValue());
+
+				if (! session.isWriterSerializer()) {
+					if (req.isPlainText()) {
+						Writer w = res.getNegotiatedWriter();
+						ByteArrayOutputStream baos = new ByteArrayOutputStream();
+						session.serialize(baos, output);
+						w.write(StringUtils.toHex(baos.toByteArray()));
+						w.close();  // Leave open if exception occurs.
+					} else {
+						OutputStream os = res.getNegotiatedOutputStream();
+						session.serialize(os, output);
+						os.close();  // Leave open if exception occurs.
+					}
+				} else {
+					Writer w = res.getNegotiatedWriter();
+					session.serialize(w, output);
+					w.close();  // Leave open if exception occurs.
+				}
+			} catch (SerializeException e) {
+				throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+			}
+		} else {
+			throw new RestException(SC_NOT_ACCEPTABLE,
+				"Unsupported media-type in request header ''Accept'': ''{0}''\n\tSupported media-types: {1}",
+				req.getHeaders().getString("Accept", ""), g.getSupportedMediaTypes()
+			);
+		}
+		return true;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/InputStreamHandler.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/InputStreamHandler.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/InputStreamHandler.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,41 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.response;
+
+import java.io.*;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Response handler for {@link InputStream} objects.
+ *
+ * <p>
+ * Simply pipes the contents of the {@link InputStream} to {@link RestResponse#getNegotiatedOutputStream()}.
+ *
+ * <p>
+ * Sets the <code>Content-Type</code> response header to whatever was set via {@link RestResponse#setContentType(String)}.
+ */
+public final class InputStreamHandler implements ResponseHandler {
+
+	@Override /* ResponseHandler */
+	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
+		if (output instanceof InputStream) {
+			res.setHeader("Content-Type", res.getContentType());
+			OutputStream os = res.getNegotiatedOutputStream();
+			IOPipe.create(output, os).closeOut().run();
+			return true;
+		}
+		return false;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/InputStreamHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ReaderHandler.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ReaderHandler.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ReaderHandler.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,38 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.response;
+
+import java.io.*;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Response handler for {@link Reader} objects.
+ *
+ * <p>
+ * Simply pipes the contents of the {@link Reader} to {@link RestResponse#getNegotiatedWriter()}.
+ */
+public final class ReaderHandler implements ResponseHandler {
+
+	@Override /* ResponseHandler */
+	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
+		if (output instanceof Reader) {
+			Writer w = res.getNegotiatedWriter();
+			IOPipe.create(output, w).closeOut().run();
+			return true;
+		}
+		return false;
+	}
+}
+

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ReaderHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/RedirectHandler.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/RedirectHandler.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/RedirectHandler.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,37 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.response;
+
+import java.io.*;
+
+import org.apache.juneau.rest.*;
+
+/**
+ * Response handler for {@link Redirect} objects.
+ */
+public final class RedirectHandler implements ResponseHandler {
+
+	@Override /* ResponseHandler */
+	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
+		if (output instanceof Redirect) {
+			Redirect r = (Redirect)output;
+			String uri = req.getUriResolver().resolve(r.getURI());
+			int rc = r.getHttpResponseCode();
+			if (rc != 0)
+				res.setStatus(rc);   // TODO - This may get ignored by the call below.
+			res.sendRedirect(uri);
+			return true;
+		}
+		return false;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/RedirectHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,51 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.response;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.rest.*;
+
+/**
+ * Response handler for {@link Writable} and {@link ReaderResource} objects.
+ *
+ * <p>
+ * Uses the {@link Writable#writeTo(Writer)} method to send the contents to the
+ * {@link RestResponse#getNegotiatedWriter()} writer.
+ */
+public final class StreamableHandler implements ResponseHandler {
+
+	@Override /* ResponseHandler */
+	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
+		if (output instanceof Streamable) {
+			if (output instanceof StreamResource) {
+				StreamResource r = (StreamResource)output;
+				MediaType mediaType = r.getMediaType();
+				if (mediaType != null)
+					res.setContentType(mediaType.toString());
+				for (Map.Entry<String,String> h : r.getHeaders().entrySet())
+					res.setHeader(h.getKey(), h.getValue());
+			}
+			OutputStream os = res.getOutputStream();
+			((Streamable)output).streamTo(os);
+			os.flush();
+			os.close();
+			return true;
+		}
+		return false;
+	}
+}
+

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,50 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.response;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.rest.*;
+
+/**
+ * Response handler for {@link Writable} and {@link ReaderResource} objects.
+ *
+ * <p>
+ * Uses the {@link Writable#writeTo(Writer)} method to send the contents to the {@link RestResponse#getNegotiatedWriter()} writer.
+ */
+public final class WritableHandler implements ResponseHandler {
+
+	@Override /* ResponseHandler */
+	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
+		if (output instanceof Writable) {
+			if (output instanceof ReaderResource) {
+				ReaderResource r = (ReaderResource)output;
+				MediaType mediaType = r.getMediaType();
+				if (mediaType != null)
+					res.setContentType(mediaType.toString());
+				for (Map.Entry<String,String> h : r.getHeaders().entrySet())
+					res.setHeader(h.getKey(), h.getValue());
+			}
+			Writer w = res.getNegotiatedWriter();
+			((Writable)output).writeTo(w);
+			w.flush();
+			w.close();
+			return true;
+		}
+		return false;
+	}
+}
+

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ZipFileListResponseHandler.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ZipFileListResponseHandler.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ZipFileListResponseHandler.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,66 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.response;
+
+import java.io.*;
+import java.util.zip.*;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.utils.*;
+import org.apache.juneau.utils.ZipFileList.*;
+
+/**
+ * Response handler for ZipFileList objects.
+ *
+ * <p>
+ * Can be associated with a REST resource using the {@link RestResource#responseHandlers} annotation.
+ *
+ * <p>
+ * Sets the following headers:
+ * <ul class='spaced-list'>
+ * 	<li>
+ * 		<code>Content-Type</code> - <code>application/zip</code>
+ * 	<li>
+ * 		<code>Content-Disposition=attachment;filename=X</code> - Sets X to the file name passed in through the
+ * 		constructor {@link ZipFileList#ZipFileList(String)}.
+ * </ul>
+ */
+public class ZipFileListResponseHandler implements ResponseHandler {
+
+	@Override /* ResponseHandler */
+	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
+		if (output.getClass() == ZipFileList.class) {
+			ZipFileList m = (ZipFileList)output;
+			res.setContentType("application/zip");
+			res.setHeader("Content-Disposition", "attachment;filename=" + m.fileName); //$NON-NLS-2$
+			OutputStream os = res.getOutputStream();
+			try {
+				ZipOutputStream zos = new ZipOutputStream(os);
+				try {
+					for (ZipFileEntry e : m)
+						e.write(zos);
+				} catch (Exception e) {
+					e.printStackTrace();
+				} finally {
+					zos.flush();
+					zos.close();
+				}
+			} finally {
+				os.flush();
+			}
+			return true;
+		}
+		return false;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/ZipFileListResponseHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/package.html
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/package.html (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/package.html Fri Sep  8 23:25:34 2017
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<!--
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ ***************************************************************************************************************************/
+ -->
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<style type="text/css">
+		/* For viewing in Page Designer */
+		@IMPORT url("../../../../javadoc.css");
+
+		/* For viewing in REST interface */
+		@IMPORT url("../htdocs/javadoc.css");
+		body { 
+			margin: 20px; 
+		}	
+	</style>
+	<script>
+		/* Replace all @code and @link tags. */	
+		window.onload = function() {
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>');
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>');
+		}
+	</script>
+</head>
+<body>
+<p>HTTP Response handlers</p>
+</body>
+</html>
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/package.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/FileVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/FileVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/FileVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,86 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.svl.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * File resource variable resolver
+ *
+ * <p>
+ * The format for this var is <js>"$F{path[,defaultValue]}"</js>.
+ *
+ * <p>
+ * File variables resolve to the contents of resource files located on the classpath or local JVM directory.
+ * They use the {@link RestRequest#getReaderResource(String)} method to retrieve the contents of the file.
+ * That in turn uses the {@link ResourceFinder} associated with the servlet class to find the file.
+ *
+ * <p>
+ * The {@link ResourceFinder} is similar to {@link Class#getResourceAsStream(String)} except if it doesn't find the
+ * resource on this class, it searches up the parent hierarchy chain.
+ *
+ * <p>
+ * If the resource cannot be found in the classpath, then an attempt is made to look in the JVM working directory.
+ * <br>Path traversals outside the working directory are not allowed for security reasons.
+
+ * <p>
+ * Localized resources (based on the locale of the HTTP request) are supported.
+ * For example, if looking for the resource <js>"MyResource.txt"</js> for the Japanese locale, we will look for
+ * files in the following order:
+ * <ol>
+ * 	<li><js>"MyResource_ja_JP.txt"</js>
+ * 	<li><js>"MyResource_ja.txt"</js>
+ * 	<li><js>"MyResource.txt"</js>
+ * </ol>
+ *
+ * <p>
+ * Example:
+ * <p class='bcode'>
+ * 	<ja>@RestResource</ja>(
+ * 		htmldoc=<ja>@HtmlDoc</ja>(
+ * 			aside=<js>"$F{resources/MyAsideMessage.html, Oops not found!}"</js>
+ * 		)
+ * 	)
+ * </p>
+ *
+ * <p>
+ * Files of type HTML, XHTML, XML, JSON, Javascript, and CSS will be stripped of comments.
+ * This allows you to place license headers in files without them being serialized to the output.
+ *
+ * @see org.apache.juneau.svl
+ */
+public class FileVar extends DefaultingVar {
+
+	private static final String SESSION_req = "req";
+
+	/**
+	 * The name of this variable.
+	 */
+	public static final String NAME = "F";
+
+	/**
+	 * Constructor.
+	 */
+	public FileVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public String resolve(VarResolverSession session, String key) throws Exception {
+		RestRequest req = session.getSessionObject(RestRequest.class, SESSION_req);
+		ReaderResource rr = req.getReaderResource(key);
+		return (rr == null ? null : rr.toCommentStrippedString());
+	}
+}
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/FileVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/LocalizationVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/LocalizationVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/LocalizationVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,61 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import java.util.*;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Localized string variable resolver.
+ *
+ * <p>
+ * The format for this var is <js>"$L{key[,args...]}"</js>.
+ *
+ * <p>
+ * This variable resolver requires that a {@link RestRequest} object be set as a context object on the resolver or a
+ * session object on the resolver session.
+ *
+ * <p>
+ * Values are pulled from the {@link RestRequest#getMessage(String,Object[])} method.
+ * These in turn are pulled from the resource bundle associated with the servlet class where the request was made.
+ *
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved before they are passed to this var.
+ *
+ * @see org.apache.juneau.svl
+ */
+public class LocalizationVar extends MultipartVar {
+
+	/** The name of this variable. */
+	public static final String NAME = "L";
+
+	/**
+	 * Constructor.
+	 */
+	public LocalizationVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public String resolve(VarResolverSession session, String[] args) {
+		if (args.length > 0) {
+			String key = args[0];
+			String[] a = (args.length > 1) ? Arrays.copyOfRange(args, 1, args.length) : new String[0];
+			return session.getSessionObject(RestRequest.class, RequestVar.SESSION_req).getMessage(key, (Object[])a);
+		}
+		return "";
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/LocalizationVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,101 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Request attribute variable resolver.
+ *
+ * <p>
+ * The format for this var is <js>"$R{key[,defaultValue]}"</js>.
+ *
+ * <p>
+ * The possible values are:
+ * <ul>
+ * 	<li><js>"contextPath"</js> - Value returned by {@link RestRequest#getContextPath()}
+ * 	<li><js>"method"</js> - Value returned by {@link RestRequest#getMethod()}
+ * 	<li><js>"methodDescription"</js> - Value returned by {@link RestRequest#getMethodDescription()}
+ * 	<li><js>"methodSummary"</js> - Value returned by {@link RestRequest#getMethodSummary()}
+ * 	<li><js>"pathInfo"</js> - Value returned by {@link RestRequest#getPathInfo()}
+ * 	<li><js>"requestParentURI"</js> - Value returned by {@link UriContext#getRootRelativePathInfoParent()}
+ * 	<li><js>"requestURI"</js> - Value returned by {@link RestRequest#getRequestURI()}
+ * 	<li><js>"servletDescription"</js> - Value returned by {@link RestRequest#getServletDescription()}
+ * 	<li><js>"servletParentURI"</js> - Value returned by {@link UriContext#getRootRelativeServletPathParent()}
+ * 	<li><js>"servletPath"</js> - See {@link RestRequest#getServletPath()}
+ * 	<li><js>"servletTitle"</js> - See {@link RestRequest#getServletTitle()}
+ * 	<li><js>"servletURI"</js> - See {@link UriContext#getRootRelativeServletPath()}
+ * 	<li><js>"siteName"</js> - See {@link RestRequest#getSiteName()}
+ * 	<li><js>"Attribute.x"</js> - Value returned by {@link HttpServletRequest#getAttribute(String)}.
+ * 	<li><js>"FormData.x"</js> - Value returned by {@link RestRequest#getFormData(String)}.
+ * 	<li><js>"Header.x"</js> - Value returned by {@link RestRequest#getHeader(String)}.
+ * 	<li><js>"Path.x"</js> - Value returned by {@link RestRequest#getPath(String)}.
+ * 	<li><js>"Query.x"</js> = Value returned by {@link RestRequest#getQuery(String)}.
+ * </ul>
+ * <p>
+ * This variable resolver requires that a {@link RestRequest} object be set as a context object on the resolver or a
+ * session object on the resolver session.
+ *
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved before they are passed to this var.
+ *
+ * @see org.apache.juneau.svl
+ */
+public class RequestVar extends DefaultingVar {
+
+	/**
+	 * The name of the session or context object that identifies the {@link RestRequest} object.
+	 */
+	public static final String SESSION_req = "req";
+
+
+	/** The name of this variable. */
+	public static final String NAME = "R";
+
+	/**
+	 * Constructor.
+	 */
+	public RequestVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public String resolve(VarResolverSession session, String key) {
+		RestRequest req = session.getSessionObject(RestRequest.class, SESSION_req);
+		if (key.length() > 0) {
+				String k = key.toString();
+				int i = k.indexOf('.');
+				if (i != -1) {
+					String prefix = k.substring(0, i);
+					String remainder = k.substring(i+1);
+					Object o = req.resolveProperty(null, prefix, remainder);
+					if (o != null)
+						return o.toString();
+				} else {
+					Object o = req.resolveProperty(null, "Request", key);
+					if (o != null)
+						return o.toString();
+				}
+				Object o = req.getProperties().get(key);
+				if (o != null)
+					return o.toString();
+				return req.getPathMatch().get(key);
+			}
+		return null;
+	}
+}
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/SerializedRequestAttrVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/SerializedRequestAttrVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/SerializedRequestAttrVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,67 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.io.*;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Serialized request attribute variable resolver.
+ *
+ * <p>
+ * The format for this var is <js>"$SA{contentType,key[,defaultValue]}"</js>.
+ *
+ * <p>
+ * This variable resolver requires that a {@link RestRequest} object be set as a context object on the resolver or a
+ * session object on the resolver session.
+ *
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved before they are passed to this var.
+ *
+ * @see org.apache.juneau.svl
+ */
+public class SerializedRequestAttrVar extends StreamedVar {
+
+	/** The name of this variable. */
+	public static final String NAME = "SA";
+
+	/**
+	 * Constructor.
+	 */
+	public SerializedRequestAttrVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public void resolveTo(VarResolverSession session, Writer w, String key) throws Exception {
+		int i = key.indexOf(',');
+		if (i == -1)
+			throw new RuntimeException("Invalid format for $SA var.  Must be of the format $SA{contentType,key[,defaultValue]}");
+		String[] s2 = split(key);
+		RestRequest req = session.getSessionObject(RestRequest.class, RequestVar.SESSION_req);
+		if (req != null) {
+			Object o = req.getAttribute(key);
+			if (o == null)
+				o = key;
+			Serializer s = req.getSerializerGroup().getSerializer(s2[0]);
+			if (s != null)
+				s.serialize(w, o);
+		}
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/SerializedRequestAttrVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/ServletInitParamVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/ServletInitParamVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/ServletInitParamVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,53 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Servlet init parameter variable resolver.
+ *
+ * <p>
+ * The format for this var is <js>"$I{key[,defaultValue]}"</js>.
+ *
+ * <p>
+ * This variable resolver requires that a {@link RestRequest} object be set as a context object on the resolver or a
+ * session object on the resolver session.
+ *
+ * <p>
+ * Values are pulled from the {@link RestServlet#getInitParameter(String)} method.
+ *
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved before they are passed to this var.
+ *
+ * @see org.apache.juneau.svl
+ */
+public class ServletInitParamVar extends DefaultingVar {
+
+	/** The name of this variable. */
+	public static final String NAME = "I";
+
+	/**
+	 * Constructor.
+	 */
+	public ServletInitParamVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public String resolve(VarResolverSession session, String key) {
+		return session.getSessionObject(RestRequest.class, RequestVar.SESSION_req).getContext().getServletInitParameter(key);
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/ServletInitParamVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlEncodeVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlEncodeVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlEncodeVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,52 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * URL-encoding variable resolver.
+ *
+ * <p>
+ * The format for this var is <js>"$UE{uriPart}"</js>.
+ *
+ * <p>
+ * This variable takes the contents inside the variable and replaces it with a value returned by calling
+ * {@link StringUtils#urlEncode(String)}).
+ *
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved before they are passed to this var.
+ *
+ * @see org.apache.juneau.svl
+ */
+public class UrlEncodeVar extends SimpleVar {
+
+	/** The name of this variable. */
+	public static final String NAME = "UE";
+
+	/**
+	 * Constructor.
+	 */
+	public UrlEncodeVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public String resolve(VarResolverSession session, String key) {
+		return urlEncode(key);
+	}
+}
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlEncodeVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,62 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * URL variable resolver.
+ *
+ * <p>
+ * The format for this var is <js>"$U{uri}"</js>.
+ *
+ * <p>
+ * The advantage of using this variable is that you can resolve URLs with special protocols such as
+ * <js>"servlet:/xxx"</js>.
+ *
+ * <p>
+ * See {@link UriResolver} for the kinds of URIs that can be resolved.
+ * <ul>
+ * 	<li>{@link HtmlDoc#widgets() @HtmlDoc.widgets()}
+ * 	<li>{@link RestConfig#addHtmlWidget(Class)}
+ * </ul>
+ *
+ * <p>
+ * Uses the URI resolver returned by {@link RestRequest#getUriResolver(UriResolution, UriRelativity)} with resolution
+ * {@link UriResolution#ROOT_RELATIVE} and relativity {@link UriRelativity#RESOURCE}.
+ *
+ * @see org.apache.juneau.svl
+ */
+public class UrlVar extends SimpleVar {
+
+	private static final String SESSION_req = "req";
+
+	/** The name of this variable. */
+	public static final String NAME = "U";
+
+	/**
+	 * Constructor.
+	 */
+	public UrlVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public String resolve(VarResolverSession session, String key) {
+		RestRequest req = session.getSessionObject(RestRequest.class, SESSION_req);
+		return req.getUriResolver().resolve(key);
+	}
+}
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/UrlVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain