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 2016/08/01 17:30:15 UTC

[26/53] [partial] incubator-juneau git commit: Merge changes from GitHub repo.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletContext.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletContext.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletContext.java
new file mode 100755
index 0000000..f093a35
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletContext.java
@@ -0,0 +1,218 @@
+/***************************************************************************************************************************
+ * 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.server;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.server.annotation.*;
+
+/**
+ * Configurable properties on the {@link RestServlet} 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 or system properties.
+ * <p>
+ * Some of these properties are only applicable on the servlet class, and others can be specified on the servlet class or method.<br>
+ * These distinctions are noted below.
+ * <p>
+ * See {@link ContextFactory} for more information about context properties.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+public final class RestServletContext extends Context {
+
+	/**
+	 * Allow header URL parameters ({@link Boolean}, default=<jk>true</jk>).
+	 * <p>
+	 * When enabled, headers such as <js>"Accept"</js> and <js>"Content-Type"</js> to be passed in as URL query parameters.
+	 * For example:  <js>"?Accept=text/json&Content-Type=text/json"</js>
+	 * <p>
+	 * Parameter names are case-insensitive.
+	 * <p>
+	 * Useful for debugging REST interface using only a browser.
+	 * <p>
+	 * Applicable to servlet class only.
+	 */
+	public static final String REST_allowHeaderParams = "RestServlet.allowHeaderParams";
+
+	/**
+	 * Allow <js>"method"</js> URL parameter for specific HTTP methods (String, default=<js>""</js>, example=<js>"HEAD,OPTIONS"</js>).
+	 * <p>
+	 * When specified, the HTTP method can be overridden by passing in a <js>"method"</js> URL parameter on a regular GET request.
+	 * For example:  <js>"?method=OPTIONS"</js>
+	 * <p>
+	 * Parameter name is case-insensitive.  Use "*" to represent all methods.  For backwards compatibility, "true" also means "*".
+	 * <p>
+	 * Note that per the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html">HTTP specification</a>, special care should
+	 * 	be taken when allowing non-safe (POST, PUT, DELETE) methods to be invoked through GET requests.
+	 * <p>
+	 * Applicable to servlet class only.
+	 */
+	public static final String REST_allowMethodParam = "RestServlet.allowMethodParam";
+
+	/**
+	 * Allow <js>"content"</js> URL parameter ({@link Boolean}, default=<jk>true</jk>).
+	 * <p>
+	 * When enabled, the HTTP body content on PUT and POST requests can be passed in as text using the <js>"content"</js> URL parameter.
+	 * For example:  <js>"?content={name:'John%20Smith',age:45}"</js>
+	 * <p>
+	 * Parameter name is case-insensitive.
+	 * <p>
+	 * Useful for debugging PUT and POST methods using only a browser.
+	 * <p>
+	 * Applicable to servlet class only.
+	 */
+	public static final String REST_allowContentParam = "RestServlet.allowContentParam";
+
+	/**
+	 * Render stack traces in HTTP response bodies when errors occur ({@link Boolean}, default=<jk>false</jk>).
+	 * <p>
+	 * When enabled, Java stack traces will be rendered in the output response.
+	 * Useful for debugging, although allowing stack traces to be rendered may cause security concerns.
+	 * <p>
+	 * Applicable to servlet class only.
+	 */
+	public static final String REST_renderResponseStackTraces = "RestServlet.renderResponseStackTraces";
+
+	/**
+	 * Use stack trace hashes ({@link Boolean}, default=<jk>true</jk>).
+	 * <p>
+	 * When enabled, the number of times an exception has occurred will be determined based on stack trace hashsums,
+	 * made available through the {@link RestException#getOccurrence()} method.
+	 * <p>
+	 * Applicable to servlet class only.
+	 */
+	public static final String REST_useStackTraceHashes = "RestServlet.useStackTraceHashes";
+
+	/**
+	 * The default character encoding for the request and response if not specified on the request ({@link String}>, default=<js>"utf-8"</js>).
+	 * <p>
+	 * Applicable to servlet class and methods.
+	 */
+	public static final String REST_defaultCharset = "RestServlet.defaultCharset";
+
+	/**
+	 * The expected format of request parameters ({@link String}, default=<js>"UON"</js>).
+	 * <p>
+	 * Possible values:
+	 * <ul class='spaced-list'>
+	 * 	<li><js>"UON"</js> - URL-Encoded Object Notation.<br>
+	 *			This notation allows for request parameters to contain arbitrarily complex POJOs.
+	 * 	<li><js>"PLAIN"</js> - Plain text.<br>
+	 *			This treats request parameters as plain text.<br>
+	 *			Only POJOs directly convertable from <l>Strings</l> can be represented in parameters when using this mode.
+	 * </ul>
+	 * <p>
+	 * Note that the parameter value <js>"(foo)"</js> is interpreted as <js>"(foo)"</js> when using plain mode, but
+	 * 	<js>"foo"</js> when using UON mode.
+	 * <p>
+	 * The format can also be specified per-parameter using the {@link Param#format() @Param.format()} and {@link QParam#format() @QParam.format()}
+	 * 	annotations.
+	 * <p>
+	 * Applicable to servlet class and methods.
+	 */
+	public static final String REST_paramFormat = "RestServlet.paramFormat";
+
+	//--------------------------------------------------------------------------------
+	// Automatically added properties.
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * The request servlet path.
+	 * <p>
+	 * Automatically added to properties return by {@link RestServlet#createRequestProperties(org.apache.juneau.ObjectMap, RestRequest)}
+	 * 	and are therefore available through {@link SerializerSession#getProperties()} and {@link ParserSession#getProperties()}.
+	 * <p>
+	 * Equivalent to the value returned by {@link RestRequest#getServletPath()}
+	 */
+	public static final String REST_servletPath = "RestServlet.servletPath";
+
+	/**
+	 * The request servlet URI.
+	 * <p>
+	 * Equivalent to the value returned by {@link RestRequest#getServletURI()}
+	 */
+	public static final String REST_servletURI = "RestServlet.servletURI";
+
+	/**
+	 * The request servlet URI.
+	 * <p>
+	 * Equivalent to the value returned by {@link RestRequest#getRelativeServletURI()}
+	 */
+	public static final String REST_relativeServletURI = "RestServlet.relativeServletURI";
+
+	/**
+	 * The request URI path info.
+	 * <p>
+	 * Automatically added to properties return by {@link RestServlet#createRequestProperties(org.apache.juneau.ObjectMap, RestRequest)}
+	 * 	and are therefore available through {@link SerializerSession#getProperties()} and {@link ParserSession#getProperties()}.
+	 * <p>
+	 * Equivalent to the value returned by {@link RestRequest#getPathInfo()}
+	 */
+	public static final String REST_pathInfo = "RestServlet.pathInfo";
+
+	/**
+	 * The request URI.
+	 * <p>
+	 * Automatically added to properties return by {@link RestServlet#createRequestProperties(org.apache.juneau.ObjectMap, RestRequest)}
+	 * 	and are therefore available through {@link SerializerSession#getProperties()} and {@link ParserSession#getProperties()}.
+	 * <p>
+	 * Equivalent to the value returned by {@link RestRequest#getRequestURI()}
+	 */
+	public static final String REST_requestURI = "RestServlet.requestURI";
+
+	/**
+	 * The request method.
+	 * <p>
+	 * Automatically added to properties return by {@link RestServlet#createRequestProperties(org.apache.juneau.ObjectMap, RestRequest)}
+	 * 	and are therefore available through {@link SerializerSession#getProperties()} and {@link ParserSession#getProperties()}.
+	 * <p>
+	 * Equivalent to the value returned by {@link RestRequest#getMethod()}
+	 */
+	public static final String REST_method = "RestServlet.method";
+
+
+	final boolean allowHeaderParams, allowContentParam, renderResponseStackTraces, useStackTraceHashes;
+	final String defaultCharset, paramFormat;
+	final Set<String> allowMethodParams;
+
+	/**
+	 * Constructor.
+	 * <p>
+	 * Typically only called from {@link ContextFactory#getContext(Class)}.
+	 *
+	 * @param cf The factory that created this context.
+	 */
+	public RestServletContext(ContextFactory cf) {
+		super(cf);
+		allowHeaderParams = cf.getProperty(REST_allowHeaderParams, boolean.class, true);
+		allowContentParam = cf.getProperty(REST_allowContentParam, boolean.class, true);
+		renderResponseStackTraces = cf.getProperty(REST_renderResponseStackTraces, boolean.class, false);
+		useStackTraceHashes = cf.getProperty(REST_useStackTraceHashes, boolean.class, true);
+		defaultCharset = cf.getProperty(REST_defaultCharset, String.class, "utf-8");
+		paramFormat = cf.getProperty(REST_paramFormat, String.class, "");
+
+		Set<String> s = new LinkedHashSet<String>();
+		for (String m : StringUtils.split(cf.getProperty(REST_allowMethodParam, String.class, ""), ','))
+			if (m.equals("true"))  // For backwards compatibility when this was a boolean field.
+				s.add("*");
+			else
+				s.add(m.toUpperCase());
+		allowMethodParams = Collections.unmodifiableSet(s);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletDefault.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletDefault.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletDefault.java
new file mode 100755
index 0000000..2402927
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletDefault.java
@@ -0,0 +1,235 @@
+/***************************************************************************************************************************
+ * 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.server;
+
+import static org.apache.juneau.html.HtmlDocSerializerContext.*;
+import static org.apache.juneau.server.RestServletContext.*;
+
+import org.apache.juneau.html.*;
+import org.apache.juneau.jso.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.msgpack.*;
+import org.apache.juneau.plaintext.*;
+import org.apache.juneau.server.annotation.*;
+import org.apache.juneau.server.labels.*;
+import org.apache.juneau.soap.*;
+import org.apache.juneau.urlencoding.*;
+import org.apache.juneau.xml.*;
+
+/**
+ * Subclass of {@link RestServlet} with default serializers and parsers defined.
+ * <p>
+ * 	Supports the following request <code>Accept</code> header values with the resulting response <code>Content-Type</code>:
+ * </p>
+ * <table class='styled'>
+ * 	<tr>
+ * 		<th>Accept</th>
+ * 		<th>Content-Type</th>
+ * 		<th>Serializer</th>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>application/json<br>text/json</td>
+ * 		<td class='code'>application/json</td>
+ * 		<td>{@link JsonSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>application/json+simple<br>text/json+simple</td>
+ * 		<td class='code'>application/json</td>
+ * 		<td>{@link org.apache.juneau.json.JsonSerializer.Simple}</td>
+ * 	</tr>
+ * 		<td class='code'>application/json+schema<br>text/json+schema</td>
+ * 		<td class='code'>application/json</td>
+ * 		<td>{@link JsonSchemaSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/xml</td>
+ * 		<td class='code'>text/xml</td>
+ * 		<td>{@link XmlDocSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/xml+schema</td>
+ * 		<td class='code'>text/xml</td>
+ * 		<td>{@link XmlSchemaDocSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/html</td>
+ * 		<td class='code'>text/html</td>
+ * 		<td>{@link HtmlDocSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/html+stripped</td>
+ * 		<td class='code'>text/html</td>
+ * 		<td>{@link HtmlStrippedDocSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/uon</td>
+ * 		<td class='code'>text/uon</td>
+ * 		<td>{@link UonSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/uon-simple</td>
+ * 		<td class='code'>text/uon</td>
+ * 		<td>{@link org.apache.juneau.urlencoding.UonSerializer.Simple}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>application/x-www-form-urlencoded</td>
+ * 		<td class='code'>application/x-www-form-urlencoded</td>
+ * 		<td>{@link UrlEncodingSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>application/x-www-form-urlencoded-simple</td>
+ * 		<td class='code'>application/x-www-form-urlencoded</td>
+ * 		<td>{@link org.apache.juneau.urlencoding.UrlEncodingSerializer.Simple}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/xml+soap</td>
+ * 		<td class='code'>text/xml</td>
+ * 		<td>{@link SoapXmlSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/plain</td>
+ * 		<td class='code'>text/plain</td>
+ * 		<td>{@link PlainTextSerializer}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>application/x-java-serialized-object</td>
+ * 		<td class='code'>application/x-java-serialized-object</td>
+ * 		<td>{@link JavaSerializedObjectSerializer}</td>
+ * 	</tr>
+ * </table>
+ * <p>
+ * 	Supports the following request <code>Content-Type</code> header values:
+ * </p>
+ * <table class='styled'>
+ * 	<tr>
+ * 		<th>Content-Type</th>
+ * 		<th>Parser</th>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>application/json<br>text/json</td>
+ * 		<td>{@link JsonParser}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/xml<br>application/xml</td>
+ * 		<td>{@link XmlParser}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/html<br>text/html+stripped</td>
+ * 		<td>{@link HtmlParser}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/uon</td>
+ * 		<td>{@link UonParser}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>application/x-www-form-urlencoded</td>
+ * 		<td>{@link UrlEncodingParser}</td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td class='code'>text/plain</td>
+ * 		<td>{@link PlainTextParser}</td>
+ * 	</tr>
+ * </table>
+ * <p>
+ * 	It should be noted that we do NOT add {@link JavaSerializedObjectParser} to the list of parsers since this could
+ * 		cause security issues.  Use caution when using this particular parser as it could inadvertantly cause
+ * 		code execution security holes.
+ *	</p>
+ * <p>
+ * 	The list of serializers and parsers can be appended to using the {@link RestResource#serializers() @RestResource.serializers()}
+ * 		and {@link RestResource#parsers() @RestResource.parsers()} annotations on subclasses.
+ * </p>
+ * <p>
+ * 	This subclass also provides a default OPTIONS page by implementing a {@link #getOptions(RestRequest)} that returns a POJO consisting
+ * 		of beans describing the class.
+ * </p>
+ * <img class='bordered' src='doc-files/OptionsPage.png'>
+ * <p>
+ * 	The OPTIONS page can be modified or augmented by overriding this method and providing your own data.
+ * </p>
+ *
+ * <h6 class='topic'>Other Notes</h6>
+ * <ul class='spaced-list'>
+ * 	<li>Provides a default HTML stylesheet by setting {@link RestResource#stylesheet() @RestResource.stylesheet()} to <js>"styles/juneau.css"</js>.
+ * 	<li>Provides a default favicon by setting {@link RestResource#favicon() @RestResource.favicon()} to <js>"juneau.ico"</js>.
+ * 	<li>Provides a default classpath entry "htdocs" by setting {@link RestResource#staticFiles() @RestResource.staticFiles()} to <js>"{htdocs:'htdocs'}"</js>.
+ * 		This allows files inside the <code>[servletPackage].htdocs</code> package to be served up under the URL <code>/servletPath/htdocs</code>.
+ * </ul>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@RestResource(
+	serializers={
+		HtmlDocSerializer.class, // HTML must be listed first because Internet Explore does not include text/html in their Accept header.
+		HtmlStrippedDocSerializer.class,
+		HtmlSchemaDocSerializer.class,
+		JsonSerializer.class,
+		JsonSerializer.Simple.class,
+		JsonSchemaSerializer.class,
+		XmlDocSerializer.class,
+		XmlSchemaDocSerializer.class,
+		UonSerializer.class,
+		UonSerializer.Simple.class,
+		UrlEncodingSerializer.class,
+		UrlEncodingSerializer.Simple.class,
+		MsgPackSerializer.class,
+		SoapXmlSerializer.class,
+		PlainTextSerializer.class,
+		JavaSerializedObjectSerializer.class
+	},
+	parsers={
+		JsonParser.class,
+		XmlParser.class,
+		HtmlParser.class,
+		UonParser.class,
+		UrlEncodingParser.class,
+		MsgPackParser.class,
+		PlainTextParser.class
+	},
+	properties={
+		// Allow &method parameter on safe HTTP methods.
+		@Property(name=REST_allowMethodParam, value="OPTIONS"),
+		// Provide a default title on HTML pages.
+		@Property(name=HTMLDOC_title, value="$R{servletLabel}"),
+		// Provide a default description on HTML pages.
+		@Property(name=HTMLDOC_description, value="$R{servletDescription}")
+	},
+	stylesheet="styles/juneau.css",
+	favicon="juneau.ico",
+	staticFiles="{htdocs:'htdocs'}"
+)
+public abstract class RestServletDefault extends RestServlet {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * [OPTIONS /*] - Show resource options.
+	 *
+	 * @param req The HTTP request.
+	 * @return A bean containing the contents for the OPTIONS page.
+	 */
+	@RestMethod(name="OPTIONS", path="/*",
+		properties={
+			@Property(name=HTMLDOC_links, value="{back:'$R{servletURI}'}"),
+			@Property(name=HTMLDOC_description, value="Resource options")
+		},
+		description="Resource options"
+	)
+	public ResourceOptions getOptions(RestRequest req) {
+		return new ResourceOptions(this, req);
+	}
+
+	@Override /* RestServlet */
+	public boolean hasOptionsPage() {
+		return true;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletException.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletException.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletException.java
new file mode 100755
index 0000000..1e33808
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletException.java
@@ -0,0 +1,48 @@
+/***************************************************************************************************************************
+ * 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.server;
+
+import java.text.*;
+
+import javax.servlet.*;
+
+/**
+ * General exception thrown from {@link RestServlet} during construction or initialization.
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+public class RestServletException extends ServletException {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The detailed message.
+	 * @param args Optional message arguments.
+	 */
+	public RestServletException(String message, Object...args) {
+		super(args.length == 0 ? message : MessageFormat.format(message, args));
+	}
+
+	/**
+	 * Sets the inner cause for this exception.
+	 *
+	 * @param cause The inner cause.
+	 * @return This object (for method chaining).
+	 */
+	@Override /* Throwable */
+	public synchronized RestServletException initCause(Throwable cause) {
+		super.initCause(cause);
+		return this;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletGroupDefault.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletGroupDefault.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletGroupDefault.java
new file mode 100755
index 0000000..4083e61
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestServletGroupDefault.java
@@ -0,0 +1,43 @@
+/***************************************************************************************************************************
+ * 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.server;
+
+import org.apache.juneau.server.annotation.*;
+import org.apache.juneau.server.labels.*;
+
+/**
+ * Specialized subclass of {@link RestServletDefault} for showing "group" pages.
+ * <p>
+ * 	Group pages consist of simple lists of child resource URLs and their labels.
+ * 	They're meant to be used as jumping-off points for child resources.
+ * <p>
+ * 	Child resources are specified using the {@link RestResource#children()} annotation.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@RestResource()
+public abstract class RestServletGroupDefault extends RestServletDefault {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * [GET /] - Get child resources.
+	 *
+	 * @param req The HTTP request.
+	 * @return The bean containing links to the child resources.
+	 */
+	@RestMethod(name="GET", path="/", description="Child resources")
+	public ChildResourceDescriptions getChildren(RestRequest req) {
+		return new ChildResourceDescriptions(this, req);
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestUtils.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestUtils.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestUtils.java
new file mode 100755
index 0000000..12ce0cd
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/RestUtils.java
@@ -0,0 +1,250 @@
+/***************************************************************************************************************************
+ * 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.server;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.internal.*;
+
+/**
+ * Various reusable utility methods.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+public final class RestUtils {
+
+	/**
+	 * Returns readable text for an HTTP response code.
+	 *
+	 * @param rc The HTTP response code.
+	 * @return Readable text for an HTTP response code, or <jk>null</jk> if it's an invalid code.
+	 */
+	public static String getHttpResponseText(int rc) {
+		return httpMsgs.get(rc);
+	}
+
+	@SuppressWarnings("serial")
+	private static Map<Integer,String> httpMsgs = new HashMap<Integer,String>() {{
+		put(200, "OK");
+		put(201, "Created");
+		put(202, "Accepted");
+		put(203, "Non-Authoritative Information");
+		put(204, "No Content");
+		put(205, "Reset Content");
+		put(206, "Partial Content");
+		put(300, "Multiple Choices");
+		put(301, "Moved Permanently");
+		put(302, "Temporary Redirect");
+		put(303, "See Other");
+		put(304, "Not Modified");
+		put(305, "Use Proxy");
+		put(307, "Temporary Redirect");
+		put(400, "Bad Request");
+		put(401, "Unauthorized");
+		put(402, "Payment Required");
+		put(403, "Forbidden");
+		put(404, "Not Found");
+		put(405, "Method Not Allowed");
+		put(406, "Not Acceptable");
+		put(407, "Proxy Authentication Required");
+		put(408, "Request Time-Out");
+		put(409, "Conflict");
+		put(410, "Gone");
+		put(411, "Length Required");
+		put(412, "Precondition Failed");
+		put(413, "Request Entity Too Large");
+		put(414, "Request-URI Too Large");
+		put(415, "Unsupported Media Type");
+		put(500, "Internal Server Error");
+		put(501, "Not Implemented");
+		put(502, "Bad Gateway");
+		put(503, "Service Unavailable");
+		put(504, "Gateway Timeout");
+		put(505, "HTTP Version Not Supported");
+	}};
+
+	/**
+	 * Trims <js>'/'</js> characters from both the start and end of the specified string.
+	 *
+	 * @param s The string to trim.
+	 * @return A new trimmed string, or the same string if no trimming was necessary.
+	 */
+	public static String trimSlashes(String s) {
+		if (s == null)
+			return null;
+		while (StringUtils.endsWith(s, '/'))
+			s = s.substring(0, s.length()-1);
+		while (s.length() > 0 && s.charAt(0) == '/')
+			s = s.substring(1);
+		return s;
+	}
+
+	/**
+	 * Trims <js>'/'</js> characters from the end of the specified string.
+	 *
+	 * @param s The string to trim.
+	 * @return A new trimmed string, or the same string if no trimming was necessary.
+	 */
+	public static String trimTrailingSlashes(String s) {
+		if (s == null)
+			return null;
+		while (StringUtils.endsWith(s, '/'))
+			s = s.substring(0, s.length()-1);
+		return s;
+	}
+
+	/**
+	 * Trims <js>'/'</js> characters from the end of the specified string.
+	 *
+	 * @param s The string to trim.
+	 * @return The same string buffer.
+	 */
+	public static StringBuffer trimTrailingSlashes(StringBuffer s) {
+		if (s == null)
+			return null;
+		while (s.length() > 0 && s.charAt(s.length()-1) == '/')
+			s.setLength(s.length()-1);
+		return s;
+	}
+
+   /**
+    * Decodes a <code>application/x-www-form-urlencoded</code> string using <code>UTF-8</code> encoding scheme.
+    *
+	 * @param s The string to decode.
+	 * @return The decoded string, or <jk>null</jk> if input is <jk>null</jk>.
+    */
+	public static String decode(String s) {
+		if (s == null)
+			return s;
+		boolean needsDecode = false;
+		for (int i = 0; i < s.length() && ! needsDecode; i++) {
+			char c = s.charAt(i);
+			if (c == '+' || c == '%')
+				needsDecode = true;
+		}
+		if (needsDecode)
+		try {
+				return URLDecoder.decode(s, "UTF-8");
+			} catch (UnsupportedEncodingException e) {/* Won't happen */}
+		return s;
+	}
+
+	// Characters that do not need to be URL-encoded
+	private static final AsciiSet unencodedChars = new AsciiSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()\\");
+
+   /**
+    * Encodes a <code>application/x-www-form-urlencoded</code> string using <code>UTF-8</code> encoding scheme.
+    *
+    * @param s The string to encode.
+    * @return The encoded string, or <jk>null</jk> if input is <jk>null</jk>.
+    */
+	public static String encode(String s) {
+		if (s == null)
+			return null;
+		boolean needsEncode = false;
+		for (int i = 0; i < s.length() && ! needsEncode; i++)
+			needsEncode |= (! unencodedChars.contains(s.charAt(i)));
+		if (needsEncode)
+		try {
+				return URLEncoder.encode(s, "UTF-8");
+			} catch (UnsupportedEncodingException e) {/* Won't happen */}
+		return s;
+	}
+
+   /**
+    * Identical to {@link HttpServletRequest#getPathInfo()} but doesn't decode encoded characters.
+    *
+    * @param req The HTTP request
+    * @return The undecoded path info.
+    */
+	public static String getPathInfoUndecoded(HttpServletRequest req) {
+		String requestURI = req.getRequestURI();
+		String contextPath = req.getContextPath();
+		String servletPath = req.getServletPath();
+		int l = contextPath.length() + servletPath.length();
+		if (requestURI.length() == l)
+			return null;
+		return requestURI.substring(l);
+	}
+
+	/**
+	 * Efficiently trims the path info part from a request URI.
+	 * <p>
+	 * The result is the URI of the servlet itself.
+	 *
+	 * @param requestURI The value returned by {@link HttpServletRequest#getRequestURL()}
+	 * @param contextPath The value returned by {@link HttpServletRequest#getContextPath()}
+	 * @param servletPath The value returned by {@link HttpServletRequest#getServletPath()}
+	 * @return The same StringBuilder with remainder trimmed.
+	 */
+	public static StringBuffer trimPathInfo(StringBuffer requestURI, String contextPath, String servletPath) {
+		if (servletPath.equals("/"))
+			servletPath = "";
+		if (contextPath.equals("/"))
+			contextPath = "";
+
+		try {
+			// Given URL:  http://hostname:port/servletPath/extra
+			// We want:    http://hostname:port/servletPath
+			int sc = 0;
+			for (int i = 0; i < requestURI.length(); i++) {
+				char c = requestURI.charAt(i);
+				if (c == '/') {
+					sc++;
+					if (sc == 3) {
+						if (servletPath.isEmpty()) {
+							requestURI.setLength(i);
+							return requestURI;
+						}
+
+						// Make sure context path follows the authority.
+						for (int j = 0; j < contextPath.length(); i++, j++)
+							if (requestURI.charAt(i) != contextPath.charAt(j))
+								throw new Exception("case=1");
+
+						// Make sure servlet path follows the authority.
+						for (int j = 0; j < servletPath.length(); i++, j++)
+							if (requestURI.charAt(i) != servletPath.charAt(j))
+								throw new Exception("case=2");
+
+						// Make sure servlet path isn't a false match (e.g. /foo2 should not match /foo)
+						c = (requestURI.length() == i ? '/' : requestURI.charAt(i));
+						if (c == '/' || c == '?') {
+							requestURI.setLength(i);
+							return requestURI;
+						}
+
+						throw new Exception("case=3");
+					}
+				} else if (c == '?') {
+					if (sc != 2)
+						throw new Exception("case=4");
+					if (servletPath.isEmpty()) {
+						requestURI.setLength(i);
+						return requestURI;
+					}
+					throw new Exception("case=5");
+				}
+			}
+			if (servletPath.isEmpty())
+				return requestURI;
+			throw new Exception("case=6");
+		} catch (Exception e) {
+			throw new RuntimeException("Could not find servlet path in request URI.  URI=["+requestURI+"], servletPath=["+servletPath+"]", e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/StreamResource.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/StreamResource.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/StreamResource.java
new file mode 100755
index 0000000..fb7dd13
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/StreamResource.java
@@ -0,0 +1,91 @@
+/***************************************************************************************************************************
+ * 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.server;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.server.response.*;
+
+/**
+ * Represents the contents of a byte stream file with convenience methods for adding HTTP response headers.
+ * <p>
+ * This class is handled special by the {@link StreamableHandler} class.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+public class StreamResource implements Streamable {
+
+	private byte[] contents;
+	private String mediaType;
+	private Map<String,String> headers = new LinkedHashMap<String,String>();
+
+	/**
+	 * Constructor.
+	 * Create a stream resource from a byte array.
+	 *
+	 * @param contents The resource contents.
+	 * @param mediaType The resource media type.
+	 */
+	public StreamResource(byte[] contents, String mediaType) {
+		this.contents = contents;
+		this.mediaType = mediaType;
+	}
+
+	/**
+	 * Constructor.
+	 * Create a stream resource from an <code>InputStream</code>.
+	 * Contents of stream will be loaded into a reusable byte array.
+	 *
+	 * @param contents The resource contents.
+	 * @param mediaType The resource media type.
+	 * @throws IOException
+	 */
+	public StreamResource(InputStream contents, String mediaType) throws IOException {
+		this.contents = IOUtils.readBytes(contents, 1024);
+		this.mediaType = mediaType;
+	}
+
+	/**
+	 * Add an HTTP response header.
+	 *
+	 * @param name The header name.
+	 * @param value The header value, converted to a string using {@link Object#toString()}.
+	 * @return This object (for method chaining).
+	 */
+	public StreamResource setHeader(String name, Object value) {
+		headers.put(name, value == null ? "" : value.toString());
+		return this;
+	}
+
+	/**
+	 * Get the HTTP response headers.
+	 *
+	 * @return The HTTP response headers.  Never <jk>null</jk>.
+	 */
+	public Map<String,String> getHeaders() {
+		return headers;
+	}
+
+	@Override /* Streamable */
+	public void streamTo(OutputStream os) throws IOException {
+		os.write(contents);
+	}
+
+	@Override /* Streamable */
+	public String getMediaType() {
+		return mediaType;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/UrlPathPattern.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/UrlPathPattern.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/UrlPathPattern.java
new file mode 100755
index 0000000..4c161bb
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/UrlPathPattern.java
@@ -0,0 +1,161 @@
+/***************************************************************************************************************************
+ * 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.server;
+
+import static org.apache.juneau.server.RestUtils.*;
+
+import java.util.*;
+import java.util.regex.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.server.annotation.*;
+
+/**
+ * A parsed path pattern constructed from a {@link RestMethod#path()} value.
+ * <p>
+ * Handles aspects of matching and precedence ordering.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+public final class UrlPathPattern implements Comparable<UrlPathPattern> {
+	private Pattern pattern;
+	String patternString;
+	private boolean isOnlyDotAll, isDotAll;
+	String[] vars = new String[0];
+
+	/**
+	 * Constructor.
+	 *
+	 * @param patternString The raw pattern string from the {@link RestMethod#path()} annotation.
+	 */
+	public UrlPathPattern(String patternString) {
+		this.patternString = patternString;
+		if (! StringUtils.startsWith(patternString, '/'))
+			patternString = '/' + patternString;
+		if (patternString.equals("/*")) {
+			isOnlyDotAll = true;
+			return;
+		}
+		if (patternString.endsWith("/*"))
+			isDotAll = true;
+
+		// Find all {xxx} variables.
+		Pattern p = Pattern.compile("\\{([^\\}]+)\\}");
+		List<String> vl = new LinkedList<String>();
+		Matcher m = p.matcher(patternString);
+		while (m.find())
+			vl.add(m.group(1));
+		this.vars = vl.toArray(new String[vl.size()]);
+
+		patternString = patternString.replaceAll("\\{[^\\}]+\\}", "([^\\/]+)");
+		patternString = patternString.replaceAll("\\/\\*$", "((?:)|(?:\\/.*))");
+		pattern = Pattern.compile(patternString);
+	}
+
+	/**
+	 * Returns a non-<jk>null</jk> value if the specified path matches this pattern.
+	 *
+	 * @param path The path to match against.
+	 * @return An array of values matched against <js>"{var}"</js> variable in the pattern,
+	 * 	or an empty array if the pattern matched but no vars were present, or <jk>null</jk>
+	 * 	if the specified path didn't match the pattern.
+	 */
+	protected String[] match(String path) {
+
+		if (isOnlyDotAll) {
+			// Remainder always gets leading slash trimmed.
+			if (path != null)
+				path = path.substring(1);
+			return new String[]{path};
+		}
+
+		if (path == null)
+			return (patternString.equals("/") ? new String[]{} : null);
+
+		Matcher m = pattern.matcher(path);
+		if (! m.matches())
+			return null;
+
+		int len = m.groupCount();
+		String[] v = new String[len];
+
+		for (int i = 0; i < len; i++) {
+			if (isDotAll && i == len-1)
+				v[i] = m.group(i+1).isEmpty() ? null : m.group(i+1).substring(1);
+			else
+			v[i] = decode(m.group(i+1));
+		}
+
+		return v;
+	}
+
+	/**
+	 * Comparator for this object.
+	 * The comparator is designed to order URL pattern from most-specific to least-specific.
+	 * For example, the following patterns would be ordered as follows:
+	 * <ol>
+	 * 	<li><code>/foo/bar</code>
+	 * 	<li><code>/foo/bar/*</code>
+	 * 	<li><code>/foo/{id}/bar</code>
+	 * 	<li><code>/foo/{id}/bar/*</code>
+	 * 	<li><code>/foo/{id}</code>
+	 * 	<li><code>/foo/{id}/*</code>
+	 * 	<li><code>/foo</code>
+	 * 	<li><code>/foo/*</code>
+	 * </ol>
+	 */
+	@Override /* Comparable */
+	public int compareTo(UrlPathPattern o) {
+		String s1 = patternString.replaceAll("\\{[^\\}]+\\}", ".").replaceAll("\\w+", "X").replaceAll("\\.", "W");
+		String s2 = o.patternString.replaceAll("\\{[^\\}]+\\}", ".").replaceAll("\\w+", "X").replaceAll("\\.", "W");
+		if (s1.isEmpty())
+			s1 = "+";
+		if (s2.isEmpty())
+			s2 = "+";
+		if (! s1.endsWith("/*"))
+			s1 = s1 + "/W";
+		if (! s2.endsWith("/*"))
+			s2 = s2 + "/W";
+		int c = s2.compareTo(s1);
+		if (c == 0)
+			return o.toRegEx().compareTo(toRegEx());
+		return c;
+	}
+
+	@Override /* Object */
+	public boolean equals(Object o) {
+		if (! (o instanceof UrlPathPattern))
+			return false;
+		return (compareTo((UrlPathPattern)o) == 0);
+	}
+
+	@Override /* Object */
+	public int hashCode() {
+		return super.hashCode();
+	}
+
+	@Override /* Object */
+	public String toString() {
+		return patternString;
+	}
+
+	/**
+	 * Returns this path pattern as the compiled regular expression.
+	 * Useful for debugging.
+	 *
+	 * @return The path pattern.
+	 */
+	public String toRegEx() {
+		return isOnlyDotAll ? "*" : pattern.pattern();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Attr.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Attr.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Attr.java
new file mode 100755
index 0000000..6c1aed5
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Attr.java
@@ -0,0 +1,74 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify it as a variable in a URL path pattern converted to a POJO.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res,
+ * 			<ja>@Attr</ja> String foo, <ja>@Attr</ja> <jk>int</jk> bar, <ja>@Attr</ja> UUID baz) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	The <ja>@Attr</ja> annotation is optional if the parameters are specified immediately
+ * 	following the <code>RestRequest</code> and <code>RestResponse</code> parameters,
+ * 	and are specified in the same order as the variables in the URL path pattern.
+ * 	The following example is equivalent to the previous example.
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res,
+ * 			String foo, <jk>int</jk> bar, UUID baz) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	If the order of parameters is not the default order shown above, the
+ * 	attribute names must be specified (since parameter names are lost during compilation).
+ * 	The following example is equivalent to the previous example, except
+ * 	the parameter order has been switched, requiring the use of the <ja>@Attr</ja>
+ * 	annotations.
+ * <p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res,
+ * 			<ja>@Attr</ja>(<js>"baz"</js>) UUID baz, <ja>@Attr</ja>(<js>"foo"</js>) String foo, <ja>@Attr</ja>(<js>"bar"</js>) <jk>int</jk> bar) {
+ * 		...
+ * 	}
+ * </p>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Attr {
+
+	/**
+	 * URL variable name.
+	 * <p>
+	 * 	Optional if the attributes are specified in the same order as in the URL path pattern.
+	 */
+	String value() default "";
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Content.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Content.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Content.java
new file mode 100755
index 0000000..bdf3e65
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Content.java
@@ -0,0 +1,58 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.io.*;
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify it as the HTTP request body converted to a POJO.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ * 	<jk>public void</jk> doPostPerson(RestRequest req, RestResponse res, <ja>@Content</ja> Person person) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ * 	<jk>public void</jk> doPostPerson(RestRequest req, RestResponse res) {
+ * 		Person person = req.getInput(Person.<jk>class</jk>);
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	{@link Reader Readers} and {@link InputStream InputStreams} can also be specified as content parameters.
+ * 	When specified, any registered parsers are bypassed.
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ * 	<jk>public void</jk> doPostPerson(<ja>@Header</ja> String mediaType, <ja>@Content</ja> InputStream input) {
+ * 		...
+ * 	}
+ * </p>
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Content {}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasParam.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasParam.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasParam.java
new file mode 100755
index 0000000..06c44a6
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasParam.java
@@ -0,0 +1,95 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.server.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify whether or not the request has the specified GET or POST parameter.
+ * <p>
+ * Note that this can be used to detect the existence of a parameter when it's not set to a particular value.
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(<ja>@HasParam</ja>(<js>"p1"</js>) <jk>boolean</jk> p1) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req) {
+ * 		<jk>boolean</jk> p1 = req.hasParameter(<js>"p1"</js>);
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * The following table shows the behavioral differences between <code>@HasParam</code> and <code>@Param</code>...
+ * <table class='styled'>
+ * 	<tr>
+ * 		<th><code>URL</code></th>
+ * 		<th><code><ja>@HasParam</ja>(<js>"a"</js>)</code></th>
+ * 		<th><code><ja>@Param</ja>(<js>"a"</js>)</code></th>
+ * 	</tr>
+ * 	<tr>
+ * 		<td><code>?a=foo</code></td>
+ * 		<td><code><jk>true</jk></td>
+ * 		<td><code><js>"foo"</js></td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td><code>?a=</code></td>
+ * 		<td><code><jk>true</jk></td>
+ * 		<td><code><js>""</js></td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td><code>?a</code></td>
+ * 		<td><code><jk>true</jk></td>
+ * 		<td><code><jk>null</jk></td>
+ * 	</tr>
+ * 	<tr>
+ * 		<td><code>?b=foo</code></td>
+ * 		<td><code><jk>false</jk></td>
+ * 		<td><code><jk>null</jk></td>
+ * 	</tr>
+ * </table>
+ *
+ * <h6 class='topic'>Important note concerning FORM posts</h6>
+ * <p>
+ * This annotation should not be combined with the {@link Content @Content} annotation or {@link RestRequest#getInput(Class)} method
+ * 	for <code>application/x-www-form-urlencoded POST</code> posts, since it will trigger the underlying servlet API to parse the body
+ * 	content as key-value pairs, resulting in empty content.
+ * <p>
+ * The {@link HasQParam @HasQParam} annotation can be used to check for the existing of a URL parameter
+ * 	in the URL string without triggering the servlet to drain the body content.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface HasParam {
+
+	/**
+	 * URL parameter name.
+	 */
+	String value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasQParam.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasQParam.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasQParam.java
new file mode 100755
index 0000000..a51a56b
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/HasQParam.java
@@ -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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.server.*;
+
+/**
+ * Identical to {@link HasParam @HasParam}, but only checks the existing of the parameter in the
+ * 	URL string, not URL-encoded form posts.
+ * <p>
+ * Unlike {@link HasParam @HasParam}, using this annotation does not result in the servlet reading the contents
+ * 	of URL-encoded form posts.
+ * Therefore, this annotation can be used in conjunction with the {@link Content @Content} annotation
+ * 	or {@link RestRequest#getInput(Class)} method for <code>application/x-www-form-urlencoded POST</code> calls.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doPost(<ja>@HasQParam</ja>(<js>"p1"</js>) <jk>boolean</jk> p1, <ja>@Content</ja> Bean myBean) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req) {
+ * 		<jk>boolean</jk> p1 = req.hasQueryParameter(<js>"p1"</js>);
+ * 		...
+ * 	}
+ * </p>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface HasQParam {
+
+	/**
+	 * URL parameter name.
+	 */
+	String value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Header.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Header.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Header.java
new file mode 100755
index 0000000..b26674d
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Header.java
@@ -0,0 +1,54 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify it as a HTTP request header converted to a POJO.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res, <ja>@Header</ja>(<js>"ETag"</js>) UUID etag) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doPostPerson(RestRequest req, RestResponse res) {
+ * 		UUID etag = req.getHeader(UUID.<jk>class</jk>, "ETag");
+ * 		...
+ * 	}
+ * </p>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Header {
+
+	/**
+	 * HTTP header name.
+	 */
+	String value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Inherit.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Inherit.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Inherit.java
new file mode 100755
index 0000000..de0f6ac
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Inherit.java
@@ -0,0 +1,34 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ ***************************************************************************************************************************/
+package org.apache.juneau.server.annotation;
+
+/**
+ * Inheritance values for the {@link RestMethod#serializersInherit()} and {@link RestMethod#parsersInherit()}
+ * 	annotations.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+public enum Inherit {
+
+	/** Inherit serializers from parent. */
+	SERIALIZERS,
+
+	/** Inherit parsers from parent. */
+	PARSERS,
+
+	/** Inherit transforms from parent. */
+	TRANSFORMS,
+
+	/** Inherit properties from parent. */
+	PROPERTIES
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Messages.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Messages.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Messages.java
new file mode 100755
index 0000000..66cbc7f
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Messages.java
@@ -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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+import java.util.*;
+
+import org.apache.juneau.utils.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify it as the resource bundle for the request locale.
+ * <p>
+ * 	Parameter type must be either {@link ResourceBundle} or {@link MessageBundle}.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public</jk> String doGet(<ja>@Messages</ja> ResourceBundle messages) {
+ * 		<jk>return</jk> messages.getString(<js>"myLocalizedMessage"</js>);
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public</jk> String doGet(RestRequest req) {
+ * 		<jk>return</jk> req.getMessage(<js>"myLocalizedMessage"</js>);
+ * 	}
+ * </p>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Messages {}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Method.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Method.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Method.java
new file mode 100755
index 0000000..80acbb4
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Method.java
@@ -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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify it as the HTTP method.
+ * <p>
+ * 	Typically used for HTTP method handlers of type <js>"*"</js> (i.e. handle all requests).
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"*"</js>)
+ * 	<jk>public void</jk> doAnything(RestRequest req, RestResponse res, <ja>@Method</ja> String method) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"*"</js>)
+ * 	<jk>public void</jk> doAnything(RestRequest req, RestResponse res) {
+ * 		String method = req.getMethod();
+ * 		...
+ * 	}
+ * </p>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Method {
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Param.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Param.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Param.java
new file mode 100755
index 0000000..d20f08c
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Param.java
@@ -0,0 +1,98 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.server.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify it as a URL query parameter converted to a POJO.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res,
+ * 				<ja>@Param</ja>(<js>"p1"</js>) <jk>int</jk> p1, <ja>@Param</ja>(<js>"p2"</js>) String p2, <ja>@Param</ja>(<js>"p3"</js>) UUID p3) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res) {
+ * 		<jk>int</jk> p1 = req.getParam(<jk>int</jk>.<jk>class</jk>, <js>"p1"</js>, 0);
+ * 		String p2 = req.getParam(String.<jk>class</jk>, <js>"p2"</js>);
+ * 		UUID p3 = req.getParam(UUID.<jk>class</jk>, <js>"p3"</js>);
+ * 		...
+ * 	}
+ * </p>
+ *
+ * <h6 class='topic'>Important note concerning FORM posts</h6>
+ * <p>
+ * This annotation should not be combined with the {@link Content @Content} annotation or {@link RestRequest#getInput(Class)} method
+ * 	for <code>application/x-www-form-urlencoded POST</code> posts, since it will trigger the underlying servlet
+ * 	API to parse the body content as key-value pairs resulting in empty content.
+ * <p>
+ * The {@link QParam @QParam} annotation can be used to retrieve a URL parameter
+ * 	in the URL string without triggering the servlet to drain the body content.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Param {
+
+	/**
+	 * URL parameter name.
+	 */
+	String value();
+
+	/**
+	 * Specify <jk>true</jk> if using multi-part parameters to represent collections and arrays.
+	 * <p>
+	 * 	Normally, we expect single parameters to be specified in UON notation for representing
+	 * 	collections of values (e.g. <js>"&key=(1,2,3)"</js>.
+	 * 	This annotation allows the use of multi-part parameters to represent collections
+	 * 	(e.g. <js>"&key=1&key=2&key=3"</js>.
+	 * <p>
+	 *		This setting should only be applied to Java parameters of type array or Collection.
+	 */
+	boolean multipart() default false;
+
+	/**
+	 * The expected format of the request parameter.
+	 * <p>
+	 * Possible values:
+	 * <ul class='spaced-list'>
+	 * 	<li><js>"UON"</js> - URL-Encoded Object Notation.<br>
+	 *			This notation allows for request parameters to contain arbitrarily complex POJOs.
+	 * 	<li><js>"PLAIN"</js> - Plain text.<br>
+	 *			This treats request parameters as plain text.<br>
+	 *			Only POJOs directly convertable from <l>Strings</l> can be represented in parameters when using this mode.
+	 * 	<li><js>"INHERIT"</js> (default) - Inherit from the {@link RestServletContext#REST_paramFormat} property on the servlet method or class.
+	 * </ul>
+	 * <p>
+	 * Note that the parameter value <js>"(foo)"</js> is interpreted as <js>"(foo)"</js> when using plain mode, but
+	 * 	<js>"foo"</js> when using UON mode.
+	 */
+	String format() default "INHERIT";
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/PathRemainder.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/PathRemainder.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/PathRemainder.java
new file mode 100755
index 0000000..b51ff6b
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/PathRemainder.java
@@ -0,0 +1,48 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify it as the URL parameter remainder after a path pattern match.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo/*"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res, <ja>@PathRemainder</ja> String remainder) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo/*"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res) {
+ * 		String remainder = req.getPathRemainder();
+ * 		...
+ * 	}
+ * </p>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface PathRemainder {}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Properties.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Properties.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Properties.java
new file mode 100755
index 0000000..5aba15e
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Properties.java
@@ -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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} annotated method
+ * 	to identify the request-duration properties object for the current request.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public Person</jk> doGetPerson(<ja>@Properties</ja> ObjectMap properties) {
+ * 		properties.put(<jsf>HTMLDOC_title</jsf>, <js>"This is a person"</js>);
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public Person</jk> doGetPerson(RestResponse res) {
+ * 		ObjectMap properties = res.getProperties();
+ * 		properties.put(<jsf>HTMLDOC_title</jsf>, <js>"This is a person"</js>);
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	...or this...
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public Person</jk> doGetPerson(RestResponse res) {
+ * 		res.setProperty(<jsf>HTMLDOC_title</jsf>, <js>"This is a person"</js>);
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	The parameter type can be one of the following:
+ * 	<ul>
+ * 		<li>{@link ObjectMap}
+ * 		<li><code>Map&lt;String,Object&gt;</code>
+ * 	</ul>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Properties {}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Property.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Property.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Property.java
new file mode 100755
index 0000000..c06675d
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Property.java
@@ -0,0 +1,65 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.jena.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.xml.*;
+
+/**
+ * Property name/value pair used in the {@link RestResource#properties()} annotation.
+ * <p>
+ * 	Any of the following property names can be specified:
+ * <ul>
+ * 	<li>{@link BeanContext}
+ * 	<li>{@link SerializerContext}
+ * 	<li>{@link ParserContext}
+ * 	<li>{@link JsonSerializerContext}
+ * 	<li>{@link RdfSerializerContext}
+ * 	<li>{@link RdfParserContext}
+ * 	<li>{@link RdfCommonContext}
+ * 	<li>{@link XmlSerializerContext}
+ * 	<li>{@link XmlParserContext}
+ * </ul>
+ * <p>
+ * 	Property values types that are not <code>Strings</code> will automatically be converted to the
+ * 		correct type (e.g. <code>Boolean</code>, etc...).
+ * <p>
+ * 	See {@link RestResource#properties} for more information.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(ANNOTATION_TYPE)
+@Retention(RUNTIME)
+@Inherited
+public @interface Property {
+
+	/**
+	 * Property name.
+	 */
+	String name();
+
+	/**
+	 * Property value.
+	 */
+	String value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/QParam.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/QParam.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/QParam.java
new file mode 100755
index 0000000..0b13621
--- /dev/null
+++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/QParam.java
@@ -0,0 +1,94 @@
+/***************************************************************************************************************************
+ * 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.server.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.server.*;
+
+/**
+ * Identical to {@link Param @Param}, but only retrieves the parameter from the
+ * 	URL string, not URL-encoded form posts.
+ * <p>
+ * Unlike {@link Param @Param}, using this annotation does not result in the servlet reading the contents
+ * 	of URL-encoded form posts.
+ * Therefore, this annotation can be used in conjunction with the {@link Content @Content} annotation
+ * 	or {@link RestRequest#getInput(Class)} method for <code>application/x-www-form-urlencoded POST</code> calls.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res,
+ * 				<ja>@QParam</ja>(<js>"p1"</js>) <jk>int</jk> p1, <ja>@QParam</ja>(<js>"p2"</js>) String p2, <ja>@QParam</ja>(<js>"p3"</js>) UUID p3) {
+ * 		...
+ * 	}
+ * </p>
+ * <p>
+ * 	This is functionally equivalent to the following code...
+ * </p>
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res) {
+ * 		<jk>int</jk> p1 = req.getQueryParameter(<jk>int</jk>.<jk>class</jk>, <js>"p1"</js>, 0);
+ * 		String p2 = req.getQueryParameter(String.<jk>class</jk>, <js>"p2"</js>);
+ * 		UUID p3 = req.getQueryParameter(UUID.<jk>class</jk>, <js>"p3"</js>);
+ * 		...
+ * 	}
+ * </p>
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface QParam {
+
+	/**
+	 * URL parameter name.
+	 */
+	String value();
+
+	/**
+	 * Specify <jk>true</jk> if using multi-part parameters to represent collections and arrays.
+	 * <p>
+	 * 	Normally, we expect single parameters to be specified in UON notation for representing
+	 * 	collections of values (e.g. <js>"&key=(1,2,3)"</js>.
+	 * 	This annotation allows the use of multi-part parameters to represent collections
+	 * 	(e.g. <js>"&key=1&key=2&key=3"</js>.
+	 * <p>
+	 *		This setting should only be applied to Java parameters of type array or Collection.
+	 */
+	boolean multipart() default false;
+
+	/**
+	 * The expected format of the request parameter.
+	 * <p>
+	 * Possible values:
+	 * <ul class='spaced-list'>
+	 * 	<li><js>"UON"</js> - URL-Encoded Object Notation.<br>
+	 *			This notation allows for request parameters to contain arbitrarily complex POJOs.
+	 * 	<li><js>"PLAIN"</js> - Plain text.<br>
+	 *			This treats request parameters as plain text.<br>
+	 *			Only POJOs directly convertable from <l>Strings</l> can be represented in parameters when using this mode.
+	 * 	<li><js>"INHERIT"</js> (default) - Inherit from the {@link RestServletContext#REST_paramFormat} property on the servlet method or class.
+	 * </ul>
+	 * <p>
+	 * Note that the parameter value <js>"(foo)"</js> is interpreted as <js>"(foo)"</js> when using plain mode, but
+	 * 	<js>"foo"</js> when using UON mode.
+	 */
+	String format() default "INHERIT";
+}