http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
new file mode 100644
index 0000000..2b55b47
--- /dev/null
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
@@ -0,0 +1,233 @@
+// 
***************************************************************************************************************************
+// * 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 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>
+        * <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.
+        *
+        * @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) {
+               String q = req.getQueryString();
+               return (q == null ? true : q.indexOf("noTrace=true") == -1);
+       }
+
+       /**
+        * 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:
+        * </p>
+        * <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;
+       }
+
+       /**
+        * NO-OP logger.
+        * <p>
+        * Disables all logging.
+        *
+        * @author James Bognar ([email protected])
+        */
+       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) {
+                       if (args.length > 0)
+                               msg = MessageFormat.format(msg, args);
+                       getLogger().log(level, msg, cause);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
index 4a2619d..2a1cc16 100644
--- 
a/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
+++ 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest;
 import java.lang.reflect.*;
 
 /**
- * Subclass of {@link RestMatcher} that gives access to the servlet and Java 
method it's applied to.
+ * 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
@@ -26,8 +26,8 @@ public abstract class RestMatcherReflecting extends 
RestMatcher {
        /**
         * Constructor.
         *
-        * @param servlet The REST servlet.
+        * @param resource The REST servlet.
         * @param javaMethod The Java method that this rest matcher is defined 
on.
         */
-       protected RestMatcherReflecting(RestServlet servlet, Method javaMethod) 
{}
+       protected RestMatcherReflecting(Object resource, Method javaMethod) {}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
index cc60feb..98aba93 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -19,6 +19,7 @@ import static javax.servlet.http.HttpServletResponse.*;
 import java.io.*;
 import java.lang.reflect.*;
 import java.net.*;
+import java.nio.charset.*;
 import java.text.*;
 import java.util.*;
 import java.util.logging.*;
@@ -63,13 +64,15 @@ import org.apache.juneau.utils.*;
 @SuppressWarnings("unchecked")
 public final class RestRequest extends HttpServletRequestWrapper {
 
-       private final RestServlet servlet;
+       private final RestContext context;
+
        private final String method;
        private String pathRemainder, body;
        private Method javaMethod;
        private ObjectMap properties;
        private SerializerGroup serializerGroup;
        private ParserGroup parserGroup;
+       private EncoderGroup encoders;
        private Encoder encoder;
        private int contentLength;
        private final boolean debug;
@@ -89,17 +92,17 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        /**
         * Constructor.
         */
-       RestRequest(RestServlet servlet, HttpServletRequest req) throws 
ServletException {
+       RestRequest(RestContext context, HttpServletRequest req) throws 
ServletException {
                super(req);
+               this.context = context;
 
                try {
-                       this.servlet = servlet;
                        isPost = req.getMethod().equalsIgnoreCase("POST");
 
                        // If this is a POST, we want to parse the query 
parameters ourselves to prevent
                        // the servlet code from processing the HTTP body as 
URL-Encoded parameters.
                        if (isPost)
-                               queryParams = 
servlet.getUrlEncodingParser().parseIntoSimpleMap(getQueryString());
+                               queryParams = 
context.getUrlEncodingParser().parseIntoSimpleMap(getQueryString());
                        else {
                                queryParams = req.getParameterMap();
                        }
@@ -109,23 +112,23 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                        String _method = super.getMethod();
 
                        String m = getQueryParameter("method");
-                       if (! StringUtils.isEmpty(m) && 
(servlet.context.allowMethodParams.contains(m) || 
servlet.context.allowMethodParams.contains("*")))
+                       if (context.allowMethodParam(m))
                                _method = m;
 
                        method = _method;
 
-                       if (servlet.context.allowBodyParam) {
+                       if (context.isAllowBodyParam()) {
                                body = getQueryParameter("body");
                                if (body != null)
                                        setHeader("Content-Type", 
UonSerializer.DEFAULT.getResponseContentType());
                        }
 
-                       defaultServletHeaders = 
servlet.getDefaultRequestHeaders();
+                       defaultServletHeaders = 
context.getDefaultRequestHeaders();
 
                        debug = "true".equals(getQueryParameter("debug", 
"false"));
 
                        if (debug) {
-                               servlet.log(Level.INFO, toString());
+                               context.getLogger().log(Level.INFO, toString());
                        }
 
                } catch (RestException e) {
@@ -139,7 +142,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         * Called from RestServlet after a match has been made but before the 
guard or method invocation.
         */
        @SuppressWarnings("hiding")
-       final void init(Method javaMethod, String pathRemainder, ObjectMap 
properties, Map<String,String> mDefaultRequestHeaders, String defaultCharset, 
SerializerGroup mSerializers, ParserGroup mParsers, UrlEncodingParser 
mUrlEncodingParser) {
+       final void init(Method javaMethod, String pathRemainder, ObjectMap 
properties, Map<String,String> mDefaultRequestHeaders, String defaultCharset, 
SerializerGroup mSerializers, ParserGroup mParsers, UrlEncodingParser 
mUrlEncodingParser, EncoderGroup encoders) {
                this.javaMethod = javaMethod;
                this.pathRemainder = pathRemainder;
                this.properties = properties;
@@ -149,6 +152,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                this.urlEncodingParser = mUrlEncodingParser;
                this.beanSession = 
urlEncodingParser.getBeanContext().createSession();
                this.defaultCharset = defaultCharset;
+               this.encoders = encoders;
        }
 
        /**
@@ -403,7 +407,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                        }
                        if (charset == null)
                                charset = defaultCharset;
-                       if (! 
RestServlet.availableCharsets.containsKey(charset))
+                       if (! Charset.isSupported(charset))
                                throw new 
RestException(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported charset in header 
''Content-Type'': ''{0}''", h);
                }
                return charset;
@@ -1299,11 +1303,11 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                                        properties.append("mediaType", 
mediaType).append("characterEncoding", getCharacterEncoding());
                                        if (! p.isReaderParser()) {
                                                InputStreamParser p2 = 
(InputStreamParser)p;
-                                               ParserSession session = 
p2.createSession(getInputStream(), properties, getJavaMethod(), getServlet(), 
locale, timeZone, mediaType);
+                                               ParserSession session = 
p2.createSession(getInputStream(), properties, getJavaMethod(), 
context.getResource(), locale, timeZone, mediaType);
                                                return p2.parseSession(session, 
cm);
                                        }
                                        ReaderParser p2 = (ReaderParser)p;
-                                       ParserSession session = 
p2.createSession(getUnbufferedReader(), properties, getJavaMethod(), 
getServlet(), locale, timeZone, mediaType);
+                                       ParserSession session = 
p2.createSession(getUnbufferedReader(), properties, getJavaMethod(), 
context.getResource(), locale, timeZone, mediaType);
                                        return p2.parseSession(session, cm);
                                } catch (ParseException e) {
                                        throw new RestException(SC_BAD_REQUEST,
@@ -1576,45 +1580,45 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        /**
         * Returns the localized servlet title.
         * <p>
-        * Equivalent to calling {@link RestServlet#getTitle(RestRequest)} with 
this object.
+        * Equivalent to calling {@link RestInfoProvider#getTitle(RestRequest)} 
with this object.
         *
         * @return The localized servlet label.
         */
        public String getServletTitle() {
-               return servlet.getTitle(this);
+               return context.getInfoProvider().getTitle(this);
        }
 
        /**
         * Returns the localized servlet description.
         * <p>
-        * Equivalent to calling {@link 
RestServlet#getDescription(RestRequest)} with this object.
+        * Equivalent to calling {@link 
RestInfoProvider#getDescription(RestRequest)} with this object.
         *
         * @return The localized servlet description.
         */
        public String getServletDescription() {
-               return servlet.getDescription(this);
+               return context.getInfoProvider().getDescription(this);
        }
 
        /**
         * Returns the localized method summary.
         * <p>
-        * Equivalent to calling {@link RestServlet#getMethodSummary(String, 
RestRequest)} with this object.
+        * Equivalent to calling {@link 
RestInfoProvider#getMethodSummary(String, RestRequest)} with this object.
         *
         * @return The localized method description.
         */
        public String getMethodSummary() {
-               return servlet.getMethodSummary(javaMethod.getName(), this);
+               return 
context.getInfoProvider().getMethodSummary(javaMethod.getName(), this);
        }
 
        /**
         * Returns the localized method description.
         * <p>
-        * Equivalent to calling {@link 
RestServlet#getMethodDescription(String, RestRequest)} with this object.
+        * Equivalent to calling {@link 
RestInfoProvider#getMethodDescription(String, RestRequest)} with this object.
         *
         * @return The localized method description.
         */
        public String getMethodDescription() {
-               return servlet.getMethodDescription(javaMethod.getName(), this);
+               return 
context.getInfoProvider().getMethodDescription(javaMethod.getName(), this);
        }
 
 
@@ -1713,14 +1717,14 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        }
 
        /**
-        * Shortcut method for calling {@link RestServlet#getMessage(Locale, 
String, Object...)} based on the request locale.
+        * Shortcut method for calling {@link MessageBundle#getString(Locale, 
String, Object...)} based on the request locale.
         *
         * @param key The message key.
         * @param args Optional {@link MessageFormat}-style arguments.
         * @return The localized message.
         */
        public String getMessage(String key, Object...args) {
-               return servlet.getMessage(getLocale(), key, args);
+               return context.getMessages().getString(getLocale(), key, args);
        }
 
        /**
@@ -1729,7 +1733,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         * @return The resource bundle.  Never <jk>null</jk>.
         */
        public MessageBundle getResourceBundle() {
-               return servlet.getMessages(getLocale());
+               return context.getMessages().getBundle(getLocale());
        }
 
        /**
@@ -1740,8 +1744,8 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         *
         * @return The servlet handling the request.
         */
-       public RestServlet getServlet() {
-               return servlet;
+       public RestContext getContext() {
+               return context;
        }
 
        /**
@@ -1772,13 +1776,13 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        }
 
        /**
-        * Returns the variable resolver session for this request using session 
objects created by {@link RestServlet#getSessionObjects(RestRequest)}.
+        * Returns the variable resolver session for this request using session 
objects created by {@link RestCallHandler#getSessionObjects(RestRequest)}.
         *
         * @return The variable resolver for this request.
         */
        public VarResolverSession getVarResolverSession() {
                if (varSession == null)
-                       varSession = 
servlet.getVarResolver().createSession(servlet.getSessionObjects(this));
+                       varSession = 
context.getVarResolver().createSession(context.getCallHandler().getSessionObjects(this));
                return varSession;
        }
 
@@ -1803,7 +1807,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         * @throws IOException
         */
        public ReaderResource getReaderResource(String name, boolean 
resolveVars, MediaType mediaType) throws IOException {
-               String s = servlet.getResourceAsString(name, getLocale());
+               String s = context.getResourceAsString(name, getLocale());
                if (s == null)
                        return null;
                ReaderResource.Builder b = new 
ReaderResource.Builder().mediaType(mediaType).contents(s);
@@ -1813,8 +1817,8 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        }
 
        /**
-        * Same as {@link #getReaderResource(String, boolean, MediaType)} 
except uses {@link RestServlet#getMimetypesFileTypeMap()}
-        * to determine the media type.
+        * Same as {@link #getReaderResource(String, boolean, MediaType)} 
except uses the resource mime-type map
+        * constructed using {@link RestConfig#addMimeTypes(String...)} to 
determine the media type.
         *
         * @param name The name of the resource (i.e. the value normally passed 
to {@link Class#getResourceAsStream(String)}.
         * @param resolveVars If <jk>true</jk>, any {@link 
org.apache.juneau.rest.annotation.Parameter} variables will be resolved by the 
variable resolver returned
@@ -1823,7 +1827,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         * @throws IOException
         */
        public ReaderResource getReaderResource(String name, boolean 
resolveVars) throws IOException {
-               return getReaderResource(name, resolveVars, 
MediaType.forString(servlet.getMimetypesFileTypeMap().getContentType(name)));
+               return getReaderResource(name, resolveVars, 
MediaType.forString(context.getMediaTypeForName(name)));
        }
 
        /**
@@ -1834,7 +1838,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         * @throws IOException
         */
        public ReaderResource getReaderResource(String name) throws IOException 
{
-               return getReaderResource(name, false, 
MediaType.forString(servlet.getMimetypesFileTypeMap().getContentType(name)));
+               return getReaderResource(name, false, 
MediaType.forString(context.getMediaTypeForName(name)));
        }
 
        /**
@@ -1842,9 +1846,9 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         *
         * @return The config file associated with the servlet, or 
<jk>null</jk> if servlet does not have a config file associated with it.
         */
-       public ConfigFile getConfig() {
+       public ConfigFile getConfigFile() {
                if (cf == null)
-                       cf = 
servlet.getConfig().getResolving(getVarResolverSession());
+                       cf = 
context.getConfigFile().getResolving(getVarResolverSession());
                return cf;
        }
 
@@ -1855,7 +1859,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         */
        public Swagger getSwagger() {
                if (swagger == null)
-                       swagger = servlet.getSwagger(this);
+                       swagger = context.getInfoProvider().getSwagger(this);
                return swagger;
        }
 
@@ -1871,7 +1875,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         */
        protected Swagger getSwaggerFromFile() {
                if (fileSwagger == null)
-                       fileSwagger = 
servlet.getSwaggerFromFile(this.getLocale());
+                       fileSwagger = 
context.getInfoProvider().getSwaggerFromFile(this.getLocale());
                if (fileSwagger == null)
                        fileSwagger = Swagger.NULL;
                return fileSwagger == Swagger.NULL ? null : fileSwagger;
@@ -1895,7 +1899,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                                sb.append(getBodyAsString()).append("\n");
                        } catch (Exception e1) {
                                sb.append(e1.getLocalizedMessage());
-                               servlet.log(WARNING, e1, "Error occurred while 
trying to read debug input.");
+                               context.getLogger().log(WARNING, e1, "Error 
occurred while trying to read debug input.");
                        }
                }
                return sb.toString();
@@ -1942,11 +1946,11 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                        String ce = getHeader("content-encoding");
                        if (! (ce == null || ce.isEmpty())) {
                                ce = ce.trim();
-                               encoder = servlet.getEncoders().getEncoder(ce);
+                               encoder = encoders.getEncoder(ce);
                                if (encoder == null)
                                        throw new 
RestException(SC_UNSUPPORTED_MEDIA_TYPE,
                                                "Unsupported encoding in 
request header ''Content-Encoding'': ''{0}''\n\tSupported codings: {1}",
-                                               getHeader("content-encoding"), 
servlet.getEncoders().getSupportedEncodings()
+                                               getHeader("content-encoding"), 
encoders.getSupportedEncodings()
                                        );
                        }
 
@@ -1966,7 +1970,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         */
        private String getOverriddenHeader(String name) {
                String h = null;
-               if (servlet.context.allowHeaderParams)
+               if (context.isAllowHeaderParams())
                        h = getQueryParameter(name);
                if (h != null)
                        return h;

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
new file mode 100644
index 0000000..7989eb9
--- /dev/null
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
@@ -0,0 +1,80 @@
+// 
***************************************************************************************************************************
+// * 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.internal.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Class used to resolve {@link Class} objects to instances.
+ * <p>
+ * Used to convert classes defined via {@link RestResource#children() 
@RestResource.children()} into child instances.
+ * <p>
+ * Subclasses can be created to provide customized resource resolution.
+ * These can be associated with REST resources in one of the following ways:
+ * <ul>
+ *     <li>{@link RestResource#resourceResolver() 
@RestResource.resourceResolver()} annotation.
+ *     <li>{@link RestConfig#setResourceResolver(Class)}/{@link 
RestConfig#setResourceResolver(RestResourceResolver)} methods.
+ * </ul>
+ * <p>
+ * The default implementation simply instantiates the class using one of the 
following constructors:
+ * <ul>
+ *     <li><code><jk>public</jk> T(RestConfig)</code>
+ *     <li><code><jk>public</jk> T()</code>
+ * </ul>
+ * The former constructor can be used to get access to the {@link RestConfig} 
object to get access to the
+ * config file and initialization information or make programmatic 
modifications to the resource before
+ * full initialization.
+ * <p>
+ * Non-<code>RestServlet</code> classes can also add the following two methods 
to get access to the
+ * {@link RestConfig} and {@link RestContext} objects:
+ * <ul>
+ *     <li><jk>public void</jk> init(RestConfig);</code>
+ *     <li><jk>public void</jk> init(RestContext);</code>
+ * </ul>
+ */
+public class RestResourceResolver {
+
+       /**
+        * Denotes the default resolver.
+        */
+       public static final class DEFAULT extends RestResourceResolver {}
+
+       /**
+        * Resolves the specified class to a resource object.
+        * <p>
+        * Subclasses can override this method to provide their own custom 
resolution.
+        * <p>
+        * The default implementation simply creates a new class instance using 
{@link Class#newInstance()}.
+        *
+        * @param c The class to resolve.
+        * @param config The initialization configuration for the resource.
+        * @return The instance of that class.
+        * @throws RestServletException If class could not be resolved.
+        */
+       public Object resolve(Class<?> c, RestConfig config) throws 
RestServletException {
+               try {
+                       Constructor<?> c1 = ClassUtils.findPublicConstructor(c, 
RestConfig.class);
+                       if (c1 != null)
+                               return c1.newInstance(config);
+                       c1 = ClassUtils.findPublicConstructor(c);
+                       if (c1 != null)
+                               return c1.newInstance();
+               } catch (Exception e) {
+                       throw new RestServletException("Could not instantiate 
resource class ''{0}''", c.getName()).initCause(e);
+               }
+               throw new RestServletException("Could not find public 
constructor for class ''{0}''.", c);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
index 3fa5398..637dc7e 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.rest;
 
 import java.io.*;
+import java.nio.charset.*;
 import java.util.*;
 
 import javax.servlet.*;
@@ -55,24 +56,22 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
        SerializerGroup serializerGroup;
        UrlEncodingSerializer urlEncodingSerializer;         // The serializer 
used to convert arguments passed into Redirect objects.
        private EncoderGroup encoders;
-       private final RestServlet servlet;
        private ServletOutputStream os;
 
        /**
         * Constructor.
         */
-       RestResponse(RestServlet servlet, RestRequest req, HttpServletResponse 
res) {
+       RestResponse(RestContext context, RestRequest req, HttpServletResponse 
res) {
                super(res);
                this.request = req;
-               this.servlet = servlet;
 
-               for (Map.Entry<String,Object> e : 
servlet.getDefaultResponseHeaders().entrySet())
+               for (Map.Entry<String,Object> e : 
context.getDefaultResponseHeaders().entrySet())
                        setHeader(e.getKey(), e.getValue().toString());
 
                try {
                        String passThroughHeaders = 
req.getHeader("x-response-headers");
                        if (passThroughHeaders != null) {
-                               ObjectMap m = 
servlet.getUrlEncodingParser().parseParameter(passThroughHeaders, 
ObjectMap.class);
+                               ObjectMap m = 
context.getUrlEncodingParser().parseParameter(passThroughHeaders, 
ObjectMap.class);
                                for (Map.Entry<String,Object> e : m.entrySet())
                                        setHeader(e.getKey(), 
e.getValue().toString());
                        }
@@ -101,7 +100,7 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
                                MediaType mt = r.getMediaType();
                                if (mt.getType().equals("*"))
                                        charset = defaultCharset;
-                               else if 
(RestServlet.availableCharsets.containsKey(mt.getType()))
+                               else if (Charset.isSupported(mt.getType()))
                                        charset = mt.getType();
                                if (charset != null)
                                        break;
@@ -138,7 +137,7 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
         * @throws RestServletException
         */
        public List<String> getSupportedEncodings() throws RestServletException 
{
-               return servlet.getEncoders().getSupportedEncodings();
+               return encoders.getSupportedEncodings();
        }
 
        /**

Reply via email to