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 [14/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...

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestGuard.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestGuard.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestGuard.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;
+
+import static javax.servlet.http.HttpServletResponse.*;
+
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * REST method guard.
+ *
+ * <h5 class='section'>Description:</h5>
+ *
+ * Implements a guard mechanism for REST method calls that allows requests to be rejected before invocation of the REST
+ * method.
+ * For example, guards can be used to ensure that only administrators can call certain methods.
+ *
+ * <p>
+ * Guards are applied to REST methods declaratively through the {@link RestResource#guards()} or
+ * {@link RestMethod#guards()} annotations.
+ *
+ * <p>
+ * If multiple guards are specified, ALL guards must pass in order for the request to proceed.
+ *
+ * <h6 class='topic'>How to implement</h6>
+ *
+ * Typically, guards will be used for permissions checking on the user making the request, but it can also be used for
+ * other purposes like pre-call validation of a request.
+ *
+ * <p>
+ * Implementers should simply throw a {@link RestException} from the {@link #guard(RestRequest, RestResponse)}
+ * method to abort processing on the current request.
+ *
+ * <p>
+ * Guards must implement a no-args constructor.
+ *
+ * <h6 class='topic'>Example usage:</h6>
+ * <p class='bcode'>
+ * 	<jk>public</jk> MyResource <jk>extends</jk> RestServlet {
+ *
+ * 		<jc>// Delete method with guard that only allows Billy to call it.</jc>
+ * 		<ja>@RestMethod</ja>(name=<js>"DELETE"</js>, guards=BillyGuard.<jk>class</jk>)
+ * 		<jk>public</jk> doDelete(RestRequest req, RestResponse res) <jk>throws</jk> Exception {...}
+ * 	}
+ * </p>
+ *
+ * <h6 class='topic'>Example implementation:</h6>
+ * <p class='bcode'>
+ * 	<jc>// Define a guard that only lets Billy make a request</jc>
+ * 	<jk>public</jk> BillyGuard <jk>extends</jk> RestGuard {
+ *
+ * 		<ja>@Override</ja>
+ * 		<jk>public boolean</jk> isRequestAllowed(RestRequest req) {
+ * 			return req.getUserPrincipal().getName().contains(<js>"Billy"</js>);
+ * 		}
+ * 	}
+ * </p>
+ */
+public abstract class RestGuard {
+
+	/**
+	 * Checks the current HTTP request and throws a {@link RestException} if the guard does not permit the request.
+	 *
+	 * <p>
+	 * By default, throws an <jsf>SC_FORBIDDEN</jsf> exception if {@link #isRequestAllowed(RestRequest)} returns
+	 * <jk>false</jk>.
+	 *
+	 * <p>
+	 * Subclasses are free to override this method to tailor the behavior of how to handle unauthorized requests.
+	 *
+	 * @param req The servlet request.
+	 * @param res The servlet response.
+	 * @throws RestException Thrown to abort processing on current request.
+	 * @return
+	 * 	<jk>true</jk> if request can proceed.
+	 * 	Specify <jk>false</jk> if you're doing something like a redirection to a login page.
+	 */
+	public boolean guard(RestRequest req, RestResponse res) throws RestException {
+		if (! isRequestAllowed(req))
+			throw new RestException(SC_FORBIDDEN, "Access denied by guard");
+		return true;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if the specified request can pass through this guard.
+	 *
+	 * @param req The servlet request.
+	 * @return <jk>true</jk> if the specified request can pass through this guard.
+	 */
+	public abstract boolean isRequestAllowed(RestRequest req);
+}

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

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProvider.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProvider.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestInfoProvider.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,572 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import static javax.servlet.http.HttpServletResponse.*;
+import static org.apache.juneau.dto.swagger.SwaggerBuilder.*;
+import static org.apache.juneau.internal.ReflectionUtils.*;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Class that provides documentation and other related information about a REST resource.
+ *
+ * <p>
+ * Subclasses can override these methods to tailor how HTTP REST resources are documented.
+ * Subclasses MUST implement a public constructor that takes in a {@link RestContext} object.
+ *
+ * <p>
+ * RestInfoProviders are associated with servlets/resources in one of the following ways:
+ * <ul>
+ * 	<li>The {@link RestResource#infoProvider @RestResource.infoProvider()} annotation.
+ * 	<li>The {@link RestConfig#setInfoProvider(Class)}/{@link RestConfig#setInfoProvider(RestInfoProvider)} methods.
+ * </ul>
+ */
+@SuppressWarnings("hiding")
+public class RestInfoProvider {
+
+	private final RestContext context;
+	private final String
+		siteName,
+		title,
+		description,
+		termsOfService,
+		contact,
+		license,
+		version,
+		tags,
+		externalDocs;
+	private final ConcurrentHashMap<Locale,Swagger> swaggers = new ConcurrentHashMap<Locale,Swagger>();
+
+	/**
+	 * Constructor.
+	 *
+	 * @param context The resource context.
+	 */
+	public RestInfoProvider(RestContext context) {
+		this.context = context;
+
+		Builder b = new Builder(context);
+		this.siteName = b.siteName;
+		this.title = b.title;
+		this.description = b.description;
+		this.termsOfService = b.termsOfService;
+		this.contact = b.contact;
+		this.license = b.license;
+		this.version = b.version;
+		this.tags = b.tags;
+		this.externalDocs = b.externalDocs;
+	}
+
+	private static class Builder {
+		private String
+			siteName,
+			title,
+			description,
+			termsOfService,
+			contact,
+			license,
+			version,
+			tags,
+			externalDocs;
+
+		Builder(RestContext context) {
+
+			LinkedHashMap<Class<?>,RestResource> restResourceAnnotationsParentFirst = findAnnotationsMapParentFirst(RestResource.class, context.getResource().getClass());
+
+			for (RestResource r : restResourceAnnotationsParentFirst.values()) {
+				if (! r.siteName().isEmpty())
+					siteName = r.siteName();
+				if (! r.title().isEmpty())
+					title = r.title();
+				if (! r.description().isEmpty())
+					description = r.description();
+				ResourceSwagger sr = r.swagger();
+				if (! sr.termsOfService().isEmpty())
+					termsOfService = sr.termsOfService();
+				if (! sr.contact().isEmpty())
+					contact = sr.contact();
+				if (! sr.license().isEmpty())
+					license = sr.license();
+				if (! sr.version().isEmpty())
+					version = sr.version();
+				if (! sr.tags().isEmpty())
+					tags = sr.tags();
+				if (! sr.externalDocs().isEmpty())
+					externalDocs = sr.externalDocs();
+			}
+		}
+	}
+
+	/**
+	 * Returns the localized swagger for this REST resource.
+	 *
+	 * @param req The incoming HTTP request.
+	 * @return A new Swagger instance.
+	 * @throws RestException
+	 */
+	protected Swagger getSwagger(RestRequest req) throws RestException {
+		try {
+			// If a file is defined, use that.
+			Swagger s = req.getSwaggerFromFile();
+			if (s != null)
+				return s;
+
+			s = swagger(
+				info(getTitle(req), getVersion(req))
+					.contact(getContact(req))
+					.license(getLicense(req))
+					.description(getDescription(req))
+					.termsOfService(getTermsOfService(req))
+				)
+				.consumes(context.getSupportedAcceptTypes())
+				.produces(context.getSupportedContentTypes())
+				.tags(getTags(req))
+				.externalDocs(getExternalDocs(req));
+
+			for (CallMethod sm : context.getCallMethods().values()) {
+				if (sm.isRequestAllowed(req)) {
+					Operation o = sm.getSwaggerOperation(req);
+					s.path(
+						sm.getPathPattern(),
+						sm.getHttpMethod().toLowerCase(),
+						o
+					);
+				}
+			}
+			return s;
+		} catch (RestException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+		}
+	}
+
+	/**
+	 * Returns the localized Swagger from the file system.
+	 *
+	 * <p>
+	 * Looks for a file called <js>"{ServletClass}_{locale}.json"</js> in the same package as this servlet and returns
+	 * it as a parsed {@link Swagger} object.
+	 *
+	 * <p>
+	 * Returned objects are cached for later quick-lookup.
+	 *
+	 * @param locale The locale of the swagger.
+	 * @return The parsed swagger object, or <jk>null</jk> if the swagger file could not be found.
+	 * @throws RestException
+	 */
+	protected Swagger getSwaggerFromFile(Locale locale) throws RestException {
+		Swagger s = swaggers.get(locale);
+		if (s == null) {
+			try {
+				s = context.getResource(Swagger.class, MediaType.JSON, getClass().getSimpleName() + ".json", locale);
+				swaggers.putIfAbsent(locale, s == null ? Swagger.NULL : s);
+			} catch (Exception e) {
+				throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+			}
+		}
+		return s == Swagger.NULL ? null : s;
+	}
+
+	/**
+	 * Returns the localized summary of the specified java method on this servlet.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own summary.
+	 *
+	 * <p>
+	 * The default implementation returns the summary from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link RestMethod#summary() @RestMethod.summary()} annotation on the method.
+	 * 	<li><ck>[ClassName].[javaMethodName].summary</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>[javaMethodName].summary</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * </ol>
+	 *
+	 * @param javaMethodName The name of the Java method whose description we're retrieving.
+	 * @param req The current request.
+	 * @return The localized summary of the method, or a blank string if no summary was found.
+	 */
+	public String getMethodSummary(String javaMethodName, RestRequest req) {
+		CallMethod m = context.getCallMethods().get(javaMethodName);
+		if (m != null)
+			return m.getSummary(req);
+		return "";
+	}
+
+	/**
+	 * Returns the localized description of the specified java method on this servlet.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own description.
+	 *
+	 * <p>
+	 * The default implementation returns the description from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link RestMethod#description() @RestMethod.description()} annotation on the method.
+	 * 	<li><ck>[ClassName].[javaMethodName].description</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>[javaMethodName].description</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * </ol>
+	 *
+	 * @param javaMethodName The name of the Java method whose description we're retrieving.
+	 * @param req The current request.
+	 * @return The localized description of the method, or a blank string if no description was found.
+	 */
+	protected String getMethodDescription(String javaMethodName, RestRequest req) {
+		CallMethod m = context.getCallMethods().get(javaMethodName);
+		if (m != null)
+			return m.getDescription(req);
+		return "";
+	}
+
+	/**
+	 * Returns the localized site name of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own site name.
+	 *
+	 * <p>
+	 * The default implementation returns the description from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link RestResource#siteName() @RestResource.siteName()} annotation on this class, and then any parent classes.
+	 * 	<li><ck>[ClassName].siteName</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @ResourceBundle.messages()} annotation for this class, then any parent
+	 * 		classes.
+	 * 	<li><ck>siteName</ck> in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+	 * 		annotation for this class, then any parent classes.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return The localized description of this REST resource, or <jk>null</jk> if no resource description was found.
+	 */
+	public String getSiteName(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		if (this.siteName != null)
+			return vr.resolve(this.siteName);
+		String siteName = context.getMessages().findFirstString(req.getLocale(), "siteName");
+		if (siteName != null)
+			return vr.resolve(siteName);
+		return null;
+	}
+
+	/**
+	 * Returns the localized title of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own title.
+	 *
+	 * <p>
+	 * The default implementation returns the description from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link RestResource#title() @RestResource.title()} annotation on this class, and then any parent classes.
+	 * 	<li><ck>[ClassName].title</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @ResourceBundle.messages()} annotation for this class, then any parent
+	 * 		classes.
+	 * 	<li><ck>title</ck> in resource bundle identified by {@link RestResource#messages() @RestResource.messages()}
+	 * 		annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/title</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return The localized description of this REST resource, or <jk>null</jk> if no resource description was found.
+	 */
+	public String getTitle(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		if (this.title != null)
+			return vr.resolve(this.title);
+		String title = context.getMessages().findFirstString(req.getLocale(), "title");
+		if (title != null)
+			return vr.resolve(title);
+		Swagger s = req.getSwaggerFromFile();
+		if (s != null && s.getInfo() != null)
+			return s.getInfo().getTitle();
+		return null;
+	}
+
+	/**
+	 * Returns the localized description of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own description.
+	 *
+	 * <p>
+	 * The default implementation returns the description from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link RestResource#description() @RestResource.description()} annotation on this class, and then any
+	 * 		parent classes.
+	 * 	<li><ck>[ClassName].description</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>description</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/description</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return The localized description of this REST resource, or <jk>null</jk> if no resource description was found.
+	 */
+	public String getDescription(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		if (this.description != null)
+			return vr.resolve(this.description);
+		String description = context.getMessages().findFirstString(req.getLocale(), "description");
+		if (description != null)
+			return vr.resolve(description);
+		Swagger s = req.getSwaggerFromFile();
+		if (s != null && s.getInfo() != null)
+			return s.getInfo().getDescription();
+		return null;
+	}
+
+	/**
+	 * Returns the localized contact information of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own contact information.
+	 *
+	 * <p>
+	 * The default implementation returns the contact information from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link ResourceSwagger#contact() @ResourceSwagger.contact()} annotation on this class, and then any parent
+	 * 		classes.
+	 * 	<li><ck>[ClassName].contact</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>contact</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/contact</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return
+	 * 	The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+	 */
+	public Contact getContact(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		JsonParser jp = JsonParser.DEFAULT;
+		try {
+			if (this.contact != null)
+				return jp.parse(vr.resolve(this.contact), Contact.class);
+			String contact = context.getMessages().findFirstString(req.getLocale(), "contact");
+			if (contact != null)
+				return jp.parse(vr.resolve(contact), Contact.class);
+			Swagger s = req.getSwaggerFromFile();
+			if (s != null && s.getInfo() != null)
+				return s.getInfo().getContact();
+			return null;
+		} catch (ParseException e) {
+			throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+		}
+	}
+
+	/**
+	 * Returns the localized license information of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own license information.
+	 *
+	 * <p>
+	 * The default implementation returns the license information from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link ResourceSwagger#license() @ResourceSwagger.license()} annotation on this class, and then any parent
+	 * 		classes.
+	 * 	<li><ck>[ClassName].license</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>license</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/license</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return
+	 * 	The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+	 */
+	public License getLicense(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		JsonParser jp = JsonParser.DEFAULT;
+		try {
+			if (this.license != null)
+				return jp.parse(vr.resolve(this.license), License.class);
+			String license = context.getMessages().findFirstString(req.getLocale(), "license");
+			if (license != null)
+				return jp.parse(vr.resolve(license), License.class);
+			Swagger s = req.getSwaggerFromFile();
+			if (s != null && s.getInfo() != null)
+				return s.getInfo().getLicense();
+			return null;
+		} catch (ParseException e) {
+			throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+		}
+	}
+
+	/**
+	 * Returns the terms-of-service information of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own terms-of-service information.
+	 *
+	 * <p>
+	 * The default implementation returns the terms-of-service information from the following locations (whichever
+	 * matches first):
+	 * <ol>
+	 * 	<li>{@link ResourceSwagger#termsOfService() @ResourceSwagger.termsOfService()} annotation on this class, and
+	 * 		then any parent classes.
+	 * 	<li><ck>[ClassName].termsOfService</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>termsOfService</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/termsOfService</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return
+	 * 	The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+	 */
+	public String getTermsOfService(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		if (this.termsOfService != null)
+			return vr.resolve(this.termsOfService);
+		String termsOfService = context.getMessages().findFirstString(req.getLocale(), "termsOfService");
+		if (termsOfService != null)
+			return vr.resolve(termsOfService);
+		Swagger s = req.getSwaggerFromFile();
+		if (s != null && s.getInfo() != null)
+			return s.getInfo().getTermsOfService();
+		return null;
+	}
+
+	/**
+	 * Returns the version information of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own version information.
+	 *
+	 * <p>
+	 * The default implementation returns the version information from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent
+	 * 		classes.
+	 * 	<li><ck>[ClassName].version</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>version</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/version</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return
+	 * 	The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+	 */
+	public String getVersion(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		if (this.version != null)
+			return vr.resolve(this.version);
+		String version = context.getMessages().findFirstString(req.getLocale(), "version");
+		if (version != null)
+			return vr.resolve(version);
+		Swagger s = req.getSwaggerFromFile();
+		if (s != null && s.getInfo() != null)
+			return s.getInfo().getVersion();
+		return null;
+	}
+
+	/**
+	 * Returns the version information of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own version information.
+	 *
+	 * <p>
+	 * The default implementation returns the version information from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent
+	 * 		classes.
+	 * 	<li><ck>[ClassName].version</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>version</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/version</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return
+	 * 	The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+	 */
+	public List<Tag> getTags(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		JsonParser jp = JsonParser.DEFAULT;
+		try {
+			if (this.tags != null)
+				return jp.parse(vr.resolve(this.tags), ArrayList.class, Tag.class);
+			String tags = context.getMessages().findFirstString(req.getLocale(), "tags");
+			if (tags != null)
+				return jp.parse(vr.resolve(tags), ArrayList.class, Tag.class);
+			Swagger s = req.getSwaggerFromFile();
+			if (s != null)
+				return s.getTags();
+			return null;
+		} catch (Exception e) {
+			throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+		}
+	}
+
+	/**
+	 * Returns the version information of this REST resource.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own version information.
+	 *
+	 * <p>
+	 * The default implementation returns the version information from the following locations (whichever matches first):
+	 * <ol>
+	 * 	<li>{@link ResourceSwagger#version() @ResourceSwagger.version()} annotation on this class, and then any parent
+	 * 		classes.
+	 * 	<li><ck>[ClassName].version</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>version</ck> property in resource bundle identified by
+	 * 		{@link RestResource#messages() @RestResource.messages()} annotation for this class, then any parent classes.
+	 * 	<li><ck>/info/version</ck> entry in swagger file.
+	 * </ol>
+	 *
+	 * @param req The current request.
+	 * @return
+	 * 	The localized contact information of this REST resource, or <jk>null</jk> if no contact information was found.
+	 */
+	public ExternalDocumentation getExternalDocs(RestRequest req) {
+		VarResolverSession vr = req.getVarResolverSession();
+		JsonParser jp = JsonParser.DEFAULT;
+		try {
+			if (this.externalDocs != null)
+				return jp.parse(vr.resolve(this.externalDocs), ExternalDocumentation.class);
+			String externalDocs = context.getMessages().findFirstString(req.getLocale(), "externalDocs");
+			if (externalDocs != null)
+				return jp.parse(vr.resolve(externalDocs), ExternalDocumentation.class);
+			Swagger s = req.getSwaggerFromFile();
+			if (s != null)
+				return s.getExternalDocs();
+			return null;
+		} catch (Exception e) {
+			throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+		}
+	}
+}

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

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestLogger.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestLogger.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestLogger.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,257 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import static javax.servlet.http.HttpServletResponse.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.text.*;
+import java.util.logging.*;
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Logging utility class.
+ *
+ * <p>
+ * Subclasses can override these methods to tailor logging of HTTP requests.
+ * Subclasses MUST implement a no-arg public constructor.
+ *
+ * <p>
+ * RestLoggers are associated with servlets/resources in one of the following ways:
+ * <ul>
+ * 	<li>The {@link RestResource#logger @RestResource.logger()} annotation.
+ * 	<li>The {@link RestConfig#setLogger(Class)}/{@link RestConfig#setLogger(RestLogger)} methods.
+ * </ul>
+ */
+public abstract class RestLogger {
+
+	/**
+	 * Returns the Java logger used for logging.
+	 *
+	 * <p>
+	 * Subclasses can provide their own logger.
+	 * The default implementation returns the logger created using <code>Logger.getLogger(getClass())</code>.
+	 *
+	 * @return The logger used for logging.
+	 */
+	protected abstract Logger getLogger();
+
+	/**
+	 * Log a message to the logger.
+	 *
+	 * <p>
+	 * Subclasses can override this method if they wish to log messages using a library other than Java Logging
+	 * (e.g. Apache Commons Logging).
+	 *
+	 * @param level The log level.
+	 * @param cause The cause.
+	 * @param msg The message to log.
+	 * @param args Optional {@link MessageFormat}-style arguments.
+	 */
+	protected abstract void log(Level level, Throwable cause, String msg, Object...args);
+
+	/**
+	 * Log a message.
+	 *
+	 * <p>
+	 * Equivalent to calling <code>log(level, <jk>null</jk>, msg, args);</code>
+	 *
+	 * @param level The log level.
+	 * @param msg The message to log.
+	 * @param args Optional {@link MessageFormat}-style arguments.
+	 */
+	protected void log(Level level, String msg, Object...args) {
+		log(level, null, msg, args);
+	}
+
+	/**
+	 * Same as {@link #log(Level, String, Object...)} excepts runs the arguments through {@link JsonSerializer#DEFAULT_LAX_READABLE}.
+	 *
+	 * <p>
+	 * Serialization of arguments do not occur if message is not logged, so it's safe to use this method from within
+	 * debug log statements.
+	 *
+	 * <h5 class='section'>Example:</h5>
+	 * <p class='bcode'>
+	 * 	logObjects(<jsf>DEBUG</jsf>, <js>"Pojo contents:\n{0}"</js>, myPojo);
+	 * </p>
+	 *
+	 * @param level The log level.
+	 * @param msg The message to log.
+	 * @param args Optional {@link MessageFormat}-style arguments.
+	 */
+	protected void logObjects(Level level, String msg, Object...args) {
+		for (int i = 0; i < args.length; i++)
+			args[i] = JsonSerializer.DEFAULT_LAX_READABLE.toStringObject(args[i]);
+		log(level, null, msg, args);
+	}
+
+	/**
+	 * Callback method for logging errors during HTTP requests.
+	 *
+	 * <p>
+	 * Typically, subclasses will override this method and log errors themselves.
+	 *
+	 * <p>
+	 * The default implementation simply logs errors to the <code>RestServlet</code> logger.
+	 *
+	 * <p>
+	 * Here's a typical implementation showing how stack trace hashing can be used to reduce log file sizes...
+	 * <p class='bcode'>
+	 * 	<jk>protected void</jk> onError(HttpServletRequest req, HttpServletResponse res, RestException e, <jk>boolean</jk> noTrace) {
+	 * 		String qs = req.getQueryString();
+	 * 		String msg = <js>"HTTP "</js> + req.getMethod() + <js>" "</js> + e.getStatus() + <js>" "</js> + req.getRequestURI() + (qs == <jk>null</jk> ? <js>""</js> : <js>"?"</js> + qs);
+	 * 		<jk>int</jk> c = e.getOccurrence();
+	 *
+	 * 		<jc>// REST_useStackTraceHashes is disabled, so we have to log the exception every time.</jc>
+	 * 		<jk>if</jk> (c == 0)
+	 * 			myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%s] %s"</js>, e.getStatus(), msg), e);
+	 *
+	 * 		<jc>// This is the first time we've countered this error, so log a stack trace
+	 * 		// unless ?noTrace was passed in as a URL parameter.</jc>
+	 * 		<jk>else if</jk> (c == 1 &amp;&amp; ! noTrace)
+	 * 			myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%h.%s.%s] %s"</js>, e.hashCode(), e.getStatus(), c, msg), e);
+	 *
+	 * 		<jc>// This error occurred before.
+	 * 		// Only log the message, not the stack trace.</jc>
+	 * 		<jk>else</jk>
+	 * 			myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%h.%s.%s] %s, %s"</js>, e.hashCode(), e.getStatus(), c, msg, e.getLocalizedMessage()));
+	 * 	}
+	 * </p>
+	 *
+	 * @param req The servlet request object.
+	 * @param res The servlet response object.
+	 * @param e Exception indicating what error occurred.
+	 */
+	protected void onError(HttpServletRequest req, HttpServletResponse res, RestException e) {
+		if (shouldLog(req, res, e)) {
+			String qs = req.getQueryString();
+			String msg = "HTTP " + req.getMethod() + " " + e.getStatus() + " " + req.getRequestURI() + (qs == null ? "" : "?" + qs);
+			int c = e.getOccurrence();
+			if (shouldLogStackTrace(req, res, e)) {
+				msg = '[' + Integer.toHexString(e.hashCode()) + '.' + e.getStatus() + '.' + c + "] " + msg;
+				log(Level.WARNING, e, msg);
+			} else {
+				msg = '[' + Integer.toHexString(e.hashCode()) + '.' + e.getStatus() + '.' + c + "] " + msg + ", " + e.getLocalizedMessage();
+				log(Level.WARNING, msg);
+			}
+		}
+	}
+
+	/**
+	 * Returns <jk>true</jk> if the specified exception should be logged.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own logic for determining when exceptions are logged.
+	 *
+	 * <p>
+	 * The default implementation will return <jk>false</jk> if <js>"noTrace=true"</js> is passed in the query string
+	 * or <code>No-Trace: true</code> is specified in the header.
+	 *
+	 * @param req The HTTP request.
+	 * @param res The HTTP response.
+	 * @param e The exception.
+	 * @return <jk>true</jk> if exception should be logged.
+	 */
+	protected boolean shouldLog(HttpServletRequest req, HttpServletResponse res, RestException e) {
+		if (isNoTrace(req) && ! isDebug(req))
+			return false;
+		return true;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if a stack trace should be logged for this exception.
+	 *
+	 * <p>
+	 * Subclasses can override this method to provide their own logic for determining when stack traces are logged.
+	 *
+	 * <p>
+	 * The default implementation will only log a stack trace if {@link RestException#getOccurrence()} returns
+	 * <code>1</code> and the exception is not one of the following:
+	 * <ul>
+	 * 	<li>{@link HttpServletResponse#SC_UNAUTHORIZED}
+	 * 	<li>{@link HttpServletResponse#SC_FORBIDDEN}
+	 * 	<li>{@link HttpServletResponse#SC_NOT_FOUND}
+	 * </ul>
+	 *
+	 * @param req The HTTP request.
+	 * @param res The HTTP response.
+	 * @param e The exception.
+	 * @return <jk>true</jk> if stack trace should be logged.
+	 */
+	protected boolean shouldLogStackTrace(HttpServletRequest req, HttpServletResponse res, RestException e) {
+		if (e.getOccurrence() == 1) {
+			switch (e.getStatus()) {
+				case SC_UNAUTHORIZED:
+				case SC_FORBIDDEN:
+				case SC_NOT_FOUND:  return false;
+				default:            return true;
+			}
+		}
+		return false;
+	}
+
+	private static boolean isNoTrace(HttpServletRequest req) {
+		return "true".equals(req.getHeader("No-Trace")) || (req.getQueryString() != null && req.getQueryString().contains("noTrace=true"));
+	}
+
+	private static boolean isDebug(HttpServletRequest req) {
+		return "true".equals(req.getHeader("Debug"));
+	}
+
+	/**
+	 * NO-OP logger.
+	 *
+	 * <p>
+	 * Disables all logging.
+	 *
+	 * @author James Bognar (james.bognar@salesforce.com)
+	 */
+	public static class NoOp extends RestLogger {
+
+		@Override /* RestLogger */
+		protected Logger getLogger() {
+			return null;
+		}
+
+		@Override /* RestLogger */
+		protected void log(Level level, Throwable cause, String msg, Object...args) {}
+	}
+
+	/**
+	 * Default logger.
+	 *
+	 * <p>
+	 * Logs all messages to the logger returned by <code>Logger.<jsm>getLogger</jsm>(getClass().getName())</code>
+	 */
+	public static class Normal extends RestLogger {
+
+		private final JuneauLogger logger = JuneauLogger.getLogger(getClass());
+
+		@Override /* RestLogger */
+		protected Logger getLogger() {
+			return logger;
+		}
+
+		@Override /* RestLogger */
+		protected void log(Level level, Throwable cause, String msg, Object...args) {
+			msg = format(msg, args);
+			getLogger().log(level, msg, cause);
+		}
+	}
+}

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

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMatcher.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMatcher.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMatcher.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,79 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Class used for defining method-level matchers using the {@link RestMethod#matchers()} annotation.
+ *
+ * <p>
+ * Matchers are used to allow multiple Java methods to handle requests assigned to the same URL path pattern, but
+ * differing based on some request attribute, such as a specific header value.
+ * For example, matchers can be used to provide two different methods for handling requests from two different client
+ * versions.
+ *
+ * <p>
+ * Java methods with matchers associated with them are always attempted before Java methods without matchers.
+ * This allows a 'default' method to be defined to handle requests where no matchers match.
+ *
+ * <p>
+ * When multiple matchers are specified on a method, only one matcher is required to match.
+ * This is opposite from the {@link RestMethod#guards()} annotation, where all guards are required to match in order to
+ * execute the method.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * 	<jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
+ *
+ * 		<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo"</js>, matchers=IsDNT.<jk>class</jk>)
+ * 		<jk>public</jk> Object doGetWithDNT() {
+ * 			<jc>// Handle request with Do-Not-Track specified</jc>
+ * 		}
+ *
+ * 		<ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foo"</js>)
+ * 		<jk>public</jk> Object doGetWithoutDNT() {
+ * 			<jc>// Handle request without Do-Not-Track specified</jc>
+ * 		}
+ * 	}
+ *
+ * 	<jk>public class</jk> IsDNT <jk>extends</jk> RestMatcher {
+ * 		<ja>@Override</ja>
+ * 		<jk>public boolean</jk> matches(RestRequest req) {
+ * 			<jk>return</jk> req.getHeader(<jk>int</jk>.<jk>class</jk>, <js>"DNT"</js>, 0) == 1;
+ * 		}
+ * 	}
+ * </p>
+ */
+public abstract class RestMatcher {
+
+	/**
+	 * Returns <jk>true</jk> if the specified request matches this matcher.
+	 *
+	 * @param req The servlet request.
+	 * @return <jk>true</jk> if the specified request matches this matcher.
+	 */
+	public abstract boolean matches(RestRequest req);
+
+	/**
+	 * Returns <jk>true</jk> if this matcher is required to match in order for the method to be invoked.
+	 *
+	 * <p>
+	 * If <jk>false</jk>, then only one of the matchers must match.
+	 *
+	 * @return <jk>true</jk> if this matcher is required to match in order for the method to be invoked.
+	 */
+	public boolean mustMatch() {
+		return false;
+	}
+}

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

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,33 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import java.lang.reflect.*;
+
+/**
+ * Subclass of {@link RestMatcher} that gives access to the servlet/resource and Java method it's applied to.
+ *
+ * <p>
+ * Essentially the same as {@link RestMatcher} except has a constructor where the Java method is passed in so that you
+ * can access annotations defined on it to tailor the behavior of the matcher.
+ */
+public abstract class RestMatcherReflecting extends RestMatcher {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param resource The REST servlet.
+	 * @param javaMethod The Java method that this rest matcher is defined on.
+	 */
+	protected RestMatcherReflecting(Object resource, Method javaMethod) {}
+}

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

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,97 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * REST java method parameter resolver.
+ *
+ * <p>
+ * Used to resolve instances of classes being passed to Java REST methods.
+ *
+ * <p>
+ * This class is associated with REST classes via the {@link RestResource#paramResolvers()} annotation and
+ * {@link RestConfig#addParamResolvers(Class...)} method.
+ */
+public abstract class RestParam {
+
+	final RestParamType paramType;
+	final String name;
+	final Type type;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param paramType The Swagger parameter type.
+	 * @param name
+	 * 	The parameter name.
+	 * 	Can be <jk>null</jk> if parameter doesn't have a name (e.g. the request body).
+	 * @param type The object type to convert the parameter to.
+	 */
+	protected RestParam(RestParamType paramType, String name, Type type) {
+		this.paramType = paramType;
+		this.name = name;
+		this.type = type;
+	}
+
+	/**
+	 * Resolves the parameter object.
+	 *
+	 * @param req The rest request.
+	 * @param res The rest response.
+	 * @return The resolved object.
+	 * @throws Exception
+	 */
+	public abstract Object resolve(RestRequest req, RestResponse res) throws Exception;
+
+	/**
+	 * Returns the parameter class type that this parameter resolver is meant for.
+	 *
+	 * @return The parameter class type, or <jk>null</jk> if the type passed in isn't an instance of {@link Class}.
+	 */
+	protected Class<?> forClass() {
+		if (type instanceof Class)
+			return (Class<?>)type;
+		return null;
+	}
+
+	/**
+	 * Returns the swagger parameter type for this parameter as shown in the Swagger doc.
+	 *
+	 * @return the swagger parameter type for this parameter.
+	 */
+	protected RestParamType getParamType() {
+		return paramType;
+	}
+
+	/**
+	 * Returns the parameter name for this parameter as shown in the Swagger doc.
+	 *
+	 * @return the parameter name for this parameter.
+	 */
+	protected String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the parameter class type.
+	 *
+	 * @return the parameter class type.
+	 */
+	public Type getType() {
+		return type;
+	}
+}

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

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,971 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.rest.RestParamType.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.logging.*;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.http.Date;
+import org.apache.juneau.ini.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Default REST method parameter resolvers.
+ */
+class RestParamDefaults {
+
+	/**
+	 * Standard set of method parameter resolvers.
+	 */
+	static final Map<Class<?>,RestParam> STANDARD_RESOLVERS;
+
+	static {
+		Map<Class<?>,RestParam> m = new HashMap<Class<?>,RestParam>();
+
+		@SuppressWarnings("rawtypes")
+		Class[] r = new Class[] {
+
+			// Standard top-level objects
+			HttpServletRequestObject.class,
+			RestRequestObject.class,
+			HttpServletResponseObject.class,
+			RestResponseObject.class,
+
+			// Headers
+			AcceptHeader.class,
+			AcceptCharsetHeader.class,
+			AcceptEncodingHeader.class,
+			AcceptLanguageHeader.class,
+			AuthorizationHeader.class,
+			CacheControlHeader.class,
+			ConnectionHeader.class,
+			ContentLengthHeader.class,
+			ContentTypeHeader.class,
+			DateHeader.class,
+			ExpectHeader.class,
+			FromHeader.class,
+			HostHeader.class,
+			IfMatchHeader.class,
+			IfModifiedSinceHeader.class,
+			IfNoneMatchHeader.class,
+			IfRangeHeader.class,
+			IfUnmodifiedSinceHeader.class,
+			MaxForwardsHeader.class,
+			PragmaHeader.class,
+			ProxyAuthorizationHeader.class,
+			RangeHeader.class,
+			RefererHeader.class,
+			TEHeader.class,
+			UserAgentHeader.class,
+			UpgradeHeader.class,
+			ViaHeader.class,
+			WarningHeader.class,
+			TimeZoneHeader.class,
+
+			// Other objects
+			ResourceBundleObject.class,
+			MessageBundleObject.class,
+			InputStreamObject.class,
+			ServletInputStreamObject.class,
+			ReaderObject.class,
+			OutputStreamObject.class,
+			ServletOutputStreamObject.class,
+			WriterObject.class,
+			RequestHeadersObject.class,
+			RequestQueryObject.class,
+			RequestFormDataObject.class,
+			HttpMethodObject.class,
+			LoggerObject.class,
+			JuneauLoggerObject.class,
+			RestContextObject.class,
+			ParserObject.class,
+			LocaleObject.class,
+			SwaggerObject.class,
+			RequestPathMatchObject.class,
+			RequestBodyObject.class,
+			ConfigFileObject.class,
+			UriContextObject.class,
+			UriResolverObject.class,
+		};
+
+		for (Class<?> c : r) {
+			try {
+				RestParam mpr = (RestParam)c.newInstance();
+				m.put(mpr.forClass(), mpr);
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+
+		STANDARD_RESOLVERS = Collections.unmodifiableMap(m);
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Request / Response retrievers
+	//-------------------------------------------------------------------------------------------------------------------
+
+	static final class HttpServletRequestObject extends RestParam {
+
+		protected HttpServletRequestObject() {
+			super(OTHER, null, HttpServletRequest.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) {
+			return req;
+		}
+	}
+
+	static final class HttpServletResponseObject extends RestParam {
+
+		protected HttpServletResponseObject() {
+			super(OTHER, null, HttpServletResponse.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) {
+			return res;
+		}
+	}
+
+	static final class RestRequestObject extends RestParam {
+
+		protected RestRequestObject() {
+			super(OTHER, null, RestRequest.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) {
+			return req;
+		}
+	}
+
+	static final class RestResponseObject extends RestParam {
+
+		protected RestResponseObject() {
+			super(OTHER, null, RestResponse.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) {
+			return res;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Header retrievers
+	//-------------------------------------------------------------------------------------------------------------------
+
+	static final class AcceptHeader extends RestParam {
+
+		protected AcceptHeader() {
+			super(HEADER, "Accept-Header", Accept.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getAccept();
+		}
+	}
+
+	static final class AcceptCharsetHeader extends RestParam {
+
+		protected AcceptCharsetHeader() {
+			super(HEADER, "Accept-Charset", AcceptCharset.class);
+		}
+
+		@Override /* RestParam */
+		public AcceptCharset resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getAcceptCharset();
+		}
+	}
+
+	static final class AcceptEncodingHeader extends RestParam {
+
+		protected AcceptEncodingHeader() {
+			super(HEADER, "Accept-Encoding", AcceptEncoding.class);
+		}
+
+		@Override
+		public AcceptEncoding resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getAcceptEncoding();
+		}
+	}
+
+	static final class AcceptLanguageHeader extends RestParam {
+
+		protected AcceptLanguageHeader() {
+			super(HEADER, "Accept-Language", AcceptLanguage.class);
+		}
+
+		@Override
+		public AcceptLanguage resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getAcceptLanguage();
+		}
+	}
+
+	static final class AuthorizationHeader extends RestParam {
+
+		protected AuthorizationHeader() {
+			super(HEADER, "Authorization", Authorization.class);
+		}
+
+		@Override
+		public Authorization resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getAuthorization();
+		}
+	}
+
+	static final class CacheControlHeader extends RestParam {
+
+		protected CacheControlHeader() {
+			super(HEADER, "Cache-Control", CacheControl.class);
+		}
+
+		@Override
+		public CacheControl resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getCacheControl();
+		}
+	}
+
+	static final class ConnectionHeader extends RestParam {
+
+		protected ConnectionHeader() {
+			super(HEADER, "Connection", Connection.class);
+		}
+
+		@Override
+		public Connection resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getConnection();
+		}
+	}
+
+	static final class ContentLengthHeader extends RestParam {
+
+		protected ContentLengthHeader() {
+			super(HEADER, "Content-Length", ContentLength.class);
+		}
+
+		@Override
+		public ContentLength resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getContentLength();
+		}
+	}
+
+	static final class ContentTypeHeader extends RestParam {
+
+		protected ContentTypeHeader() {
+			super(HEADER, "Content-Type", ContentType.class);
+		}
+
+		@Override
+		public ContentType resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getContentType();
+		}
+	}
+
+	static final class DateHeader extends RestParam {
+
+		protected DateHeader() {
+			super(HEADER, "Date", Date.class);
+		}
+
+		@Override
+		public Date resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getDate();
+		}
+	}
+
+	static final class ExpectHeader extends RestParam {
+
+		protected ExpectHeader() {
+			super(HEADER, "Expect", Expect.class);
+		}
+
+		@Override
+		public Expect resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getExpect();
+		}
+	}
+
+	static final class FromHeader extends RestParam {
+
+		protected FromHeader() {
+			super(HEADER, "From", From.class);
+		}
+
+		@Override
+		public From resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getFrom();
+		}
+	}
+
+	static final class HostHeader extends RestParam {
+
+		protected HostHeader() {
+			super(HEADER, "Host", Host.class);
+		}
+
+		@Override
+		public Host resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getHost();
+		}
+	}
+
+	static final class IfMatchHeader extends RestParam {
+
+		protected IfMatchHeader() {
+			super(HEADER, "If-Match", IfMatch.class);
+		}
+
+		@Override
+		public IfMatch resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getIfMatch();
+		}
+	}
+
+	static final class IfModifiedSinceHeader extends RestParam {
+
+		protected IfModifiedSinceHeader() {
+			super(HEADER, "If-Modified-Since", IfModifiedSince.class);
+		}
+
+		@Override
+		public IfModifiedSince resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getIfModifiedSince();
+		}
+	}
+
+	static final class IfNoneMatchHeader extends RestParam {
+
+		protected IfNoneMatchHeader() {
+			super(HEADER, "If-None-Match", IfNoneMatch.class);
+		}
+
+		@Override
+		public IfNoneMatch resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getIfNoneMatch();
+		}
+	}
+
+	static final class IfRangeHeader extends RestParam {
+
+		protected IfRangeHeader() {
+			super(HEADER, "If-Range", IfRange.class);
+		}
+
+		@Override
+		public IfRange resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getIfRange();
+		}
+	}
+
+	static final class IfUnmodifiedSinceHeader extends RestParam {
+
+		protected IfUnmodifiedSinceHeader() {
+			super(HEADER, "If-Unmodified-Since", IfUnmodifiedSince.class);
+		}
+
+		@Override
+		public IfUnmodifiedSince resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getIfUnmodifiedSince();
+		}
+	}
+
+	static final class MaxForwardsHeader extends RestParam {
+
+		protected MaxForwardsHeader() {
+			super(HEADER, "Max-Forwards", MaxForwards.class);
+		}
+
+		@Override
+		public MaxForwards resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getMaxForwards();
+		}
+	}
+
+	static final class PragmaHeader extends RestParam {
+
+		protected PragmaHeader() {
+			super(HEADER, "Pragma", Pragma.class);
+		}
+
+		@Override
+		public Pragma resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getPragma();
+		}
+	}
+
+	static final class ProxyAuthorizationHeader extends RestParam {
+
+		protected ProxyAuthorizationHeader() {
+			super(HEADER, "Proxy-Authorization", ProxyAuthorization.class);
+		}
+
+		@Override
+		public ProxyAuthorization resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getProxyAuthorization();
+		}
+	}
+
+	static final class RangeHeader extends RestParam {
+
+		protected RangeHeader() {
+			super(HEADER, "Range", Range.class);
+		}
+
+		@Override
+		public Range resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getRange();
+		}
+	}
+
+	static final class RefererHeader extends RestParam {
+
+		protected RefererHeader() {
+			super(HEADER, "Referer", Referer.class);
+		}
+
+		@Override
+		public Referer resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getReferer();
+		}
+	}
+
+	static final class TEHeader extends RestParam {
+
+		protected TEHeader() {
+			super(HEADER, "TE", TE.class);
+		}
+
+		@Override
+		public TE resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getTE();
+		}
+	}
+
+	static final class UserAgentHeader extends RestParam {
+
+		protected UserAgentHeader() {
+			super(HEADER, "User-Agent", UserAgent.class);
+		}
+
+		@Override
+		public UserAgent resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getUserAgent();
+		}
+	}
+
+	static final class UpgradeHeader extends RestParam {
+
+		protected UpgradeHeader() {
+			super(HEADER, "Upgrade", Upgrade.class);
+		}
+
+		@Override
+		public Upgrade resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getUpgrade();
+		}
+	}
+
+	static final class ViaHeader extends RestParam {
+
+		protected ViaHeader() {
+			super(HEADER, "Via", Via.class);
+		}
+
+		@Override
+		public Via resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getVia();
+		}
+	}
+
+	static final class WarningHeader extends RestParam {
+
+		protected WarningHeader() {
+			super(HEADER, "Warning", Warning.class);
+		}
+
+		@Override
+		public Warning resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getWarning();
+		}
+	}
+
+	static final class TimeZoneHeader extends RestParam {
+
+		protected TimeZoneHeader() {
+			super(HEADER, "Time-Zone", TimeZone.class);
+		}
+
+		@Override
+		public TimeZone resolve(RestRequest req, RestResponse res) {
+			return req.getHeaders().getTimeZone();
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Annotated retrievers
+	//-------------------------------------------------------------------------------------------------------------------
+
+	static final class PathParameterObject extends RestParam {
+
+		protected PathParameterObject(String name, Type type) {
+			super(PATH, name, type);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getPathMatch().get(name, type);
+		}
+	}
+
+	static final class BodyObject extends RestParam {
+
+		protected BodyObject(Type type) {
+			super(BODY, null, type);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getBody().asType(type);
+		}
+	}
+
+	static final class HeaderObject extends RestParam {
+
+		protected HeaderObject(Header a, Type type) {
+			super(HEADER, firstNonEmpty(a.name(), a.value()), type);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getHeaders().get(name, type);
+		}
+	}
+
+	static final class MethodObject extends RestParam {
+
+		protected MethodObject(Method method, Type type) throws ServletException {
+			super(OTHER, null, null);
+			if (type != String.class)
+				throw new RestServletException("Use of @Method annotation on parameter that is not a String on method ''{0}''", method);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getMethod();
+		}
+	}
+
+	static final class FormDataObject extends RestParam {
+		private final boolean multiPart, plainParams;
+
+		protected FormDataObject(Method method, FormData a, Type type, boolean methodPlainParams) throws ServletException {
+			super(FORMDATA, firstNonEmpty(a.name(), a.value()), type);
+			if (a.multipart() && ! isCollection(type))
+					throw new RestServletException("Use of multipart flag on @FormData parameter that's not an array or Collection on method ''{0}''", method);
+			this.multiPart = a.multipart();
+			this.plainParams = a.format().equals("INHERIT") ? methodPlainParams : a.format().equals("PLAIN");
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			BeanSession bs = req.getBeanSession();
+			if (multiPart)
+				return req.getFormData().getAll(name, type);
+			if (plainParams)
+				return bs.convertToType(req.getFormData().getString(name), bs.getClassMeta(type));
+			return req.getFormData().get(name, type);
+		}
+	}
+
+	static final class QueryObject extends RestParam {
+		private final boolean multiPart, plainParams;
+
+		protected QueryObject(Method method, Query a, Type type, boolean methodPlainParams) throws ServletException {
+			super(QUERY, firstNonEmpty(a.name(), a.value()), type);
+			if (a.multipart() && ! isCollection(type))
+					throw new RestServletException("Use of multipart flag on @Query parameter that's not an array or Collection on method ''{0}''", method);
+			this.multiPart = a.multipart();
+			this.plainParams = a.format().equals("INHERIT") ? methodPlainParams : a.format().equals("PLAIN");
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			BeanSession bs = req.getBeanSession();
+			if (multiPart)
+				return req.getQuery().getAll(name, type);
+			if (plainParams)
+				return bs.convertToType(req.getQuery().getString(name), bs.getClassMeta(type));
+			return req.getQuery().get(name, type);
+		}
+	}
+
+	static final class HasFormDataObject extends RestParam {
+
+		protected HasFormDataObject(Method method, HasFormData a, Type type) throws ServletException {
+			super(FORMDATA, firstNonEmpty(a.name(), a.value()), type);
+			if (type != Boolean.class && type != boolean.class)
+				throw new RestServletException("Use of @HasForm annotation on parameter that is not a boolean on method ''{0}''", method);
+	}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			BeanSession bs = req.getBeanSession();
+			return bs.convertToType(req.getFormData().containsKey(name), bs.getClassMeta(type));
+		}
+	}
+
+	static final class HasQueryObject extends RestParam {
+
+		protected HasQueryObject(Method method, HasQuery a, Type type) throws ServletException {
+			super(QUERY, firstNonEmpty(a.name(), a.value()), type);
+			if (type != Boolean.class && type != boolean.class)
+				throw new RestServletException("Use of @HasQuery annotation on parameter that is not a boolean on method ''{0}''", method);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			BeanSession bs = req.getBeanSession();
+			return bs.convertToType(req.getQuery().containsKey(name), bs.getClassMeta(type));
+		}
+	}
+
+	static final class PathRemainderObject extends RestParam {
+
+		protected PathRemainderObject(Method method, Type type) throws ServletException {
+			super(OTHER, null, null);
+			if (type != String.class)
+				throw new RestServletException("Use of @PathRemainder annotation on parameter that is not a String on method ''{0}''", method);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getPathMatch().getRemainder();
+		}
+	}
+
+	static final class PropsObject extends RestParam {
+
+		protected PropsObject(Method method, Type type) throws ServletException {
+			super(OTHER, null, null);
+			if (type != ObjectMap.class)
+				throw new RestServletException("Use of @Properties annotation on parameter that is not an ObjectMap on method ''{0}''", method);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getProperties();
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Other retrievers
+	//-------------------------------------------------------------------------------------------------------------------
+
+	static final class ResourceBundleObject extends RestParam {
+
+		protected ResourceBundleObject() {
+			super(OTHER, null, ResourceBundle.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getResourceBundle();
+		}
+	}
+
+	static final class MessageBundleObject extends RestParam {
+
+		protected MessageBundleObject() {
+			super(OTHER, null, MessageBundle.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getResourceBundle();
+		}
+	}
+
+	static final class InputStreamObject extends RestParam {
+
+		protected InputStreamObject() {
+			super(OTHER, null, InputStream.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getInputStream();
+		}
+	}
+
+	static final class ServletInputStreamObject extends RestParam {
+
+		protected ServletInputStreamObject() {
+			super(OTHER, null, ServletInputStream.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getInputStream();
+		}
+	}
+
+	static final class ReaderObject extends RestParam {
+
+		protected ReaderObject() {
+			super(OTHER, null, Reader.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getReader();
+		}
+	}
+
+	static final class OutputStreamObject extends RestParam {
+
+		protected OutputStreamObject() {
+			super(OTHER, null, OutputStream.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return res.getOutputStream();
+		}
+	}
+
+	static final class ServletOutputStreamObject extends RestParam {
+
+		protected ServletOutputStreamObject() {
+			super(OTHER, null, ServletOutputStream.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return res.getOutputStream();
+		}
+	}
+
+	static final class WriterObject extends RestParam {
+
+		protected WriterObject() {
+			super(OTHER, null, Writer.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return res.getWriter();
+		}
+	}
+
+	static final class RequestHeadersObject extends RestParam {
+
+		protected RequestHeadersObject() {
+			super(OTHER, null, RequestHeaders.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getHeaders();
+		}
+	}
+
+	static final class RequestQueryObject extends RestParam {
+
+		protected RequestQueryObject() {
+			super(OTHER, null, RequestQuery.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getQuery();
+		}
+	}
+
+	static final class RequestFormDataObject extends RestParam {
+
+		protected RequestFormDataObject() {
+			super(OTHER, null, RequestFormData.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getFormData();
+		}
+	}
+
+	static final class HttpMethodObject extends RestParam {
+
+		protected HttpMethodObject() {
+			super(OTHER, null, HttpMethod.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getHttpMethod();
+		}
+	}
+
+	static final class LoggerObject extends RestParam {
+
+		protected LoggerObject() {
+			super(OTHER, null, Logger.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getContext().getLogger().getLogger();
+		}
+	}
+
+	static final class JuneauLoggerObject extends RestParam {
+
+		protected JuneauLoggerObject() {
+			super(OTHER, null, JuneauLogger.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getContext().getLogger().getLogger();
+		}
+	}
+
+	static final class RestContextObject extends RestParam {
+
+		protected RestContextObject() {
+			super(OTHER, null, RestContext.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getContext();
+		}
+	}
+
+	static final class ParserObject extends RestParam {
+
+		protected ParserObject() {
+			super(OTHER, null, Parser.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getBody().getParser();
+		}
+	}
+
+	static final class LocaleObject extends RestParam {
+
+		protected LocaleObject() {
+			super(OTHER, null, Locale.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getLocale();
+		}
+	}
+
+	static final class SwaggerObject extends RestParam {
+
+		protected SwaggerObject() {
+			super(OTHER, null, Swagger.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getSwagger();
+		}
+	}
+
+	static final class RequestPathMatchObject extends RestParam {
+
+		protected RequestPathMatchObject() {
+			super(OTHER, null, RequestPathMatch.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getPathMatch();
+		}
+	}
+
+	static final class RequestBodyObject extends RestParam {
+
+		protected RequestBodyObject() {
+			super(BODY, null, RequestBody.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getBody();
+		}
+	}
+
+	static final class ConfigFileObject extends RestParam {
+
+		protected ConfigFileObject() {
+			super(OTHER, null, ConfigFile.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getConfigFile();
+		}
+	}
+
+	static final class UriContextObject extends RestParam {
+
+		protected UriContextObject() {
+			super(OTHER, null, UriContext.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getUriContext();
+		}
+	}
+
+	static final class UriResolverObject extends RestParam {
+
+		protected UriResolverObject() {
+			super(OTHER, null, UriResolver.class);
+		}
+
+		@Override /* RestParam */
+		public Object resolve(RestRequest req, RestResponse res) throws Exception {
+			return req.getUriResolver();
+		}
+	}
+
+	private static boolean isCollection(Type t) {
+		return BeanContext.DEFAULT.getClassMeta(t).isCollectionOrArray();
+	}
+}

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

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamType.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamType.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamType.java Fri Sep  8 23:25:34 2017
@@ -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.rest;
+
+/**
+ * Represents the possible parameter types as defined by the Swagger 2.0 specification.
+ */
+public enum RestParamType {
+
+	/** Path variable */
+	PATH("path"),
+
+	/** Header value */
+	HEADER("header"),
+
+	/** Form data entry */
+	FORMDATA("formData"),
+
+	/** Query parameter */
+	QUERY("query"),
+
+	/** Request body */
+	BODY("body"),
+
+	/** Not a standard Swagger-defined field */
+	OTHER("other");
+
+	private final String value;
+
+	private RestParamType(String value) {
+		this.value = value;
+	}
+
+	@Override /* Object */
+	public String toString() {
+		return value;
+	}
+}

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