Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,333 @@
+// 
***************************************************************************************************************************
+// * 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 java.util.logging.Level.*;
+import static javax.servlet.http.HttpServletResponse.*;
+import static org.apache.juneau.internal.IOUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.io.*;
+import java.util.*;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.vars.*;
+
+/**
+ * Class that handles the basic lifecycle of an HTTP REST call.
+ *
+ * <p>
+ * Subclasses can override these methods to tailor how HTTP REST calls are 
handled.
+ * Subclasses MUST implement a public constructor that takes in a {@link 
RestContext} object.
+ *
+ * <p>
+ * RestCallHandlers are associated with servlets/resources in one of the 
following ways:
+ * <ul>
+ *     <li>The {@link RestResource#callHandler @RestResource.callHandler()} 
annotation.
+ *     <li>The {@link RestConfig#setCallHandler(Class)} method.
+ * </ul>
+ */
+public class RestCallHandler {
+
+       private final RestContext context;
+       private final RestLogger logger;
+       private final Map<String,CallRouter> callRouters;
+
+       /**
+        * Constructor.
+        *
+        * @param context The resource context.
+        */
+       public RestCallHandler(RestContext context) {
+               this.context = context;
+               this.logger = context.getLogger();
+               this.callRouters = context.getCallRouters();
+       }
+
+       /**
+        * Creates a {@link RestRequest} object based on the specified incoming 
{@link HttpServletRequest} object.
+        *
+        * <p>
+        * Subclasses may choose to override this method to provide a 
specialized request object.
+        *
+        * @param req The request object from the {@link 
#service(HttpServletRequest, HttpServletResponse)} method.
+        * @return The wrapped request object.
+        * @throws ServletException If any errors occur trying to interpret the 
request.
+        */
+       protected RestRequest createRequest(HttpServletRequest req) throws 
ServletException {
+               return new RestRequest(context, req);
+       }
+
+       /**
+        * Creates a {@link RestResponse} object based on the specified 
incoming {@link HttpServletResponse} object
+        * and the request returned by {@link 
#createRequest(HttpServletRequest)}.
+        *
+        * <p>
+        * Subclasses may choose to override this method to provide a 
specialized response object.
+        *
+        * @param req The request object returned by {@link 
#createRequest(HttpServletRequest)}.
+        * @param res The response object from the {@link 
#service(HttpServletRequest, HttpServletResponse)} method.
+        * @return The wrapped response object.
+        * @throws ServletException If any errors occur trying to interpret the 
request or response.
+        */
+       protected RestResponse createResponse(RestRequest req, 
HttpServletResponse res) throws ServletException {
+               return new RestResponse(context, req, res);
+       }
+
+       /**
+        * The main service method.
+        *
+        * <p>
+        * Subclasses can optionally override this method if they want to 
tailor the behavior of requests.
+        *
+        * @param r1 The incoming HTTP servlet request object.
+        * @param r2 The incoming HTTP servlet response object.
+        * @throws ServletException
+        * @throws IOException
+        */
+       protected void service(HttpServletRequest r1, HttpServletResponse r2) 
throws ServletException, IOException {
+
+               logger.log(FINE, "HTTP: {0} {1}", r1.getMethod(), 
r1.getRequestURI());
+               long startTime = System.currentTimeMillis();
+
+               try {
+                       context.checkForInitException();
+
+                       String pathInfo = RestUtils.getPathInfoUndecoded(r1);  
// Can't use r1.getPathInfo() because we don't want '%2F' resolved.
+
+                       // If this resource has child resources, try to 
recursively call them.
+                       if (pathInfo != null && context.hasChildResources() && 
(! pathInfo.equals("/"))) {
+                               int i = pathInfo.indexOf('/', 1);
+                               String pathInfoPart = i == -1 ? 
pathInfo.substring(1) : pathInfo.substring(1, i);
+                               RestContext childResource = 
context.getChildResource(pathInfoPart);
+                               if (childResource != null) {
+                                       final String pathInfoRemainder = (i == 
-1 ? null : pathInfo.substring(i));
+                                       final String servletPath = 
r1.getServletPath() + "/" + pathInfoPart;
+                                       final HttpServletRequest childRequest = 
new HttpServletRequestWrapper(r1) {
+                                               @Override /* ServletRequest */
+                                               public String getPathInfo() {
+                                                       return 
urlDecode(pathInfoRemainder);
+                                               }
+                                               @Override /* ServletRequest */
+                                               public String getServletPath() {
+                                                       return servletPath;
+                                               }
+                                       };
+                                       
childResource.getCallHandler().service(childRequest, r2);
+                                       return;
+                               }
+                       }
+
+                       context.startCall(r1, r2);
+
+                       RestRequest req = createRequest(r1);
+                       RestResponse res = createResponse(req, r2);
+                       String method = req.getMethod();
+                       String methodUC = method.toUpperCase(Locale.ENGLISH);
+
+                       StreamResource r = null;
+                       if (pathInfo != null) {
+                               String p = pathInfo.substring(1);
+                               if (p.equals("favicon.ico"))
+                                       r = context.getFavIcon();
+                               else if (context.isStaticFile(p))
+                                       r = context.resolveStaticFile(p);
+                       }
+
+                       if (r != null) {
+                               res.setStatus(SC_OK);
+                               res.setOutput(r);
+                       } else {
+                               // If the specified method has been defined in 
a subclass, invoke it.
+                               int rc = SC_METHOD_NOT_ALLOWED;
+                               if (callRouters.containsKey(methodUC)) {
+                                       rc = 
callRouters.get(methodUC).invoke(pathInfo, req, res);
+                               } else if (callRouters.containsKey("*")) {
+                                       rc = 
callRouters.get("*").invoke(pathInfo, req, res);
+                               }
+
+                               // If not invoked above, see if it's an OPTIONs 
request
+                               if (rc != SC_OK)
+                                       handleNotFound(rc, req, res);
+                       }
+
+                       if (res.hasOutput()) {
+                               Object output = res.getOutput();
+
+                               // Do any class-level transforming.
+                               for (RestConverter converter : 
context.getConverters())
+                                       output = converter.convert(req, output, 
context.getBeanContext().getClassMetaForObject(output));
+
+                               res.setOutput(output);
+
+                               // Now serialize the output if there was any.
+                               // Some subclasses may write to the 
OutputStream or Writer directly.
+                               handleResponse(req, res, output);
+                       }
+
+                       // Make sure our writer in RestResponse gets written.
+                       res.flushBuffer();
+
+                       r1.setAttribute("ExecTime", System.currentTimeMillis() 
- startTime);
+
+               } catch (RestException e) {
+                       handleError(r1, r2, e);
+                       r1.setAttribute("Exception", e);
+               } catch (Throwable e) {
+                       RestException e2 = new 
RestException(SC_INTERNAL_SERVER_ERROR, e);
+                       handleError(r1, r2, e2);
+                       r1.setAttribute("Exception", e);
+               }
+
+               context.finishCall(r1, r2);
+
+               logger.log(FINE, "HTTP: [{0} {1}] finished in {2}ms", 
r1.getMethod(), r1.getRequestURI(), System.currentTimeMillis()-startTime);
+       }
+
+       /**
+        * The main method for serializing POJOs passed in through the {@link 
RestResponse#setOutput(Object)} method or
+        * returned by the Java method.
+        *
+        * <p>
+        * Subclasses may override this method if they wish to modify the way 
the output is rendered or support other output
+        * formats.
+        *
+        * <p>
+        * The default implementation simply iterates through the response 
handlers on this resource
+        * looking for the first one whose {@link 
ResponseHandler#handle(RestRequest, RestResponse, Object)} method returns
+        * <jk>true</jk>.
+        *
+        * @param req The HTTP request.
+        * @param res The HTTP response.
+        * @param output The output to serialize in the response.
+        * @throws IOException
+        * @throws RestException
+        */
+       protected void handleResponse(RestRequest req, RestResponse res, Object 
output) throws IOException, RestException {
+               // Loop until we find the correct handler for the POJO.
+               for (ResponseHandler h : context.getResponseHandlers())
+                       if (h.handle(req, res, output))
+                               return;
+               throw new RestException(SC_NOT_IMPLEMENTED, "No response 
handlers found to process output of type '"+(output == null ? null : 
output.getClass().getName())+"'");
+       }
+
+       /**
+        * Handle the case where a matching method was not found.
+        *
+        * <p>
+        * Subclasses can override this method to provide a 2nd-chance for 
specifying a response.
+        * The default implementation will simply throw an exception with an 
appropriate message.
+        *
+        * @param rc The HTTP response code.
+        * @param req The HTTP request.
+        * @param res The HTTP response.
+        * @throws Exception
+        */
+       protected void handleNotFound(int rc, RestRequest req, RestResponse 
res) throws Exception {
+               String pathInfo = req.getPathInfo();
+               String methodUC = req.getMethod();
+               String onPath = pathInfo == null ? " on no pathInfo"  : 
String.format(" on path '%s'", pathInfo);
+               if (rc == SC_NOT_FOUND)
+                       throw new RestException(rc, "Method ''{0}'' not found 
on resource with matching pattern{1}.", methodUC, onPath);
+               else if (rc == SC_PRECONDITION_FAILED)
+                       throw new RestException(rc, "Method ''{0}'' not found 
on resource{1} with matching matcher.", methodUC, onPath);
+               else if (rc == SC_METHOD_NOT_ALLOWED)
+                       throw new RestException(rc, "Method ''{0}'' not found 
on resource.", methodUC);
+               else
+                       throw new ServletException("Invalid method response: " 
+ rc);
+       }
+
+       /**
+        * Method for handling response errors.
+        *
+        * <p>
+        * The default implementation logs the error and calls
+        * {@link 
#renderError(HttpServletRequest,HttpServletResponse,RestException)}.
+        *
+        * <p>
+        * Subclasses can override this method to provide their own custom 
error response handling.
+        *
+        * @param req The servlet request.
+        * @param res The servlet response.
+        * @param e The exception that occurred.
+        * @throws IOException Can be thrown if a problem occurred trying to 
write to the output stream.
+        */
+       protected synchronized void handleError(HttpServletRequest req, 
HttpServletResponse res, RestException e) throws IOException {
+               e.setOccurrence(context == null ? 0 : 
context.getStackTraceOccurrence(e));
+               logger.onError(req, res, e);
+               renderError(req, res, e);
+       }
+
+       /**
+        * Method for rendering response errors.
+        *
+        * <p>
+        * The default implementation renders a plain text English message, 
optionally with a stack trace if
+        * {@link RestContext#REST_renderResponseStackTraces} is enabled.
+        *
+        * <p>
+        * Subclasses can override this method to provide their own custom 
error response handling.
+        *
+        * @param req The servlet request.
+        * @param res The servlet response.
+        * @param e The exception that occurred.
+        * @throws IOException Can be thrown if a problem occurred trying to 
write to the output stream.
+        */
+       protected void renderError(HttpServletRequest req, HttpServletResponse 
res, RestException e) throws IOException {
+
+               int status = e.getStatus();
+               res.setStatus(status);
+               res.setContentType("text/plain");
+               res.setHeader("Content-Encoding", "identity");
+
+               Throwable t = e.getRootCause();
+               if (t != null) {
+                       res.setHeader("Exception-Name", t.getClass().getName());
+                       res.setHeader("Exception-Message", t.getMessage());
+               }
+
+               PrintWriter w = null;
+               try {
+                       w = res.getWriter();
+               } catch (IllegalStateException e2) {
+                       w = new PrintWriter(new 
OutputStreamWriter(res.getOutputStream(), UTF8));
+               }
+               String httpMessage = RestUtils.getHttpResponseText(status);
+               if (httpMessage != null)
+                       w.append("HTTP 
").append(String.valueOf(status)).append(": 
").append(httpMessage).append("\n\n");
+               if (context != null && context.isRenderResponseStackTraces())
+                       e.printStackTrace(w);
+               else
+                       w.append(e.getFullStackMessage(true));
+               w.flush();
+               w.close();
+       }
+
+       /**
+        * Returns the session objects for the specified request.
+        *
+        * <p>
+        * The default implementation simply returns a single map containing 
<code>{'req':req}</code>.
+        *
+        * @param req The REST request.
+        * @return The session objects for that request.
+        */
+       public Map<String,Object> getSessionObjects(RestRequest req) {
+               Map<String,Object> m = new HashMap<String,Object>();
+               m.put(RequestVar.SESSION_req, req);
+               return m;
+       }
+}

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

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestConfig.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,1647 @@
+// 
***************************************************************************************************************************
+// * 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.ArrayUtils.*;
+import static org.apache.juneau.internal.ReflectionUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.rest.RestUtils.*;
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import javax.activation.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.encoders.*;
+import org.apache.juneau.encoders.Encoder;
+import org.apache.juneau.html.*;
+import org.apache.juneau.http.*;
+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.rest.response.*;
+import org.apache.juneau.rest.vars.*;
+import org.apache.juneau.rest.widget.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.svl.*;
+import org.apache.juneau.svl.vars.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Defines the initial configuration of a <code>RestServlet</code> or 
<code>@RestResource</code> annotated object.
+ *
+ * <p>
+ * An extension of the {@link ServletConfig} object used during servlet 
initialization.
+ *
+ * <p>
+ * Provides access to the following initialized resources:
+ * <ul>
+ *     <li>{@link #getConfigFile()} - The external configuration file for this 
resource.
+ *     <li>{@link #getProperties()} - The modifiable configuration properties 
for this resource.
+ *     <li>{@link #getVarResolverBuilder()} - The variable resolver for this 
resource.
+ * </ul>
+ *
+ * <p>
+ * Methods are provided for overriding or augmenting the information provided 
by the <ja>@RestResource</ja> annotation.
+ * In general, most information provided in the <ja>@RestResource</ja> 
annotation can be specified programmatically
+ * through calls on this object.
+ *
+ * <p>
+ * To interact with this object, simply implement the following init method in 
your resource class:
+ * <p class='bcode'>
+ *     <jk>public synchronized void</jk> init(RestConfig config) 
<jk>throws</jk> Exception {
+ *             
config.addPojoSwaps(CalendarSwap.<jsf>RFC2822DTZ</jsf>.<jk>class</jk>);
+ *             config.setProperty(<jsf>PARSER_debug</jsf>, <jk>true</jk>);
+ *             <jk>super</jk>.init(config); <jc>// Make sure this is the last 
line! (or just leave it out entirely)</jc>
+ *     }
+ * </p>
+ *
+ * <p>
+ * Note that this method is identical to {@link 
HttpServlet#init(ServletConfig)} except you get access to
+ * this object instead.  Also, this method can throw any exception, not just a 
{@link ServletException}.
+ *
+ * <p>
+ * The parent <code>init(RestServletConfig)</code> method will construct a 
read-only {@link RestContext} object
+ * that contains a snapshot of these settings.  If you call 
<code><jk>super</jk>.init(RestServletConfig)</code> before
+ * you modify this config object, you won't see the changes!
+ */
+@SuppressWarnings({"hiding"})
+public class RestConfig implements ServletConfig {
+
+       final ServletConfig inner;
+
+       
//---------------------------------------------------------------------------
+       // The following fields are meant to be modifiable.
+       // They should not be declared final.
+       // Read-only snapshots of these will be made in RestServletContext.
+       
//---------------------------------------------------------------------------
+
+       ObjectMap properties;
+       ConfigFile configFile;
+       VarResolverBuilder varResolverBuilder;
+
+       List<Class<?>>
+               beanFilters = new ArrayList<Class<?>>(),
+               pojoSwaps = new ArrayList<Class<?>>(),
+               paramResolvers = new ArrayList<Class<?>>();
+       Class<? extends SerializerListener> serializerListener;
+       Class<? extends ParserListener> parserListener;
+       SerializerGroupBuilder serializers = new SerializerGroupBuilder();
+       ParserGroupBuilder parsers = new ParserGroupBuilder();
+       EncoderGroupBuilder encoders = new 
EncoderGroupBuilder().append(IdentityEncoder.INSTANCE);
+       List<Object> converters = new ArrayList<Object>();
+       List<Object> guards = new ArrayList<Object>();
+       MimetypesFileTypeMap mimeTypes = new ExtendedMimetypesFileTypeMap();
+       Map<String,String> defaultRequestHeaders = new 
TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER);
+       Map<String,Object> defaultResponseHeaders = new 
LinkedHashMap<String,Object>();
+       List<Object> responseHandlers = new ArrayList<Object>();
+       List<Object> childResources = new ArrayList<Object>();
+       List<MediaType> supportedContentTypes, supportedAcceptTypes;
+       Object favIcon;
+       List<Object> staticFiles;
+       RestContext parentContext;
+       String path, htmlHeader, htmlNav, htmlAside, htmlFooter, htmlStyle, 
htmlStylesheet, htmlScript, htmlNoResultsMessage;
+       String[] htmlLinks;
+       String clientVersionHeader = "X-Client-Version";
+       String contextPath;
+
+       Object resourceResolver = RestResourceResolverSimple.class;
+       Object logger = RestLogger.Normal.class;
+       Object callHandler = RestCallHandler.class;
+       Object infoProvider = RestInfoProvider.class;
+
+       boolean htmlNoWrap;
+       Object htmlTemplate = HtmlDocTemplateBasic.class;
+
+       Class<?> resourceClass;
+       List<Class<? extends Widget>> htmlWidgets = new ArrayList<Class<? 
extends Widget>>();
+
+       /**
+        * Constructor for top-level servlets when using dependency injection.
+        *
+        * <p>
+        * Work-in-progress.
+        *
+        * @param config
+        *      The servlet config object we're extending.
+        * @param resourceClass
+        *      The class annotated with the {@link RestResource @RestResource} 
annotation.
+        * @throws ServletException
+        */
+       public RestConfig(ServletConfig config, Class<?> resourceClass) throws 
ServletException {
+               this(config, resourceClass, null);
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param config The servlet config passed into the servlet by the 
servlet container.
+        * @param resource The class annotated with <ja>@RestResource</ja>.
+        * @throws ServletException Something bad happened.
+        */
+       RestConfig(ServletConfig config, Class<?> resourceClass, RestContext 
parentContext) throws ServletException {
+               this.inner = config;
+               this.resourceClass = resourceClass;
+               this.parentContext = parentContext;
+               this.resourceResolver = parentContext == null ? 
RestResourceResolverSimple.class : parentContext.getResourceResolver();
+               try {
+
+                       ConfigFileBuilder cfb = new ConfigFileBuilder();
+
+                       properties = new ObjectMap();
+                       configFile = cfb.build();
+                       varResolverBuilder = new VarResolverBuilder()
+                               .vars(
+                                       SystemPropertiesVar.class,
+                                       EnvVariablesVar.class,
+                                       ConfigFileVar.class,
+                                       IfVar.class,
+                                       SwitchVar.class
+                               );
+
+                       VarResolver vr = varResolverBuilder.build();
+
+                       Map<Class<?>,RestResource> 
restResourceAnnotationsParentFirst = 
findAnnotationsMapParentFirst(RestResource.class, resourceClass);
+
+                       // Find our config file.  It's the last non-empty 
@RestResource.config().
+                       String configPath = "";
+                       for (RestResource r : 
restResourceAnnotationsParentFirst.values())
+                               if (! r.config().isEmpty())
+                                       configPath = r.config();
+                       String cf = vr.resolve(configPath);
+                       if (! cf.isEmpty())
+                               configFile = cfb.build(cf);
+                       configFile = configFile.getResolving(vr);
+
+                       // Add our config file to the variable resolver.
+                       
varResolverBuilder.contextObject(ConfigFileVar.SESSION_config, configFile);
+                       vr = varResolverBuilder.build();
+
+                       // Add the servlet init parameters to our properties.
+                       for (Enumeration<String> ep = 
config.getInitParameterNames(); ep.hasMoreElements();) {
+                               String p = ep.nextElement();
+                               String initParam = config.getInitParameter(p);
+                               properties.put(vr.resolve(p), 
vr.resolve(initParam));
+                       }
+
+                       // Load stuff from parent-to-child order.
+                       // This allows child settings to overwrite parent 
settings.
+                       for (Map.Entry<Class<?>,RestResource> e : 
restResourceAnnotationsParentFirst.entrySet()) {
+                               Class<?> c = e.getKey();
+                               RestResource r = e.getValue();
+                               for (Property p : r.properties())
+                                       properties.append(vr.resolve(p.name()), 
vr.resolve(p.value()));
+                               for (String p : r.flags())
+                                       properties.append(p, true);
+                               addSerializers(r.serializers());
+                               addParsers(r.parsers());
+                               addEncoders(r.encoders());
+                               
addDefaultRequestHeaders(r.defaultRequestHeaders());
+                               
addDefaultResponseHeaders(r.defaultResponseHeaders());
+                               addResponseHandlers(r.responseHandlers());
+                               addConverters(r.converters());
+                               addGuards(reverse(r.guards()));
+                               addChildResources(r.children());
+                               addBeanFilters(r.beanFilters());
+                               addPojoSwaps(r.pojoSwaps());
+                               addParamResolvers(r.paramResolvers());
+                               serializerListener(r.serializerListener());
+                               parserListener(r.parserListener());
+                               contextPath(r.contextPath());
+                               if (! r.favicon().isEmpty())
+                                       setFavIcon(c, r.favicon());
+                               if (! r.staticFiles().isEmpty())
+                                       addStaticFiles(c, r.staticFiles());
+                               if (! r.path().isEmpty())
+                                       setPath(r.path());
+                               if (! r.clientVersionHeader().isEmpty())
+                                       
setClientVersionHeader(r.clientVersionHeader());
+
+                               if (r.resourceResolver() != 
RestResourceResolver.class)
+                                       
setResourceResolver(r.resourceResolver());
+                               if (r.logger() != RestLogger.Normal.class)
+                                       setLogger(r.logger());
+                               if (r.callHandler() != RestCallHandler.class)
+                                       setCallHandler(r.callHandler());
+                               if (r.infoProvider() != RestInfoProvider.class)
+                                       setInfoProvider(r.infoProvider());
+
+                               HtmlDoc hd = r.htmldoc();
+                               for (Class<? extends Widget> cw : hd.widgets())
+                                       addHtmlWidget(cw);
+                               
setHtmlHeader(resolveNewlineSeparatedAnnotation(hd.header(), htmlHeader));
+                               
setHtmlNav(resolveNewlineSeparatedAnnotation(hd.nav(), htmlNav));
+                               
setHtmlAside(resolveNewlineSeparatedAnnotation(hd.aside(), htmlAside));
+                               
setHtmlFooter(resolveNewlineSeparatedAnnotation(hd.footer(), htmlFooter));
+                               
setHtmlStyle(resolveNewlineSeparatedAnnotation(hd.style(), htmlStyle));
+                               
setHtmlScript(resolveNewlineSeparatedAnnotation(hd.script(), htmlScript));
+                               setHtmlLinks(resolveLinks(hd.links(), 
htmlLinks));
+
+                               if (! hd.stylesheet().isEmpty())
+                                       setHtmlStylesheet(hd.stylesheet());
+                               if (! hd.noResultsMessage().isEmpty())
+                                       
setHtmlNoResultsMessage(hd.noResultsMessage());
+                               if (hd.nowrap())
+                                       setHtmlNoWrap(true);
+                               if (hd.template() != HtmlDocTemplate.class)
+                                       setHtmlTemplate(hd.template());
+                       }
+
+                       addResponseHandlers(
+                               StreamableHandler.class,
+                               WritableHandler.class,
+                               ReaderHandler.class,
+                               InputStreamHandler.class,
+                               RedirectHandler.class,
+                               DefaultHandler.class
+                       );
+
+               } catch (Exception e) {
+                       throw new ServletException(e);
+               }
+       }
+
+       /*
+        * Calls all @RestHook(INIT) methods on the specified resource object.
+        */
+       void init(Object resource) throws ServletException {
+               Map<String,Method> map = new LinkedHashMap<String,Method>();
+               for (Method m : ClassUtils.getAllMethods(this.resourceClass, 
true)) {
+                       if (m.isAnnotationPresent(RestHook.class) && 
m.getAnnotation(RestHook.class).value() == HookEvent.INIT) {
+                               Visibility.setAccessible(m);
+                               String sig = ClassUtils.getMethodSignature(m);
+                               if (! map.containsKey(sig))
+                                       map.put(sig, m);
+                       }
+               }
+               for (Method m : map.values()) {
+                       ClassUtils.assertArgsOfType(m, RestConfig.class, 
ServletConfig.class);
+                       Class<?>[] argTypes = m.getParameterTypes();
+                       Object[] args = new Object[argTypes.length];
+                       for (int i = 0; i < args.length; i++) {
+                               if (argTypes[i] == RestConfig.class)
+                                       args[i] = this;
+                               else
+                                       args[i] = this.inner;
+                       }
+                       try {
+                               m.invoke(resource, args);
+                       } catch (Exception e) {
+                               throw new RestServletException("Exception 
thrown from @RestHook(INIT) method {0}.", m).initCause(e);
+                       }
+               }
+       }
+
+       /**
+        * Adds the specified {@link Var} classes to this config.
+        *
+        * <p>
+        * These variables affect the variable resolver returned by {@link 
RestRequest#getVarResolverSession()} which is
+        * used to resolve string variables of the form <js>"$X{...}"</js>.
+        *
+        * <p>
+        * By default, this config includes the following variables:
+        * <ul>
+        *      <li>{@link SystemPropertiesVar}
+        *      <li>{@link EnvVariablesVar}
+        *      <li>{@link ConfigFileVar}
+        *      <li>{@link IfVar}
+        *      <li>{@link SwitchVar}
+        * </ul>
+        *
+        * <p>
+        * Later during the construction of {@link RestContext}, we add the 
following variables:
+        * <ul>
+        *      <li>{@link LocalizationVar}
+        *      <li>{@link RequestVar}
+        *      <li>{@link SerializedRequestAttrVar}
+        *      <li>{@link ServletInitParamVar}
+        *      <li>{@link UrlVar}
+        *      <li>{@link UrlEncodeVar}
+        *      <li>{@link WidgetVar}
+        * </ul>
+        *
+        * @param vars The {@link Var} classes to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addVars(Class<?>...vars) {
+               this.varResolverBuilder.vars(vars);
+               return this;
+       }
+
+       /**
+        * Adds a var context object to this config.
+        *
+        * <p>
+        * Var context objects are read-only objects associated with the 
variable resolver for vars that require external
+        * information.
+        *
+        * <p>
+        * For example, the {@link ConfigFileVar} needs access to this 
resource's {@link ConfigFile} through the
+        * {@link ConfigFileVar#SESSION_config} object that can be specified as 
either a session object (temporary) or
+        * context object (permanent).
+        * In this case, we call the following code to add it to the context 
map:
+        * <p class='bcode'>
+        *      config.addVarContextObject(<jsf>SESSION_config</jsf>, 
configFile);
+        * </p>
+        *
+        * @param name The context object key (i.e. the name that the Var class 
looks for).
+        * @param object The context object.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addVarContextObject(String name, Object object) {
+               this.varResolverBuilder.contextObject(name, object);
+               return this;
+       }
+
+       /**
+        * Overwrites the default config file with a custom config file.
+        *
+        * <p>
+        * By default, the config file is determined using the {@link 
RestResource#config() @RestResource.config()}
+        * annotation.
+        * This method allows you to programmatically override it with your own 
custom config file.
+        *
+        * @param configFile The new config file.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setConfigFile(ConfigFile configFile) {
+               this.configFile = configFile;
+               return this;
+       }
+
+       /**
+        * Sets a property on this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#properties()} annotation.
+        *
+        * @param key The property name.
+        * @param value The property value.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setProperty(String key, Object value) {
+               this.properties.put(key, value);
+               return this;
+       }
+
+       /**
+        * Sets multiple properties on this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#properties() @RestResource.properties()} annotation.
+        *
+        * <p>
+        * Values in the map are added to the existing properties and are 
overwritten if duplicates are found.
+        *
+        * @param properties The new properties to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setProperties(Map<String,Object> properties) {
+               this.properties.putAll(properties);
+               return this;
+       }
+
+       /**
+        * Adds class-level bean filters to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#beanFilters() @RestResource.beanFilters()}
+        * annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param beanFilters The bean filters to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addBeanFilters(Class<?>...beanFilters) {
+               this.beanFilters.addAll(Arrays.asList(beanFilters));
+               return this;
+       }
+
+       /**
+        * Adds class-level pojo swaps to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#pojoSwaps() @RestResource.pojoSwaps()} annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param pojoSwaps The pojo swaps to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addPojoSwaps(Class<?>...pojoSwaps) {
+               this.pojoSwaps.addAll(Arrays.asList(pojoSwaps));
+               return this;
+       }
+
+       /**
+        * Specifies the serializer listener class to use for listening to 
non-fatal serialization errors.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#serializerListener() 
@RestResource.serializerListener()} annotation.
+        *
+        * @param listener The listener to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig serializerListener(Class<? extends 
SerializerListener> listener) {
+               if (listener != SerializerListener.class)
+                       this.serializerListener = listener;
+               return this;
+       }
+
+       /**
+        * Specifies the parser listener class to use for listening to 
non-fatal parse errors.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#parserListener() @RestResource.parserListener()} 
annotation.
+        *
+        * @param listener The listener to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig parserListener(Class<? extends ParserListener> 
listener) {
+               if (listener != ParserListener.class)
+                       this.parserListener = listener;
+               return this;
+       }
+
+       /**
+        * Specifies the override context path for this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#contextPath() @RestResource.contextPath()} 
annotation.
+        *
+        * @param contextPath The context path for this resource and any child 
resources.
+        * @return This object (for method chaining).
+        */
+       public RestConfig contextPath(String contextPath) {
+               if (! contextPath.isEmpty())
+                       this.contextPath = contextPath;
+               return this;
+       }
+
+       /**
+        * Adds class-level parameter resolvers to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#paramResolvers() @RestResource.paramResolvers()} 
annotation.
+        *
+        * @param paramResolvers The parameter resolvers to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addParamResolvers(Class<? extends 
RestParam>...paramResolvers) {
+               this.paramResolvers.addAll(Arrays.asList(paramResolvers));
+               return this;
+       }
+
+       /**
+        * Adds class-level serializers to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#serializers() @RestResource.serializers()}
+        * annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param serializers The serializer classes to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addSerializers(Class<?>...serializers) {
+               this.serializers.append(serializers);
+               return this;
+       }
+
+       /**
+        * Adds class-level serializers to this resource.
+        *
+        * <p>
+        * Same as {@link #addSerializers(Class...)} except allows you to pass 
in serializer instances.
+        * The actual serializer ends up being the result of this operation 
using the bean filters, pojo swaps, and
+        * properties on this config:
+        * <p class='bcode'>
+        *      serializer = 
serializer.builder().beanFilters(beanFilters).pojoSwaps(pojoSwaps).properties(properties).build();
+        * </p>
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param serializers The serializers to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addSerializers(Serializer...serializers) {
+               this.serializers.append(serializers);
+               return this;
+       }
+
+       /**
+        * Adds class-level parsers to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#parsers() @RestResource.parsers()} annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param parsers The parser classes to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addParsers(Class<?>...parsers) {
+               this.parsers.append(parsers);
+               return this;
+       }
+
+       /**
+        * Adds class-level parsers to this resource.
+        *
+        * <p>
+        * Same as {@link #addParsers(Class...)} except allows you to pass in 
parser instances.
+        * The actual parser ends up being the result of this operation using 
the bean filters, pojo swaps, and properties
+        * on this config:
+        * <p class='bcode'>
+        *      parser = 
parser.builder().beanFilters(beanFilters).pojoSwaps(pojoSwaps).properties(properties).build();
+        * </p>
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param parsers The parsers to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addParsers(Parser...parsers) {
+               this.parsers.append(parsers);
+               return this;
+       }
+
+       /**
+        * Adds class-level encoders to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#encoders() @RestResource.encoders()} annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * <p>
+        * By default, only the {@link IdentityEncoder} is included in this 
list.
+        *
+        * @param encoders The parser classes to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addEncoders(Class<?>...encoders) {
+               this.encoders.append(encoders);
+               return this;
+       }
+
+       /**
+        * Adds class-level encoders to this resource.
+        *
+        * <p>
+        * Same as {@link #addEncoders(Class...)} except allows you to pass in 
encoder instances.
+        *
+        * @param encoders The encoders to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addEncoders(Encoder...encoders) {
+               this.encoders.append(encoders);
+               return this;
+       }
+
+       /**
+        * Adds class-level converters to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#converters() @RestResource.converters()}
+        * annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * <p>
+        * By default, this config includes the following converters:
+        * <ul>
+        *      <li>{@link StreamableHandler}
+        *      <li>{@link WritableHandler}
+        *      <li>{@link ReaderHandler}
+        *      <li>{@link InputStreamHandler}
+        *      <li>{@link RedirectHandler}
+        *      <li>{@link DefaultHandler}
+        * </ul>
+        *
+        * @param converters The converter classes to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addConverters(Class<?>...converters) {
+               this.converters.addAll(Arrays.asList(converters));
+               return this;
+       }
+
+       /**
+        * Adds class-level encoders to this resource.
+        *
+        * <p>
+        * Same as {@link #addConverters(Class...)} except allows you to pass 
in converter instances.
+        *
+        * @param converters The converters to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addConverters(RestConverter...converters) {
+               this.converters.addAll(Arrays.asList(converters));
+               return this;
+       }
+
+       /**
+        * Adds class-level guards to this resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#guards() @RestResource.guards()} annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param guards The guard classes to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addGuards(Class<?>...guards) {
+               this.guards.addAll(Arrays.asList(guards));
+               return this;
+       }
+
+       /**
+        * Adds class-level guards to this resource.
+        *
+        * <p>
+        * Same as {@link #addGuards(Class...)} except allows you to pass in 
guard instances.
+        *
+        * @param guards The guards to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addGuards(RestGuard...guards) {
+               this.guards.addAll(Arrays.asList(guards));
+               return this;
+       }
+
+       /**
+        * Adds MIME-type definitions.
+        *
+        * <p>
+        * These definitions are used in the following locations for setting 
the media type on responses:
+        * <ul>
+        *      <li>{@link RestRequest#getReaderResource(String)}
+        *      <li>Static files resolved through {@link 
RestResource#staticFiles()}
+        * </ul>
+        *
+        * <p>
+        * Refer to {@link MimetypesFileTypeMap#addMimeTypes(String)} for an 
explanation of the format.
+        *
+        * @param mimeTypes The MIME-types to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addMimeTypes(String...mimeTypes) {
+               if (this.mimeTypes == ExtendedMimetypesFileTypeMap.DEFAULT)
+                       this.mimeTypes = new ExtendedMimetypesFileTypeMap();
+               for (String mimeType : mimeTypes)
+                       this.mimeTypes.addMimeTypes(mimeType);
+               return this;
+       }
+
+       /**
+        * Adds class-level default HTTP request headers to this resource.
+        *
+        * <p>
+        * Default request headers are default values for when HTTP requests do 
not specify a header value.
+        * For example, you can specify a default value for <code>Accept</code> 
if a request does not specify that header
+        * value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#defaultRequestHeaders() 
@RestResource.defaultRequestHeaders()} annotation.
+        *
+        * @param name The HTTP header name.
+        * @param value The HTTP header value.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addDefaultRequestHeader(String name, Object value) {
+               this.defaultRequestHeaders.put(name, 
StringUtils.toString(value));
+               return this;
+       }
+
+       /**
+        * Adds class-level default HTTP request headers to this resource.
+        *
+        * <p>
+        * Default request headers are default values for when HTTP requests do 
not specify a header value.
+        * For example, you can specify a default value for <code>Accept</code> 
if a request does not specify that header
+        * value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#defaultRequestHeaders() 
@RestResource.defaultRequestHeaders()} annotation.
+        *
+        * @param headers HTTP headers of the form <js>"Name: Value"</js>.
+        * @return This object (for method chaining).
+        * @throws RestServletException If header string is not correctly 
formatted.
+        */
+       public RestConfig addDefaultRequestHeaders(String...headers) throws 
RestServletException {
+               for (String header : headers) {
+                       String[] h = RestUtils.parseHeader(header);
+                       if (h == null)
+                               throw new RestServletException("Invalid default 
request header specified: ''{0}''.  Must be in the format: ''Header-Name: 
header-value''", header);
+                       addDefaultRequestHeader(h[0], h[1]);
+               }
+               return this;
+       }
+
+       /**
+        * Adds class-level default HTTP response headers to this resource.
+        *
+        * <p>
+        * Default response headers are headers that will be appended to all 
responses if those headers have not already been
+        * set on the response object.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#defaultResponseHeaders() 
@RestResource.defaultResponseHeaders()} annotation.
+        *
+        * <p>
+        * Values are added AFTER those found in the annotation and therefore 
take precedence over those defined via the
+        * annotation.
+        *
+        * @param name The HTTP header name.
+        * @param value The HTTP header value.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addDefaultResponseHeader(String name, Object value) {
+               this.defaultResponseHeaders.put(name, value);
+               return this;
+       }
+
+       /**
+        * Adds class-level default HTTP response headers to this resource.
+        *
+        * <p>
+        * Default response headers are headers that will be appended to all 
responses if those headers have not already been
+        * set on the response object.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#defaultResponseHeaders() 
@RestResource.defaultResponseHeaders()} annotation.
+        *
+        * @param headers HTTP headers of the form <js>"Name: Value"</js>.
+        * @return This object (for method chaining).
+        * @throws RestServletException If header string is not correctly 
formatted.
+        */
+       public RestConfig addDefaultResponseHeaders(String...headers) throws 
RestServletException {
+               for (String header : headers) {
+                       String[] h = RestUtils.parseHeader(header);
+                       if (h == null)
+                               throw new RestServletException("Invalid default 
response header specified: ''{0}''.  Must be in the format: ''Header-Name: 
header-value''", header);
+                       addDefaultResponseHeader(h[0], h[1]);
+               }
+               return this;
+       }
+
+       /**
+        * Adds class-level response handler classes to this resource.
+        *
+        * <p>
+        * Response handlers are responsible for converting various POJOs 
returned by REST methods into actual HTTP responses.
+        *
+        * <p>
+        * By default, this config includes the following response handlers:
+        * <ul>
+        *      <li>{@link StreamableHandler}
+        *      <li>{@link WritableHandler}
+        *      <li>{@link ReaderHandler}
+        *      <li>{@link InputStreamHandler}
+        *      <li>{@link RedirectHandler}
+        *      <li>{@link DefaultHandler}
+        * </ul>
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#responseHandlers() 
@RestResource.responseHandlers()} annotation.
+        *
+        * @param responseHandlers The response handlers to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addResponseHandlers(Class<?>...responseHandlers) {
+               this.responseHandlers.addAll(Arrays.asList(responseHandlers));
+               return this;
+       }
+
+       /**
+        * Adds class-level response handlers to this resource.
+        *
+        * <p>
+        * Same as {@link #addResponseHandlers(Class...)} except allows you to 
pass in response handler instances.
+        *
+        * @param responseHandlers The response handlers to add to this config.
+        * @return This object (for method chaining).
+        */
+       public RestConfig 
addResponseHandlers(ResponseHandler...responseHandlers) {
+               this.responseHandlers.addAll(Arrays.asList(responseHandlers));
+               return this;
+       }
+
+       /**
+        * Adds a child resource to this resource.
+        *
+        * <p>
+        * Child resources are resources that are accessed under the path of 
the parent resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#children() @RestResource.children()} annotation.
+        *
+        * @param path The child path of the resource.  Must conform to {@link 
RestResource#path()} format.
+        * @param child The child resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addChildResource(String path, Object child) {
+               this.childResources.add(new Pair<String,Object>(path, child));
+               return this;
+       }
+
+       /**
+        * Add child resources to this resource.
+        *
+        * <p>
+        * Child resources are resources that are accessed under the path of 
the parent resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#children() @RestResource.children()} annotation.
+        *
+        * @param children The child resources to add to this resource.
+        * Children must be annotated with {@link RestResource#path()} to 
identify the child path.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addChildResources(Object...children) {
+               this.childResources.addAll(Arrays.asList(children));
+               return this;
+       }
+
+       /**
+        * Add child resources to this resource.
+        *
+        * <p>
+        * Child resources are resources that are accessed under the path of 
the parent resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#children() @RestResource.children()} annotation.
+        *
+        * @param children The child resources to add to this resource.
+        * Children must be annotated with {@link RestResource#path()} to 
identify the child path.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addChildResources(Class<?>...children) {
+               this.childResources.addAll(Arrays.asList(children));
+               return this;
+       }
+
+       /**
+        * Specifies the list of supported <code>Accept</code> media types for 
this resource.
+        *
+        * <p>
+        * This overrides the media types inferred from the parsers on this 
resource.
+        *
+        * <p>
+        * There is no annotation equivalent to this method call.
+        *
+        * @param mediaTypes The new list of media types supported by this 
resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setSupportedAcceptTypes(String...mediaTypes) {
+               supportedAcceptTypes = new ArrayList<MediaType>();
+               for (String mediaType : mediaTypes)
+                       
supportedAcceptTypes.add(MediaType.forString(mediaType));
+               return this;
+       }
+
+       /**
+        * Specifies the list of supported <code>Accept</code> media types for 
this resource.
+        *
+        * <p>
+        * This overrides the media types inferred from the parsers on this 
resource.
+        *
+        * <p>
+        * There is no annotation equivalent to this method call.
+        *
+        * @param mediaTypes The new list of media types supported by this 
resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setSupportedAcceptTypes(MediaType...mediaTypes) {
+               supportedAcceptTypes = Arrays.asList(mediaTypes);
+               return this;
+       }
+
+       /**
+        * Specifies the list of supported <code>Content-Type</code> media 
types for this resource.
+        *
+        * <p>
+        * This overrides the media types inferred from the serializers on this 
resource.
+        *
+        * <p>
+        * There is no annotation equivalent to this method call.
+        *
+        * @param mediaTypes The new list of media types supported by this 
resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setSupportedContentTypes(String...mediaTypes) {
+               supportedContentTypes = new ArrayList<MediaType>();
+               for (String mediaType : mediaTypes)
+                       
supportedContentTypes.add(MediaType.forString(mediaType));
+               return this;
+       }
+
+       /**
+        * Specifies the list of supported <code>Content-Type</code> media 
types for this resource.
+        *
+        * <p>
+        * This overrides the media types inferred from the serializers on this 
resource.
+        *
+        * <p>
+        * There is no annotation equivalent to this method call.
+        *
+        * @param mediaTypes The new list of media types supported by this 
resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setSupportedContentTypes(MediaType...mediaTypes) {
+               supportedContentTypes = Arrays.asList(mediaTypes);
+               return this;
+       }
+
+       /**
+        * Specifies the icon contents that make up the contents of the page 
<js>"/resource-path/favicon.ico"</js>.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#favicon() @RestResource.favicon()} annotation.
+        *
+        * <p>
+        * The object type can be any of the following:
+        * <ul>
+        *      <li>{@link InputStream}
+        *      <li>{@link File}
+        *      <li><code><jk>byte</jk>[]</code>
+        * </ul>
+        *
+        * @param favIcon The contents that make up the 
<code>favicon.ico</code> page.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setFavIcon(Object favIcon) {
+               this.favIcon = favIcon;
+               return this;
+       }
+
+       /**
+        * Specifies the icon contents that make up the contents of the page 
<js>"/resource-path/favicon.ico"</js>.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#favicon() @RestResource.favicon()} annotation.
+        *
+        * <p>
+        * Use this method to specify a resource located in the classpath.
+        * This call uses the {@link Class#getResourceAsStream(String)} method 
to retrieve the stylesheet contents.
+        *
+        * @param resourceClass The resource class used to resolve the resource 
stream.
+        * @param resourcePath
+        *      The path passed to the {@link 
Class#getResourceAsStream(String)} method.
+        *      Can also be a path starting with <js>"file://"</js> denoting a 
location to pull from the file system.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setFavIcon(Class<?> resourceClass, String 
resourcePath) {
+               this.favIcon = new Pair<Class<?>,String>(resourceClass, 
resourcePath);
+               return this;
+       }
+
+       /**
+        * Appends to the static files resource map.
+        *
+        * <p>
+        * Use this method to specify resources located in the classpath to be 
served up as static files.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#staticFiles() @RestResource.staticFiles()}
+        * annotation.
+        *
+        * @param resourceClass The resource class used to resolve the resource 
streams.
+        * @param staticFilesString
+        *      A JSON string denoting a map of child URLs to classpath 
subdirectories.
+        *      For example, if this string is <js>"{htdocs:'docs'}"</js> with 
class <code>com.foo.MyResource</code>,
+        *      then URLs of the form <js>"/resource-path/htdocs/..."</js> will 
resolve to files located in the
+        *      <code>com.foo.docs</code> package.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addStaticFiles(Class<?> resourceClass, String 
staticFilesString) {
+               if (staticFiles == null)
+                       staticFiles = new ArrayList<Object>();
+               staticFiles.add(new Pair<Class<?>,Object>(resourceClass, 
staticFilesString));
+               return this;
+       }
+
+       /**
+        * Overrides the default REST resource resolver.
+        *
+        * <p>
+        * The resource resolver is used to resolve instances from {@link 
Class} objects defined in the
+        * {@link RestResource#children()} annotation.
+        * The default value is {@link RestResourceResolverSimple}.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#resourceResolver() 
@RestResource.resourceResolver()} annotation.
+        *
+        * @param resourceResolver The new resource resolver.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setResourceResolver(Class<? extends 
RestResourceResolver> resourceResolver) {
+               this.resourceResolver = resourceResolver;
+               return this;
+       }
+
+       /**
+        * Overrides the default REST resource resolver.
+        *
+        * <p>
+        * Same as {@link #setResourceResolver(Class)} except allows you to 
specify an instance instead of a class.
+        *
+        * @param resourceResolver The new resource resolver.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setResourceResolver(RestResourceResolver 
resourceResolver) {
+               this.resourceResolver = resourceResolver;
+               return this;
+       }
+
+       /**
+        * Sets the URL path of the resource <js>"/foobar"</js>.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#path() @RestResource.path()} annotation.
+        *
+        * @param path The URL path of this resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setPath(String path) {
+               if (startsWith(path, '/'))
+                       path = path.substring(1);
+               this.path = path;
+               return this;
+       }
+
+       /**
+        * Sets name of the header used to denote the client version on HTTP 
requests.
+        *
+        * <p>
+        * This is the programmatic equivalent to the
+        * {@link RestResource#clientVersionHeader() 
@RestResource.clientVersionHeader()} annotation.
+        *
+        * @param clientVersionHeader The name of the HTTP header that denotes 
the client version.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setClientVersionHeader(String clientVersionHeader) {
+               this.clientVersionHeader = clientVersionHeader;
+               return this;
+       }
+
+       /**
+        * Sets the HTML header section contents.
+        *
+        * <p>
+        * The format of this value is HTML.
+        *
+        * <p>
+        * The page header normally contains the title and description, but 
this value can be used to override the contents
+        * to be whatever you want.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no header.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#header() 
@HtmlDoc.header()} annotation.
+        *
+        * @param value The HTML header section contents.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlHeader(String value) {
+               this.htmlHeader = value;
+               return this;
+       }
+
+       /**
+        * Sets the links in the HTML nav section.
+        *
+        * <p>
+        * The format of this value is a lax-JSON map of key/value pairs where 
the keys are the link text and the values are
+        * relative (to the servlet) or absolute URLs.
+        *
+        * <p>
+        * The page links are positioned immediately under the title and text.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no value.
+        *
+        * <p>
+        * This field can also use URIs of any support type in {@link 
UriResolver}.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#links() 
@HtmlDoc.links()} annotation.
+        *
+        * @param value The HTML nav section links links.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlLinks(String[] value) {
+               this.htmlLinks = value;
+               return this;
+       }
+
+       /**
+        * Sets the HTML nav section contents.
+        *
+        * <p>
+        * The format of this value is HTML.
+        *
+        * <p>
+        * The nav section of the page contains the links.
+        *
+        * <p>
+        * The format of this value is HTML.
+        *
+        * <p>
+        * When a value is specified, the {@link #setHtmlLinks(String[])} value 
will be ignored.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#nav() 
@HtmlDoc.nav()} annotation.
+        *
+        * @param value The HTML nav section contents.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlNav(String value) {
+               this.htmlNav = value;
+               return this;
+       }
+
+       /**
+        * Sets the HTML aside section contents.
+        *
+        * <p>
+        * The format of this value is HTML.
+        *
+        * <p>
+        * The aside section typically floats on the right side of the page.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#aside() 
@HtmlDoc.aside()} annotation.
+        *
+        * @param value The HTML aside section contents.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlAside(String value) {
+               this.htmlAside = value;
+               return this;
+       }
+
+       /**
+        * Sets the HTML footer section contents.
+        *
+        * <p>
+        * The format of this value is HTML.
+        *
+        * <p>
+        * The footer section typically floats on the bottom of the page.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#footer() 
@HtmlDoc.footer()} annotation.
+        *
+        * @param value The HTML footer section contents.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlFooter(String value) {
+               this.htmlFooter = value;
+               return this;
+       }
+
+       /**
+        * Sets the HTML CSS style section contents.
+        *
+        * <p>
+        * The format of this value is CSS.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#style() 
@HtmlDoc.style()} annotation.
+        *
+        * @param value The HTML CSS style section contents.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlStyle(String value) {
+               this.htmlStyle = value;
+               return this;
+       }
+
+       /**
+        * Sets the CSS URL in the HTML CSS style section.
+        *
+        * <p>
+        * The format of this value is a URL.
+        *
+        * <p>
+        * Specifies the URL to the stylesheet to add as a link in the style 
tag in the header.
+        *
+        * <p>
+        * The format of this value is CSS.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>) and can use URL protocols defined
+        * by {@link UriResolver}.
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
HtmlDoc#stylesheet() @HtmlDoc.stylesheet()} annotation.
+        *
+        * @param value The CSS URL in the HTML CSS style section.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlStylesheet(String value) {
+               this.htmlStylesheet = value;
+               return this;
+       }
+
+       /**
+        * Sets the HTML script section contents.
+        *
+        * <p>
+        * The format of this value is Javascript.
+        *
+        * <p>
+        * This field can contain variables (e.g. 
<js>"$L{my.localized.variable}"</js>).
+        * <br>See {@link RestContext#getVarResolver()} for the list of 
supported variables.
+        *
+        * <p>
+        * A value of <js>"NONE"</js> can be used to force no value.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#script() 
@HtmlDoc.script()} annotation.
+        *
+        * @param value The HTML script section contents.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlScript(String value) {
+               this.htmlScript = value;
+               return this;
+       }
+
+       /**
+        * Shorthand method for forcing the rendered HTML content to be no-wrap.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#nowrap() 
@HtmlDoc.nowrap()} annotation.
+        *
+        * @param value The new nowrap setting.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlNoWrap(boolean value) {
+               this.htmlNoWrap = value;
+               return this;
+       }
+
+       /**
+        * Specifies the text to display when serializing an empty array or 
collection.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
HtmlDoc#noResultsMessage() @HtmlDoc.noResultsMessage()}
+        * annotation.
+        *
+        * @param value The text to display when serializing an empty array or 
collection.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlNoResultsMessage(String value) {
+               this.htmlNoResultsMessage = value;
+               return this;
+       }
+
+       /**
+        * Specifies the template class to use for rendering the HTML page.
+        *
+        * <p>
+        * By default, uses {@link HtmlDocTemplateBasic} to render the 
contents, although you can provide your own custom
+        * renderer or subclasses from the basic class to have full control 
over how the page is rendered.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#template() 
@HtmlDoc.template()} annotation.
+        *
+        * @param value The HTML page template to use to render the HTML page.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlTemplate(Class<? extends HtmlDocTemplate> 
value) {
+               this.htmlTemplate = value;
+               return this;
+       }
+
+       /**
+        * Specifies the template class to use for rendering the HTML page.
+        *
+        * <p>
+        * By default, uses {@link HtmlDocTemplateBasic} to render the 
contents, although you can provide your own custom
+        * renderer or subclasses from the basic class to have full control 
over how the page is rendered.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link HtmlDoc#template() 
@HtmlDoc.template()} annotation.
+        *
+        * @param value The HTML page template to use to render the HTML page.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setHtmlTemplate(HtmlDocTemplate value) {
+               this.htmlTemplate = value;
+               return this;
+       }
+
+       /**
+        * Defines widgets that can be used in conjunction with string 
variables of the form <js>"$W{name}"</js>to quickly
+        * generate arbitrary replacement text.
+        *
+        * <p>
+        * Widgets are inherited from parent to child, but can be overridden by 
reusing the widget name.
+        *
+        * @param value The widget class to add.
+        * @return This object (for method chaining).
+        */
+       public RestConfig addHtmlWidget(Class<? extends Widget> value) {
+               this.htmlWidgets.add(value);
+               return this;
+       }
+
+       /**
+        * Overrides the logger for the resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#logger() @RestResource.logger()} annotation.
+        *
+        * @param logger The new logger for this resource.  Can be 
<jk>null</jk> to disable logging.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setLogger(Class<? extends RestLogger> logger) {
+               this.logger = logger;
+               return this;
+       }
+
+       /**
+        * Overrides the logger for the resource.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#logger() @RestResource.logger()} annotation.
+        *
+        * @param logger The new logger for this resource.  Can be 
<jk>null</jk> to disable logging.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setLogger(RestLogger logger) {
+               this.logger = logger;
+               return this;
+       }
+
+       /**
+        * Overrides the call handler for the resource.
+        *
+        * <p>
+        * The call handler is the object that handles execution of REST HTTP 
calls.
+        * Subclasses can be created that customize the behavior of how REST 
calls are handled.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#callHandler() @RestResource.callHandler()}
+        * annotation.
+        *
+        * @param restHandler The new call handler for this resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setCallHandler(Class<? extends RestCallHandler> 
restHandler) {
+               this.callHandler = restHandler;
+               return this;
+       }
+
+       /**
+        * Overrides the call handler for the resource.
+        *
+        * <p>
+        * The call handler is the object that handles execution of REST HTTP 
calls.
+        * Subclasses can be created that customize the behavior of how REST 
calls are handled.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#callHandler() @RestResource.callHandler()}
+        * annotation.
+        *
+        * @param restHandler The new call handler for this resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setCallHandler(RestCallHandler restHandler) {
+               this.callHandler = restHandler;
+               return this;
+       }
+
+       /**
+        * Overrides the info provider for the resource.
+        *
+        * <p>
+        * The info provider provides all the various information about a 
resource such as the Swagger documentation.
+        * Subclasses can be created that customize the information.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#infoProvider() @RestResource.infoProvider()}
+        * annotation.
+        *
+        * @param infoProvider The new info provider for this resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setInfoProvider(Class<? extends RestInfoProvider> 
infoProvider) {
+               this.infoProvider = infoProvider;
+               return this;
+       }
+
+       /**
+        * Overrides the info provider for the resource.
+        *
+        * <p>
+        * The info provider provides all the various information about a 
resource such as the Swagger documentation.
+        * Subclasses can be created that customize the information.
+        *
+        * <p>
+        * This is the programmatic equivalent to the {@link 
RestResource#infoProvider() @RestResource.infoProvider()}
+        * annotation.
+        *
+        * @param infoProvider The new info provider for this resource.
+        * @return This object (for method chaining).
+        */
+       public RestConfig setInfoProvider(RestInfoProvider infoProvider) {
+               this.infoProvider = infoProvider;
+               return this;
+       }
+
+       /**
+        * Creates a new {@link PropertyStore} object initialized with the 
properties defined in this config.
+        *
+        * @return A new property store.
+        */
+       protected PropertyStore createPropertyStore() {
+               return PropertyStore.create().addProperties(properties);
+       }
+
+
+       
//----------------------------------------------------------------------------------------------------
+       // Methods that give access to the config file, var resolver, and 
properties.
+       
//----------------------------------------------------------------------------------------------------
+
+       /**
+        * Returns the external configuration file for this resource.
+        *
+        * <p>
+        * The configuration file location is determined via the {@link 
RestResource#config() @RestResource.config()}
+        * annotation on the resource.
+        *
+        * <p>
+        * The config file can be programmatically overridden by adding the 
following method to your resource:
+        * <p class='bcode'>
+        *      <jk>public</jk> ConfigFile createConfigFile(ServletConfig 
servletConfig) <jk>throws</jk> ServletException;
+        * </p>
+        *
+        * <p>
+        * If a config file is not set up, then an empty config file will be 
returned that is not backed by any file.
+        *
+        * @return The external config file for this resource.  Never 
<jk>null</jk>.
+        */
+       public ConfigFile getConfigFile() {
+               return configFile;
+       }
+
+       /**
+        * Returns the configuration properties for this resource.
+        *
+        * <p>
+        * The configuration properties are determined via the {@link 
RestResource#properties()} annotation on the resource.
+        *
+        * <p>
+        * The configuration properties can be augmented programmatically by 
adding the following method to your resource:
+        * <p class='bcode'>
+        *      <jk>public</jk> ObjectMap createProperties(ServletConfig 
servletConfig) <jk>throws</jk> ServletException;
+        * </p>
+        *
+        * <p>
+        * These properties can be modified during servlet initialization.
+        * However, any modifications made after {@link 
RestServlet#init(ServletConfig)} has been called will have no effect.
+        *
+        * @return The configuration properties for this resource.  Never 
<jk>null</jk>.
+        */
+       public ObjectMap getProperties() {
+               return properties;
+       }
+
+       /**
+        * Creates the variable resolver for this resource.
+        *
+        * <p>
+        * The variable resolver returned by this method can resolve the 
following variables:
+        * <ul>
+        *      <li>{@link SystemPropertiesVar}
+        *      <li>{@link EnvVariablesVar}
+        *      <li>{@link ConfigFileVar}
+        *      <li>{@link IfVar}
+        *      <li>{@link SwitchVar}
+        * </ul>
+        *
+        * <p>
+        * Note that the variables supported here are only a subset of those 
returned by
+        * {@link RestRequest#getVarResolverSession()}.
+        *
+        * @return The variable resolver for this resource.  Never 
<jk>null</jk>.
+        */
+       public VarResolverBuilder getVarResolverBuilder() {
+               return varResolverBuilder;
+       }
+
+
+       
//----------------------------------------------------------------------------------------------------
+       // Methods inherited from ServletConfig
+       
//----------------------------------------------------------------------------------------------------
+
+       @Override /* ServletConfig */
+       public String getInitParameter(String name) {
+               return inner.getInitParameter(name);
+       }
+
+       @Override /* ServletConfig */
+       public Enumeration<String> getInitParameterNames() {
+               return inner.getInitParameterNames();
+       }
+
+       @Override /* ServletConfig */
+       public ServletContext getServletContext() {
+               return inner.getServletContext();
+       }
+
+       @Override /* ServletConfig */
+       public String getServletName() {
+               return inner.getServletName();
+       }
+}

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


Reply via email to