http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestServlet.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestServlet.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestServlet.java
index f876360..d7288d3 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestServlet.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestServlet.java
@@ -12,48 +12,17 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest;
 
-import static java.lang.String.*;
 import static java.util.logging.Level.*;
 import static javax.servlet.http.HttpServletResponse.*;
-import static org.apache.juneau.dto.swagger.SwaggerBuilder.*;
-import static org.apache.juneau.internal.ArrayUtils.*;
-import static org.apache.juneau.internal.ClassUtils.*;
-import static org.apache.juneau.rest.RestServlet.ParamType.*;
-import static org.apache.juneau.rest.RestServletContext.*;
-import static org.apache.juneau.rest.annotation.Inherit.*;
-import static org.apache.juneau.serializer.SerializerContext.*;
 
 import java.io.*;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.lang.reflect.Method;
-import java.nio.charset.*;
 import java.text.*;
-import java.util.*;
-import java.util.concurrent.*;
 import java.util.logging.*;
 
-import javax.activation.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.dto.swagger.*;
-import org.apache.juneau.encoders.*;
-import org.apache.juneau.encoders.Encoder;
-import org.apache.juneau.ini.*;
-import org.apache.juneau.internal.*;
-import org.apache.juneau.json.*;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.parser.ParseException;
-import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.annotation.Properties;
-import org.apache.juneau.rest.response.*;
-import org.apache.juneau.rest.vars.*;
-import org.apache.juneau.serializer.*;
-import org.apache.juneau.svl.*;
-import org.apache.juneau.svl.vars.*;
-import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -61,3265 +30,253 @@ import org.apache.juneau.utils.*;
  * <p>
  * Refer to <a class="doclink" href="package-summary.html#TOC">REST Servlet 
API</a> for information about using this class.
  */
-@SuppressWarnings({"rawtypes","hiding"})
+@SuppressWarnings("hiding")
 public abstract class RestServlet extends HttpServlet {
 
        private static final long serialVersionUID = 1L;
 
-       static final SortedMap<String,Charset> availableCharsets = new 
TreeMap<String,Charset>(String.CASE_INSENSITIVE_ORDER);
-       static {
-               availableCharsets.putAll(Charset.availableCharsets());
-       }
-       // Map of HTTP method names (e.g. GET/PUT/...) to ResourceMethod 
implementations for it.  Populated during resource initialization.
-       private final Map<String,ResourceMethod> restMethods = new 
LinkedHashMap<String,ResourceMethod>();
-
-       // The list of all @RestMethod annotated methods in the order they 
appear in the class.
-       private final Map<String,MethodMeta> javaRestMethods = new 
LinkedHashMap<String,MethodMeta>();
-
-       // Child resources of this resource defined through getX() methods on 
this class.
-       private final Map<String,RestServlet> childResources = new 
LinkedHashMap<String,RestServlet>();
-
-       private RestServlet parentResource;
-
-       private ServletConfig servletConfig;
-       private volatile boolean isInitialized = false;
-       private Exception initException;                       // Exception 
thrown by init() method (cached so it can be thrown on all subsequent requests).
-       private JuneauLogger logger;
-       private MessageBundle msgs;                           // NLS messages.
-
-       private Map<Integer,Integer> stackTraceHashes = new 
HashMap<Integer,Integer>();
-       private String path;
-
-       private LinkedHashMap<Class<?>,RestResource> 
restResourceAnnotationsChildFirst, restResourceAnnotationsParentFirst;
-
-       private UrlEncodingSerializer urlEncodingSerializer;
-       private UrlEncodingParser urlEncodingParser;
-       private ObjectMap properties;
-       private RestGuard[] guards;
-       private Class<?>[] beanFilters, pojoSwaps;
-       private RestConverter[] converters;
-       private TreeMap<String,String> defaultRequestHeaders;
-       private Map<String,Object> defaultResponseHeaders;
-       private EncoderGroup encoders;
-       private SerializerGroup serializers;
-       private ParserGroup parsers;
-       private MimetypesFileTypeMap mimetypesFileTypeMap;
-       private BeanContext beanContext;
-       private VarResolver varResolver;
-       private String title, description, termsOfService, contact, license, 
version, tags, externalDocs;
-       private Map<String,byte[]> resourceStreams = new 
ConcurrentHashMap<String,byte[]>();
-       private Map<String,String> resourceStrings = new 
ConcurrentHashMap<String,String>();
-       private ConfigFile configFile, resolvingConfigFile;
-       private String configPath;
-       private StreamResource styleSheet, favIcon;
-       private Map<String,String> staticFilesMap;
-       private String[] staticFilesPrefixes;
-       private ResponseHandler[] responseHandlers;
-       private String clientVersionHeader = "";
-       private ConcurrentHashMap<Locale,Swagger> swaggers = new 
ConcurrentHashMap<Locale,Swagger>();
-
-       RestServletContext context;
-
-       // In-memory cache of images and stylesheets in the 
org.apache.juneau.rest.htdocs package.
-       private Map<String,StreamResource> staticFilesCache = new 
ConcurrentHashMap<String,StreamResource>();
-
-       // The following code block is executed before the constructor is 
called to
-       // allow the config file to be accessed during object creation.
-       // e.g. private String myConfig = getConfig().getString("myConfig");
-       {
-               VarResolverBuilder vrb = createVarResolver();
-
-               // @RestResource annotations from bottom to top.
-               restResourceAnnotationsChildFirst = 
ReflectionUtils.findAnnotationsMap(RestResource.class, getClass());
-
-               // @RestResource annotations from top to bottom.
-               restResourceAnnotationsParentFirst = 
CollectionUtils.reverse(restResourceAnnotationsChildFirst);
-
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values()) {
-                       if (! r.config().isEmpty())
-                               configPath = r.config();
-               }
-
-               try {
-                       configFile = createConfigFile(vrb);
-                       vrb.contextObject(ConfigFileVar.SESSION_config, 
configFile);
-               } catch (IOException e) {
-                       this.initException = e;
-               }
+       private RestConfig config;
+       private RestContext context;
+       private boolean isInitialized = false;
+       private Exception initException;
 
-               varResolver = vrb.build();
-       }
 
        @Override /* Servlet */
-       public synchronized void init(ServletConfig servletConfig) throws 
ServletException {
+       public final synchronized void init(ServletConfig servletConfig) throws 
ServletException {
                try {
-                       log(FINE, "Servlet {0} init called.", 
getClass().getName());
-                       this.servletConfig = servletConfig;
-
-                       if (isInitialized)
-                               return;
-
-                       super.init(servletConfig);
-
-                       // Find resource resource bundle location.
-                       for (Map.Entry<Class<?>,RestResource> e : 
restResourceAnnotationsChildFirst.entrySet()) {
-                               Class<?> c = e.getKey();
-                               RestResource r = e.getValue();
-                               if (! r.messages().isEmpty()) {
-                                       if (msgs == null)
-                                               msgs = new MessageBundle(c, 
r.messages());
-                                       else
-                                               msgs.addSearchPath(c, 
r.messages());
-                               }
-                       }
-                       for (RestResource r : 
restResourceAnnotationsParentFirst.values()) {
-                               if (! r.title().isEmpty())
-                                       title = r.title();
-                               if (! r.description().isEmpty())
-                                       description = r.description();
-                               if (! r.clientVersionHeader().isEmpty())
-                                       clientVersionHeader = 
r.clientVersionHeader();
-                               if (! r.termsOfService().isEmpty())
-                                       termsOfService = r.termsOfService();
-                               if (! r.contact().isEmpty())
-                                       contact = r.contact();
-                               if (! r.license().isEmpty())
-                                       license = r.license();
-                               if (! r.version().isEmpty())
-                                       version = r.version();
-                               if (! r.tags().isEmpty())
-                                       tags = r.tags();
-                               if (! r.externalDocs().isEmpty())
-                                       externalDocs = r.externalDocs();
-                       }
-
-                       if (msgs == null)
-                               msgs = new MessageBundle(this.getClass(), "");
-                       if (clientVersionHeader.isEmpty())
-                               clientVersionHeader = "X-Client-Version";
-
-                       styleSheet = createStyleSheet();
-                       favIcon = createFavIcon();
-                       staticFilesMap = 
Collections.unmodifiableMap(createStaticFilesMap());
-                       staticFilesPrefixes = 
staticFilesMap.keySet().toArray(new String[0]);
-
-                       properties = createProperties();
-                       beanFilters = createBeanFilters();
-                       pojoSwaps = createPojoSwaps();
-                       context = 
PropertyStore.create().setProperties(properties).getContext(RestServletContext.class);
-                       beanContext = createBeanContext(properties, 
beanFilters, pojoSwaps);
-                       urlEncodingSerializer = 
createUrlEncodingSerializer(properties, beanFilters, pojoSwaps).build();
-                       urlEncodingParser = createUrlEncodingParser(properties, 
beanFilters, pojoSwaps).build();
-                       serializers = createSerializers(properties, 
beanFilters, pojoSwaps).build();
-                       parsers = createParsers(properties, beanFilters, 
pojoSwaps).build();
-                       converters = createConverters(properties);
-                       encoders = createEncoders(properties).build();
-                       guards = createGuards(properties);
-                       mimetypesFileTypeMap = 
createMimetypesFileTypeMap(properties);
-                       defaultRequestHeaders = new 
TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER);
-                       
defaultRequestHeaders.putAll(createDefaultRequestHeaders(properties));
-                       defaultResponseHeaders = 
createDefaultResponseHeaders(properties);
-                       responseHandlers = createResponseHandlers(properties);
-
-                       // Discover the @RestMethod methods available on the 
resource.
-                       List<String> methodsFound = new LinkedList<String>();   
// Temporary to help debug transient duplicate method issue.
-                       for (java.lang.reflect.Method method : 
this.getClass().getMethods()) {
-                               if 
(method.isAnnotationPresent(RestMethod.class)) {
-                                       RestMethod a = 
method.getAnnotation(RestMethod.class);
-                                       methodsFound.add(method.getName() + "," 
+ a.name() + "," + a.path());
-                                       try {
-                                               if (! 
Modifier.isPublic(method.getModifiers()))
-                                                       throw new 
RestServletException("@RestMethod method {0}.{1} must be defined as public.", 
this.getClass().getName(), method.getName());
-
-                                               MethodMeta sm = new 
MethodMeta(method);
-                                               
javaRestMethods.put(method.getName(), sm);
-                                               ResourceMethod rm = 
restMethods.get(sm.httpMethod);
-                                               if (rm == null)
-                                                       
restMethods.put(sm.httpMethod, sm);
-                                               else if (rm instanceof 
MultiMethod)
-                                                       
((MultiMethod)rm).addSimpleMethod(sm);
-                                               else
-                                                       
restMethods.put(sm.httpMethod, new MultiMethod((MethodMeta)rm, sm));
-                                       } catch (RestServletException e) {
-                                               throw new 
RestServletException("Problem occurred trying to serialize methods on class 
{0}, methods={1}", this.getClass().getName(), 
JsonSerializer.DEFAULT_LAX.serialize(methodsFound)).initCause(e);
-                                       }
-                               }
+                       RestConfig rsc = new RestConfig(servletConfig, 
this.getClass(), null);
+                       init(rsc);
+                       if (! isInitialized) {
+                               // Subclass may not have called 
super.init(RestServletConfig), so initialize here.
+                               createContext(rsc);
+                               super.init(servletConfig);
                        }
-
-                       for (ResourceMethod m : restMethods.values())
-                               m.complete();
-
-                       // Discover the child resources.
-                       childResources.putAll(createChildrenMap());
-
-                       for (RestServlet child : childResources.values())
-                               child.init(servletConfig);
-
-                       varResolver = varResolver
-                               .builder()
-                               .vars(LocalizationVar.class, RequestVar.class, 
SerializedRequestAttrVar.class, ServletInitParamVar.class, UrlEncodeVar.class)
-                               .build()
-                       ;
-
                } catch (RestException e) {
                        // Thrown RestExceptions are simply caught and rethrown 
on subsequent calls to service().
                        initException = e;
                        log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
-                       title = 
String.valueOf(initException.getLocalizedMessage());
                } catch (ServletException e) {
                        initException = e;
                        log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
-                       title = 
String.valueOf(initException.getLocalizedMessage());
                        throw e;
                } catch (Exception e) {
                        initException = e;
                        log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
-                       title = 
String.valueOf(initException.getLocalizedMessage());
                        throw new ServletException(e);
                } catch (Throwable e) {
                        initException = new Exception(e);
                        log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
-                       title = 
String.valueOf(initException.getLocalizedMessage());
                        throw new ServletException(e);
                } finally {
                        isInitialized = true;
                }
        }
 
-
-       
//--------------------------------------------------------------------------------
-       // Initialization methods
-       
//--------------------------------------------------------------------------------
-
-       /**
-        * Creates the child resources of this resource.
-        * <p>
-        * Default implementation calls {@link #createChildren()} and uses the 
{@link RestResource#path() @RestResource.path()} annotation
-        *      on each child to identify the subpath for the resource which 
become the keys in this map.
-        * It then calls the {@link #setParent(RestServlet)} method on the 
child resource.
-        * <p>
-        * Subclasses can override this method to programatically create child 
resources
-        *      without using the {@link RestResource#children() 
@RestResource.children()} annotation.
-        * When overridding this method, you are responsible for calling {@link 
#setParent(RestServlet)} on the
-        *      child resources.
-        *
-        * @return The new mutable list of child resource instances.
-        * @throws Exception If an error occurred during servlet instantiation.
-        */
-       protected Map<String,RestServlet> createChildrenMap() throws Exception {
-               Map<String,RestServlet> m = new 
LinkedHashMap<String,RestServlet>();
-               for (RestServlet r : createChildren()) {
-                       r.setParent(this);
-                       String p = r.findPath();
-                       if (p == null)
-                               throw new RestServletException("Child resource 
''{0}'' does not define a ''@RestResource.path'' attribute.", 
r.getClass().getName());
-                       m.put(p, r);
-               }
-               return m;
-       }
-
-       /**
-        * Creates instances of child resources for this servlet.
-        * <p>
-        * Default implementation uses the {@link RestResource#children() 
@RestResource.children()} annotation to identify and
-        *      instantiate children.
-        * <p>
-        * Subclasses can override this method to programatically create child 
resources
-        *      without using the {@link RestResource#children() 
@RestResource.children()} annotation.
-        *
-        * @return The new mutable list of child resource instances.
-        * @throws Exception If an error occurred during servlet instantiation.
-        */
-       protected List<RestServlet> createChildren() throws Exception {
-               List<RestServlet> l = new LinkedList<RestServlet>();
-               for (Class<?> c : getChildClasses()) {
-                       if (isParentClass(RestServlet.class, c))
-                               l.add((RestServlet)c.newInstance());
-                       else
-                               l.add(resolveChild(c));
-               }
-               return l;
-       }
-
-       /**
-        * Programmatic equivalent to the {@link RestResource#children() 
@RestResource.children()} annotation.
-        * <p>
-        * Subclasses can override this method to provide customized list of 
child resources.
-        *      (e.g. different children based on values specified in the 
config file).
-        * <p>
-        * Default implementation simply returns the value from the {@link 
RestResource#children() @RestResource.children()} annotation.
-        *
-        * @return The new mutable list of child resource instances.
-        * @throws Exception If an error occurred during servlet instantiation.
-        */
-       protected Class<?>[] getChildClasses() throws Exception {
-               List<Class<?>> l = new ArrayList<Class<?>>();
-               List<RestResource> rr = 
ReflectionUtils.findAnnotations(RestResource.class, getClass());
-               for (RestResource r : rr)
-                       l.addAll(Arrays.asList(r.children()));
-               return l.toArray(new Class<?>[l.size()]);
-       }
-
-       /**
-        * Creates the class-level properties associated with this servlet.
-        * <p>
-        * Subclasses can override this method to provide their own class-level 
properties for this servlet, typically
-        *      by calling <code><jk>super</jk>.createProperties()</code> and 
appending to the map.
-        * However, in most cases, the existing set of properties can be added 
to by overridding {@link #getProperties()}
-        *      and appending to the map returned by 
<code><jk>super</jk>.getProperties()</code>
-        * <p>
-        * By default, the map returned by this method contains the following:
-        * </p>
-        * <ul class='spaced-list'>
-        *      <li>Servlet-init parameters.
-        *      <li>{@link RestResource#properties()} annotations in 
parent-to-child order.
-        *      <li>{@link SerializerContext#SERIALIZER_relativeUriBase} from 
{@link ServletConfig#getServletContext()}.
-        * </ul>
-        *
-        * @return The resource properties as an {@link ObjectMap}.
-        */
-       protected ObjectMap createProperties() {
-               ObjectMap m = new ObjectMap();
-
-               ServletContext ctx = servletConfig.getServletContext();
-
-               // Workaround for bug in Jetty that causes context path to 
always end in "null".
-               String ctxPath = ctx.getContextPath();
-               if (ctxPath.endsWith("null"))
-                       ctxPath = ctxPath.substring(0, ctxPath.length()-4);
-               m.put(SERIALIZER_relativeUriBase, ctxPath);
-
-               // Get the initialization parameters.
-               for (Enumeration ep = servletConfig.getInitParameterNames(); 
ep.hasMoreElements();) {
-                       String p = (String)ep.nextElement();
-                       String initParam = servletConfig.getInitParameter(p);
-                       m.put(p, initParam);
-               }
-
-               // Properties are loaded in parent-to-child order to allow 
overrides.
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values())
-                       for (Property p : r.properties())
-                               m.append(getVarResolver().resolve(p.name()), 
getVarResolver().resolve(p.value()));
-
-               return m;
-       }
-
-       /**
-        * Creates the class-level bean filters associated with this servlet.
-        * <p>
-        * Subclasses can override this method to provide their own class-level 
bean filters for this servlet.
-        * <p>
-        * By default, returns the bean filters specified through the {@link 
RestResource#beanFilters() @RestResource.beanFilters()} annotation in 
child-to-parent order.
-        *      (i.e. bean filters will be applied in child-to-parent order 
with child annotations overriding parent annotations when
-        *      the same filters are applied).
-        *
-        * @return The new set of transforms associated with this servet.
-        */
-       protected Class<?>[] createBeanFilters() {
-               List<Class<?>> l = new LinkedList<Class<?>>();
-
-               // Bean filters are loaded in parent-to-child order to allow 
overrides.
-               for (RestResource r : 
restResourceAnnotationsChildFirst.values())
-                       for (Class c : r.beanFilters())
-                               l.add(c);
-
-               return l.toArray(new Class<?>[l.size()]);
-       }
-
-       /**
-        * Creates the class-level POJO swaps associated with this servlet.
-        * <p>
-        * Subclasses can override this method to provide their own class-level 
POJO swaps for this servlet.
-        * <p>
-        * By default, returns the transforms specified through the {@link 
RestResource#pojoSwaps() @RestResource.pojoSwaps()} annotation in 
child-to-parent order.
-        *      (i.e. POJO swaps will be applied in child-to-parent order with 
child annotations overriding parent annotations when
-        *      the same swaps are applied).
-        *
-        * @return The new set of transforms associated with this servet.
-        */
-       protected Class<?>[] createPojoSwaps() {
-               List<Class<?>> l = new LinkedList<Class<?>>();
-
-               // Swaps are loaded in parent-to-child order to allow overrides.
-               for (RestResource r : 
restResourceAnnotationsChildFirst.values())
-                       for (Class c : r.pojoSwaps())
-                               l.add(c);
-
-               return l.toArray(new Class<?>[l.size()]);
-       }
-
-       /**
-        * Creates the {@link BeanContext} object used for parsing path 
variables and header values.
-        * <p>
-        * Subclasses can override this method to provide their own specialized 
bean context.
-        *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @param beanFilters Servlet-level bean filters returned by {@link 
#createBeanFilters()}.
-        * @param pojoSwaps Servlet-level POJO swaps returned by {@link 
#createPojoSwaps()}.
-        * @return The new bean context.
-        * @throws Exception If bean context not be constructed for any reason.
-        */
-       protected BeanContext createBeanContext(ObjectMap properties, 
Class<?>[] beanFilters, Class<?>[] pojoSwaps) throws Exception {
-               return 
PropertyStore.create().addBeanFilters(beanFilters).addPojoSwaps(pojoSwaps).setProperties(properties).getBeanContext();
-       }
-
-       /**
-        * Creates the URL-encoding serializer used for serializing object 
passed to {@link Redirect}.
-        * <p>
-        * Subclasses can override this method to provide their own specialized 
serializer.
-        *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @param beanFilters Servlet-level bean filters returned by {@link 
#createBeanFilters()}.
-        * @param pojoSwaps Servlet-level POJO swaps returned by {@link 
#createPojoSwaps()}.
-        * @return The new URL-Encoding serializer.
-        * @throws Exception If the serializer could not be constructed for any 
reason.
-        */
-       protected UrlEncodingSerializerBuilder 
createUrlEncodingSerializer(ObjectMap properties, Class<?>[] beanFilters, 
Class<?>[] pojoSwaps) throws Exception {
-               return new 
UrlEncodingSerializerBuilder().properties(properties).beanFilters(beanFilters).pojoSwaps(pojoSwaps);
-       }
-
-       /**
-        * Creates the URL-encoding parser used for parsing URL query 
parameters.
-        * <p>
-        * Subclasses can override this method to provide their own specialized 
parser.
-        *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @param beanFilters Servlet-level bean filters returned by {@link 
#createBeanFilters()}.
-        * @param pojoSwaps Servlet-level POJO swaps returned by {@link 
#createPojoSwaps()}.
-        * @return The new URL-Encoding parser.
-        * @throws Exception If the parser could not be constructed for any 
reason.
-        */
-       protected UrlEncodingParserBuilder createUrlEncodingParser(ObjectMap 
properties, Class<?>[] beanFilters, Class<?>[] pojoSwaps) throws Exception {
-               return new 
UrlEncodingParserBuilder().properties(properties).beanFilters(beanFilters).pojoSwaps(pojoSwaps);
-       }
-
        /**
-        * Creates the serializer group containing serializers used for 
serializing output POJOs in HTTP responses.
+        * Resource initialization method.
         * <p>
-        * Subclasses can override this method to provide their own set of 
serializers for this servlet.
-        * They can do this by either creating a new {@link SerializerGroup} 
from scratch, or appending to the
-        *      group returned by 
<code><jk>super</jk>.createSerializers()</code>.
+        * Identical to {@link Servlet#init(ServletConfig)} except the config 
object provides
+        * access to the external config file, configuration properties, and 
variable resolver
+        * defined for this resource.
         * <p>
-        * By default, returns the serializers defined through {@link 
RestResource#serializers() @RestResource.serializers()} on this class
-        *      and all parent classes.
-        *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @param beanFilters Servlet-level bean filters returned by {@link 
#createBeanFilters()}.
-        * @param pojoSwaps Servlet-level POJO swaps returned by {@link 
#createPojoSwaps()}.
-        * @return The group of serializers.
-        * @throws Exception If serializer group could not be constructed for 
any reason.
-        */
-       protected SerializerGroupBuilder createSerializers(ObjectMap 
properties, Class<?>[] beanFilters, Class<?>[] pojoSwaps) throws Exception {
-               SerializerGroupBuilder g = new SerializerGroupBuilder();
-
-               // Serializers are loaded in parent-to-child order to allow 
overrides.
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values())
-                       g.append(reverse(r.serializers()));
-
-               return 
g.properties(properties).beanFilters(beanFilters).pojoSwaps(pojoSwaps);
-       }
-
-       /**
-        * Creates the parser group containing parsers used for parsing input 
into POJOs from HTTP requests.
+        * Classes can also use {@link HttpServlet#init()} and {@link 
RestServlet#getServletConfig()}
+        * as well to perform initialization.
         * <p>
-        * Subclasses can override this method to provide their own set of 
parsers for this servlet.
-        * They can do this by either creating a new {@link ParserGroup} from 
scratch, or appending to the
-        *      group returned by <code><jk>super</jk>.createParsers()</code>.
+        * Note that if you override this method, you must first call 
<code><jk>super</jk>.init(servletConfig)</code>!
         * <p>
-        * By default, returns the parsers defined through {@link 
RestResource#parsers() @RestResource.parsers()} on this class
-        *      and all parent classes.
+        * Resource classes that don't extend from {@link RestServlet} can add 
this method to their class
+        * to get access to the config object.
         *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @param beanFilters Servlet-level bean filters returned by {@link 
#createBeanFilters()}.
-        * @param pojoSwaps Servlet-level POJO swaps returned by {@link 
#createPojoSwaps()}.
-        * @return The group of parsers.
-        * @throws Exception If parser group could not be constructed for any 
reason.
+        * @param config The servlet configuration.
+        * @throws Exception Any exception can be thrown to signal an 
initialization failure.
         */
-       protected ParserGroupBuilder createParsers(ObjectMap properties, 
Class<?>[] beanFilters, Class<?>[] pojoSwaps) throws Exception {
-               ParserGroupBuilder g = new ParserGroupBuilder();
-
-               // Parsers are loaded in parent-to-child order to allow 
overrides.
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values())
-                       g.append(reverse(r.parsers()));
-
-               return 
g.properties(properties).beanFilters(beanFilters).pojoSwaps(pojoSwaps);
+       public synchronized void init(RestConfig config) throws Exception {
+               if (isInitialized)
+                       return;
+               createContext(config);
+               super.init(config);
+               init(context);
        }
 
        /**
-        * Creates the class-level converters associated with this servlet.
+        * Convenience method if you want to perform initialization on your 
resource after all configuration settings
+        * have been made.
         * <p>
-        * Subclasses can override this method to provide their own class-level 
converters for this servlet.
+        * This allows you to get access to the {@link RestContext} object 
during initialization.
         * <p>
-        * By default, returns the converters specified through the {@link 
RestResource#converters() @RestResource.converters()} annotation in 
child-to-parent order.
-        *      (e.g. converters on children will be called before converters 
on parents).
+        * The default implementation does nothing.
         *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @return The new set of transforms associated with this servet.
-        * @throws RestServletException
+        * @param context The servlet context containing all the set-in-stone 
configurations for this resource.
+        * @throws Exception Any exception can be thrown to signal an 
initialization failure.
         */
-       protected RestConverter[] createConverters(ObjectMap properties) throws 
RestServletException {
-               List<RestConverter> l = new LinkedList<RestConverter>();
+       public synchronized void init(RestContext context) throws Exception {}
 
-               // Converters are loaded in child-to-parent order.
-               for (RestResource r : 
restResourceAnnotationsChildFirst.values())
-                       for (Class<? extends RestConverter> c : r.converters())
-                               try {
-                                       l.add(c.newInstance());
-                               } catch (Exception e) {
-                                       throw new 
RestServletException("Exception occurred while trying to instantiate 
RestConverter ''{0}''", c.getSimpleName()).initCause(e);
-                               }
 
-               return l.toArray(new RestConverter[l.size()]);
+       private synchronized void createContext(RestConfig config) throws 
Exception {
+               if (isInitialized)
+                       return;
+               this.config = config;
+               this.context = new RestContext(this, config);
+               this.isInitialized = true;
        }
 
-       /**
-        * Creates the {@link EncoderGroup} for this servlet for handling 
various encoding schemes.
-        * <p>
-        * Subclasses can override this method to provide their own encoder 
group, typically by
-        *      appending to the group returned by 
<code><jk>super</jk>.createEncoders()</code>.
-        * <p>
-        * By default, returns a group containing {@link 
IdentityEncoder#INSTANCE} and all encoders
-        *      specified through {@link RestResource#encoders() 
@RestResource.encoders()} annotations in parent-to-child order.
-        *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @return The new encoder group associated with this servet.
-        * @throws RestServletException
-        */
-       protected EncoderGroupBuilder createEncoders(ObjectMap properties) 
throws RestServletException {
-               EncoderGroupBuilder g = new 
EncoderGroupBuilder().append(IdentityEncoder.INSTANCE);
-
-               // Encoders are loaded in parent-to-child order to allow 
overrides.
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values())
-                       for (Class<? extends Encoder> c : reverse(r.encoders()))
-                               try {
-                                       g.append(c);
-                               } catch (Exception e) {
-                                       throw new 
RestServletException("Exception occurred while trying to instantiate Encoder 
''{0}''", c.getSimpleName()).initCause(e);
-                               }
 
-               return g;
-       }
+       
//--------------------------------------------------------------------------------
+       // Other methods
+       
//--------------------------------------------------------------------------------
 
        /**
-        * Creates the class-level guards associated with this servlet.
-        * <p>
-        * Subclasses can override this method to provide their own class-level 
guards for this servlet.
+        * The main service method.
         * <p>
-        * By default, returns the guards specified through the {@link 
RestResource#guards() @RestResource.guards()} annotation in child-to-parent 
order.
-        *      (i.e. guards on children will be called before guards on 
parents).
-        *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @return The new set of guards associated with this servet.
-        * @throws RestServletException
+        * Subclasses can optionally override this method if they want to 
tailor the behavior of requests.
         */
-       protected RestGuard[] createGuards(ObjectMap properties) throws 
RestServletException {
-               List<RestGuard> l = new LinkedList<RestGuard>();
+       @Override /* Servlet */
+       public void service(HttpServletRequest r1, HttpServletResponse r2) 
throws ServletException, IOException {
+               try {
 
-               // Guards are loaded in child-to-parent order.
-               for (RestResource r : 
restResourceAnnotationsChildFirst.values())
-                       for (Class<? extends RestGuard> c : reverse(r.guards()))
-                               try {
-                                       l.add(c.newInstance());
-                               } catch (Exception e) {
-                                       throw new 
RestServletException("Exception occurred while trying to instantiate RestGuard 
''{0}''", c.getSimpleName()).initCause(e);
-                               }
+                       if (initException != null) {
+                               if (initException instanceof RestException)
+                                       throw (RestException)initException;
+                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, initException);
+                       }
+                       if (context == null)
+                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, "Servlet not initialized.  
init(RestServletConfig) was not called.");
+                       if (! isInitialized)
+                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, "Servlet has not been initialized");
 
-               return l.toArray(new RestGuard[l.size()]);
-       }
+                       context.getCallHandler().service(r1, r2);
 
-       /**
-        * Creates an instance of {@link MimetypesFileTypeMap} that is used to 
determine
-        *      the media types of static files.
-        * <p>
-        * Subclasses can override this method to provide their own mappings, 
or augment the existing
-        *      map by appending to 
<code><jk>super</jk>.createMimetypesFileTypeMap()</code>
-        *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @return A new reusable MIME-types map.
-        */
-       protected MimetypesFileTypeMap createMimetypesFileTypeMap(ObjectMap 
properties) {
-               MimetypesFileTypeMap m = new MimetypesFileTypeMap();
-               m.addMimeTypes("text/css css CSS");
-               m.addMimeTypes("text/html html htm HTML");
-               m.addMimeTypes("text/plain txt text TXT");
-               m.addMimeTypes("application/javascript js");
-               m.addMimeTypes("image/png png");
-               m.addMimeTypes("image/gif gif");
-               m.addMimeTypes("application/xml xml XML");
-               m.addMimeTypes("application/json json JSON");
-               return m;
+               } catch (RestException e) {
+                       context.getCallHandler().handleError(r1, r2, e);
+               } catch (Throwable e) {
+                       context.getCallHandler().handleError(r1, r2, new 
RestException(SC_INTERNAL_SERVER_ERROR, e));
+               }
        }
 
        /**
-        * Creates the set of default request headers for this servlet.
+        * Returns the read-only context object that contains all the 
configuration information about 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.
+        * This object is <jk>null</jk> during the call to {@link 
#init(RestConfig)} but is populated
+        * by the time {@link #init()} is called.
         * <p>
-        * Subclasses can override this method to provide their own class-level 
default request headers for this servlet.
-        * <p>
-        * By default, returns the default request headers specified through 
the {@link RestResource#defaultRequestHeaders() 
@RestResource.defaultRequestHeaders()}
-        *      annotation in parent-to-child order.
-        * (e.g. headers defined on children will override the same headers 
defined on parents).
+        * Resource classes that don't extend from {@link RestServlet} can add 
the following method to their
+        * class to get access to this context object:
+        * <p class='bcode'>
+        *      <jk>public void</jk> init(RestServletContext context) 
<jk>throws</jk> Exception;
+        * </p>
         *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @return The new set of default request headers associated with this 
servet.
-        * @throws RestServletException
+        * @return The context information on this servlet.
         */
-       protected Map<String,String> createDefaultRequestHeaders(ObjectMap 
properties) throws RestServletException {
-               Map<String,String> m = new HashMap<String,String>();
-
-               // Headers are loaded in parent-to-child order to allow 
overrides.
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values()) {
-                       for (String s : r.defaultRequestHeaders()) {
-                               String[] h = parseHeader(s);
-                               if (h == null)
-                                       throw new RestServletException("Invalid 
default request header specified: ''{0}''.  Must be in the format: 
''Header-Name: header-value''", s);
-                               m.put(h[0], h[1]);
-                       }
-               }
-
-               return m;
+       protected RestContext getContext() {
+               return context;
        }
 
        /**
-        * Creates the set of default response headers for this servlet.
+        * Callback method for listening for successful completion of requests.
         * <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.
+        * Subclasses can override this method for gathering performance 
statistics.
         * <p>
-        * Subclasses can override this method to provide their own class-level 
default response headers for this servlet.
+        * The default implementation does nothing.
         * <p>
-        * By default, returns the default response headers specified through 
the {@link RestResource#defaultResponseHeaders() 
@RestResource.defaultResponseHeaders()}
-        *      annotation in parent-to-child order.
-        * (e.g. headers defined on children will override the same headers 
defined on parents).
+        * Resources that don't extend from {@link RestServlet} can implement 
an equivalent method by
+        *      overriding the {@link RestCallHandler#onSuccess(RestRequest, 
RestResponse, long)} method.
         *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @return The new set of default response headers associated with this 
servet.
-        * @throws RestServletException
+        * @param req The HTTP request.
+        * @param res The HTTP response.
+        * @param time The time in milliseconds it took to process the request.
         */
-       protected Map<String,Object> createDefaultResponseHeaders(ObjectMap 
properties) throws RestServletException {
-               Map<String,Object> m = new LinkedHashMap<String,Object>();
-
-               // Headers are loaded in parent-to-child order to allow 
overrides.
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values()) {
-                       for (String s : r.defaultResponseHeaders()) {
-                               String[] h = parseHeader(s);
-                               if (h == null)
-                                       throw new RestServletException("Invalid 
default response header specified: ''{0}''.  Must be in the format: 
''Header-Name: header-value''", s);
-                               m.put(h[0], h[1]);
-                       }
-               }
-
-               return m;
-       }
+       protected void onSuccess(RestRequest req, RestResponse res, long time) 
{}
 
        /**
-        * Creates the class-level response handlers associated with this 
servlet.
+        * Callback method that gets invoked right before the REST Java method 
is invoked.
         * <p>
-        * Subclasses can override this method to provide their own class-level 
response handlers for this servlet.
+        * Subclasses can override this method to override request headers or 
set request-duration properties
+        *      before the Java method is invoked.
         * <p>
-        * By default, returns the handlers specified through the {@link 
RestResource#responseHandlers() @RestResource.responseHandlers()}
-        *      annotation in parent-to-child order.
-        * (e.g. handlers on children will be called before handlers on 
parents).
+        * Resources that don't extend from {@link RestServlet} can implement 
an equivalent method by
+        *      overriding the {@link RestCallHandler#onPreCall(RestRequest)} 
method.
         *
-        * @param properties Servlet-level properties returned by {@link 
#createProperties()}.
-        * @return The new set of response handlers associated with this servet.
-        * @throws RestException
+        * @param req The HTTP servlet request object.
+        * @throws RestException If any error occurs.
         */
-       protected ResponseHandler[] createResponseHandlers(ObjectMap 
properties) throws RestException {
-               List<ResponseHandler> l = new LinkedList<ResponseHandler>();
-
-               // Loaded in parent-to-child order to allow overrides.
-               for (RestResource r : 
restResourceAnnotationsParentFirst.values())
-                       for (Class<? extends ResponseHandler> c : 
r.responseHandlers())
-                               try {
-                                       l.add(c.newInstance());
-                               } catch (Exception e) {
-                                       throw new 
RestException(SC_INTERNAL_SERVER_ERROR, e);
-                               }
-
-               // Add the default handlers.
-               l.add(new StreamableHandler());
-               l.add(new WritableHandler());
-               l.add(new ReaderHandler());
-               l.add(new InputStreamHandler());
-               l.add(new RedirectHandler());
-               l.add(new DefaultHandler());
-
-               return l.toArray(new ResponseHandler[l.size()]);
-       }
-
-
-       
//--------------------------------------------------------------------------------
-       // Other methods
-       
//--------------------------------------------------------------------------------
+       protected void onPreCall(RestRequest req) throws RestException {}
 
        /**
-        * Returns the localized Swagger from the file system.
+        * Callback method that gets invoked right after the REST Java method 
is invoked, but before
+        *      the serializer is invoked.
         * <p>
-        * Looks for a file called <js>"{ServletClass}_{locale}.json"</js> in 
the same package
-        * as this servlet and returns it as a parsed {@link Swagger} object.
+        * Subclasses can override this method to override request and response 
headers, or
+        *      set/override properties used by the serializer.
         * <p>
-        * Returned objects are cached for later quick-lookup.
+        * Resources that don't extend from {@link RestServlet} can implement 
an equivalent method by
+        *      overriding the {@link 
RestCallHandler#onPostCall(RestRequest,RestResponse)} method.
         *
-        * @param locale The locale of the swagger.
-        * @return The parsed swagger object, or <jk>null</jk> if the swagger 
file could not be found.
-        * @throws RestException
-        */
-       protected Swagger getSwaggerFromFile(Locale locale) throws 
RestException {
-               Swagger s = swaggers.get(locale);
-               if (s == null) {
-                       try {
-                               s = getResource(Swagger.class, MediaType.JSON, 
getClass().getSimpleName() + ".json", locale);
-                               swaggers.putIfAbsent(locale, s == null ? 
Swagger.NULL : s);
-                       } catch (Exception e) {
-                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, e);
-                       }
-               }
-               return s == Swagger.NULL ? null : s;
-       }
-
-
-       /**
-        * Returns the localized swagger for this REST resource.
-        *
-        * @param req The incoming HTTP request.
-        * @return A new Swagger instance.
-        * @throws RestException
+        * @param req The HTTP servlet request object.
+        * @param res The HTTP servlet response object.
+        * @throws RestException If any error occurs.
         */
-       protected Swagger getSwagger(RestRequest req) throws RestException {
-               try {
-                       // If a file is defined, use that.
-                       Swagger s = req.getSwaggerFromFile();
-                       if (s != null)
-                               return s;
-
-                       s = swagger(
-                               info(getTitle(req), getVersion(req))
-                                       .contact(getContact(req))
-                                       .license(getLicense(req))
-                                       .description(getDescription(req))
-                                       .termsOfService(getTermsOfService(req))
-                               )
-                               .consumes(getSupportedAcceptTypes())
-                               .produces(getSupportedContentTypes())
-                               .tags(getTags(req))
-                               .externalDocs(getExternalDocs(req));
-
-                       for (MethodMeta sm : javaRestMethods.values()) {
-                               if (sm.isRequestAllowed(req)) {
-                                       Operation o = 
sm.getSwaggerOperation(req);
-                                       s.path(
-                                               
sm.pathPattern.getPatternString(),
-                                               sm.httpMethod.toLowerCase(),
-                                               o
-                                       );
-                               }
-                       }
-                       return s;
-               } catch (RestException e) {
-                       throw e;
-               } catch (Exception e) {
-                       throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
-               }
-       }
+       protected void onPostCall(RestRequest req, RestResponse res) throws 
RestException {}
 
        /**
-        * Sets the parent of this resource.
+        * Convenience method for calling 
<code>getContext().getLogger().log(level, msg, args);</code>
         *
-        * @param parent The parent of this resource.
+        * @param level The log level.
+        * @param msg The message to log.
+        * @param args Optional {@link MessageFormat}-style arguments.
         */
-       protected void setParent(RestServlet parent) {
-               this.parentResource = parent;
+       protected void log(Level level, String msg, Object...args) {
+               if (context != null)
+                       context.getLogger().log(level, msg, args);
        }
 
        /**
-        * Returns the parent of this resource.
+        * Convenience method for calling 
<code>getContext().getLogger().log(level, cause, msg, args);</code>
         *
-        * @return The parent of this resource, or <jk>null</jk> if resource 
has no parent.
+        * @param level The log level.
+        * @param cause The cause.
+        * @param msg The message to log.
+        * @param args Optional {@link MessageFormat}-style arguments.
         */
-       public RestServlet getParent() {
-               return this.parentResource;
-       }
-
-       private static String[] parseHeader(String s) {
-               int i = s.indexOf(':');
-               if (i == -1)
-                       return null;
-               String name = s.substring(0, 
i).trim().toLowerCase(Locale.ENGLISH);
-               String val = s.substring(i+1).trim();
-               return new String[]{name,val};
+       protected void log(Level level, Throwable cause, String msg, 
Object...args) {
+               if (context != null)
+                       context.getLogger().log(level, cause, msg, args);
        }
 
-       /**
-        * 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(this, req);
+       @Override /* GenericServlet */
+       public RestConfig getServletConfig() {
+               return config;
        }
 
-       /**
-        * 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 erros occur trying to interpret the 
request or response.
-        */
-       protected RestResponse createResponse(RestRequest req, 
HttpServletResponse res) throws ServletException {
-               return new RestResponse(this, req, res);
+       @Override /* GenericServlet */
+       public void destroy() {
+               context.destroy();
+               super.destroy();
        }
 
        /**
-        * Returns whether this resource class can provide an OPTIONS page.
-        * <p>
-        * By default, returns <jk>false</jk>.
-        * <p>
-        * Subclasses can override this method to cause the 
<code>options</code> link to show up in the HTML serialized output.
-        *
-        * @return <jk>true</jk> if this resource has implemented a {@code 
getOptions()} method.
+        * Convenience method for calling 
<code>getContext().getMessages();</code>
+        * @return The resource bundle for this resource.  Never <jk>null</jk>.
+        * @see RestContext#getProperties()
         */
-       public boolean hasOptionsPage() {
-               return false;
+       public MessageBundle getMessages() {
+               return context.getMessages();
        }
 
        /**
-        * Specify a class-level property.
-        * <p>
-        * Typically, properties in {@link RestServletContext} can be set in 
the {@link Servlet#init(ServletConfig)} method.
-        *
-        * @param key The property name.
-        * @param value The property value.
-        * @return This object (for method chaining).
+        * Convenience method for calling 
<code>getContext().getProperties();</code>
+        * @return The resource properties as an {@link ObjectMap}.
+        * @see RestContext#getProperties()
         */
-       public synchronized RestServlet setProperty(String key, Object value) {
-               getProperties().put(key, value);
-               return this;
+       public ObjectMap getProperties() {
+               return getContext().getProperties();
        }
 
        /**
-        * The main service method.
-        * <p>
-        * Subclasses can optionally override this method if they want to 
tailor the behavior of requests.
-        */
-       @Override /* Servlet */
-       public void service(HttpServletRequest r1, HttpServletResponse r2) 
throws ServletException, IOException {
-
-               log(FINE, "HTTP: {0} {1}", r1.getMethod(), r1.getRequestURI());
-               long startTime = System.currentTimeMillis();
-
-               try {
-
-                       if (initException != null) {
-                               if (initException instanceof RestException)
-                                       throw (RestException)initException;
-                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, initException);
-                       }
-
-                       if (! isInitialized)
-                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, "Servlet has not been initialized");
-
-                       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 && (! childResources.isEmpty()) && 
(! pathInfo.equals("/"))) {
-                               int i = pathInfo.indexOf('/', 1);
-                               String pathInfoPart = i == -1 ? 
pathInfo.substring(1) : pathInfo.substring(1, i);
-                               RestServlet childResource = 
childResources.get(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 
RestUtils.decode(pathInfoRemainder);
-                                               }
-                                               @Override /* ServletRequest */
-                                               public String getServletPath() {
-                                                       return servletPath;
-                                               }
-                                       };
-                                       childResource.service(childRequest, r2);
-                                       return;
-                               }
-                       }
-
-                       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 = favIcon;
-                               else if (p.equals("style.css"))
-                                       r = styleSheet;
-                               else if (StringUtils.pathStartsWith(p, 
staticFilesPrefixes))
-                                       r = 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 (restMethods.containsKey(methodUC)) {
-                                       rc = 
restMethods.get(methodUC).invoke(method, pathInfo, this, req, res);
-                               } else if (restMethods.containsKey("*")) {
-                                       rc = 
restMethods.get("*").invoke(method, pathInfo, this, 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 : getConverters())
-                                       output = converter.convert(req, output, 
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);
-                       }
-
-                       onSuccess(req, res, System.currentTimeMillis() - 
startTime);
-
-               } catch (RestException e) {
-                       handleError(r1, r2, e);
-               } catch (Throwable e) {
-                       handleError(r1, r2, new 
RestException(SC_INTERNAL_SERVER_ERROR, e));
-               }
-               log(FINE, "HTTP: [{0} {1}] finished in {2}ms", r1.getMethod(), 
r1.getRequestURI(), System.currentTimeMillis()-startTime);
-       }
-
-       /**
-        * 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"  : 
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);
-       }
-
-       private synchronized void handleError(HttpServletRequest req, 
HttpServletResponse res, RestException e) throws IOException {
-               Integer c = 1;
-               if (context.useStackTraceHashes) {
-                       int h = e.hashCode();
-                       c = stackTraceHashes.get(h);
-                       if (c == null)
-                               c = 1;
-                       else
-                               c++;
-                       stackTraceHashes.put(h, c);
-                       e.setOccurrence(c);
-               }
-               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 RestServletContext#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");
-               PrintWriter w = null;
-               try {
-                       w = res.getWriter();
-               } catch (IllegalStateException e2) {
-                       w = new PrintWriter(new 
OutputStreamWriter(res.getOutputStream(), IOUtils.UTF8));
-               }
-               String httpMessage = RestUtils.getHttpResponseText(status);
-               if (httpMessage != null)
-                       w.append("HTTP 
").append(String.valueOf(status)).append(": 
").append(httpMessage).append("\n\n");
-               if (context.renderResponseStackTraces)
-                       e.printStackTrace(w);
-               else
-                       w.append(e.getFullStackMessage(true));
-               w.flush();
-               w.close();
-       }
-
-       /**
-        * Callback method for logging errors during HTTP requests.
-        * <p>
-        *      ypically, 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;
-       }
-
-       /**
-        * 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);
-       }
-
-       /**
-        * Log a message to the logger returned by {@link #getLogger()}.
-        * <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 void log(Level level, Throwable cause, String msg, 
Object...args) {
-               JuneauLogger log = getLogger();
-               if (args.length > 0)
-                       msg = MessageFormat.format(msg, args);
-               log.log(level, msg, cause);
-       }
-
-       /**
-        * Callback method for listening for successful completion of requests.
-        * <p>
-        * Subclasses can override this method for gathering performance 
statistics.
-        * <p>
-        * The default implementation does nothing.
-        *
-        * @param req The HTTP request.
-        * @param res The HTTP response.
-        * @param time The time in milliseconds it took to process the request.
-        */
-       protected void onSuccess(RestRequest req, RestResponse res, long time) 
{}
-
-       /**
-        * Callback method that gets invoked right before the REST Java method 
is invoked.
-        * <p>
-        * Subclasses can override this method to override request headers or 
set request-duration properties
-        *      before the Java method is invoked.
-        *
-        * @param req The HTTP servlet request object.
-        * @throws RestException If any error occurs.
-        */
-       protected void onPreCall(RestRequest req) throws RestException {}
-
-       /**
-        * Callback method that gets invoked right after the REST Java method 
is invoked, but before
-        *      the serializer is invoked.
-        * <p>
-        * Subclasses can override this method to override request and response 
headers, or
-        *      set/override properties used by the serializer.
-        *
-        * @param req The HTTP servlet request object.
-        * @param res The HTTP servlet response object.
-        * @throws RestException If any error occurs.
-        */
-       protected void onPostCall(RestRequest req, RestResponse res) throws 
RestException {}
-
-       /**
-        * The main method for serializing POJOs passed in through the {@link 
RestResponse#setOutput(Object)} method.
-        * <p>
-        * Subclasses may override this method if they wish to modify the way 
the output is rendered, or support
-        *      other output formats.
-        *
-        * @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 : 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())+"'");
-       }
-
-       @Override /* GenericServlet */
-       public ServletConfig getServletConfig() {
-               return servletConfig;
-       }
-
-       @Override /* GenericServlet */
-       public void destroy() {
-               for (RestServlet r : childResources.values())
-                       r.destroy();
-               super.destroy();
-       }
-
-       /**
-        * Resolve a static resource file.
-        * <p>
-        * Subclasses can override this method to provide their own way to 
resolve files.
-        *
-        * @param pathInfo The unencoded path info.
-        * @return The resource, or <jk>null</jk> if the resource could not be 
resolved.
-        * @throws IOException
-        */
-       protected StreamResource resolveStaticFile(String pathInfo) throws 
IOException {
-               if (! staticFilesCache.containsKey(pathInfo)) {
-                       String p = 
RestUtils.decode(RestUtils.trimSlashes(pathInfo));
-                       if (p.indexOf("..") != -1)
-                               throw new RestException(SC_NOT_FOUND, "Invalid 
path");
-                       for (Map.Entry<String,String> e : 
staticFilesMap.entrySet()) {
-                               String key = RestUtils.trimSlashes(e.getKey());
-                               if (p.startsWith(key)) {
-                                       String remainder = (p.equals(key) ? "" 
: p.substring(key.length()));
-                                       if (remainder.isEmpty() || 
remainder.startsWith("/")) {
-                                               String p2 = 
RestUtils.trimSlashes(e.getValue()) + remainder;
-                                               InputStream is = 
getResource(p2, null);
-                                               if (is != null) {
-                                                       try {
-                                                               int i = 
p2.lastIndexOf('/');
-                                                               String name = 
(i == -1 ? p2 : p2.substring(i+1));
-                                                               String 
mediaType = getMimetypesFileTypeMap().getContentType(name);
-                                                               ObjectMap 
headers = new ObjectMap().append("Cache-Control", "max-age=86400, public");
-                                                               
staticFilesCache.put(pathInfo, new 
StreamResource(MediaType.forString(mediaType), headers, is));
-                                                               return 
staticFilesCache.get(pathInfo);
-                                                       } finally {
-                                                               is.close();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-               return staticFilesCache.get(pathInfo);
-       }
-
-       /**
-        * Returns a list of valid {@code Accept} content types for this 
resource.
-        * <p>
-        * Typically used by subclasses during {@code OPTIONS} requests.
-        * <p>
-        * The default implementation resturns the list from {@link 
ParserGroup#getSupportedMediaTypes()}
-        *      from the parser group returned by {@link #getParsers()}.
-        * <p>
-        * Subclasses can override or expand this list as they see fit.
-        *
-        * @return The list of valid {@code Accept} content types for this 
resource.
-        * @throws RestServletException
-        */
-       public Collection<MediaType> getSupportedAcceptTypes() throws 
RestServletException {
-               return getParsers().getSupportedMediaTypes();
-       }
-
-       /**
-        * Returns a list of valid {@code Content-Types} for input for this 
resource.
-        * <p>
-        * Typically used by subclasses during {@code OPTIONS} requests.
-        * <p>
-        * The default implementation resturns the list from {@link 
SerializerGroup#getSupportedMediaTypes()}
-        *      from the parser group returned by {@link #getSerializers()}.
-        * <p>
-        * Subclasses can override or expand this list as they see fit.
-        *
-        * @return The list of valid {@code Content-Type} header values for 
this resource.
-        * @throws RestServletException
-        */
-       public Collection<MediaType> getSupportedContentTypes() throws 
RestServletException {
-               return getSerializers().getSupportedMediaTypes();
-       }
-
-       /**
-        * Returns the localized summary of the specified java method on this 
servlet.
-        * <p>
-        * Subclasses can override this method to provide their own summary.
-        * <p>
-        * The default implementation returns the summary from the following 
locations (whichever matches first):
-        * </p>
-        * <ol>
-        *      <li>{@link RestMethod#summary() @RestMethod.summary()} 
annotation on the method.
-        *      <li><ck>[ClassName].[javaMethodName].summary</ck> property in 
resource bundle identified by {@link RestResource#messages() 
@RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>[javaMethodName].summary</ck> property in resource 
bundle identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        * </ol>
-        *
-        * @param javaMethodName The name of the Java method whose description 
we're retrieving.
-        * @param req The current request.
-        * @return The localized summary of the method, or a blank string if no 
summary was found.
-        */
-       public String getMethodSummary(String javaMethodName, RestRequest req) {
-               MethodMeta m = javaRestMethods.get(javaMethodName);
-               if (m != null)
-                       return m.getSummary(req);
-               return "";
-       }
-
-       /**
-        * Returns the localized description of the specified java method on 
this servlet.
-        * <p>
-        * Subclasses can override this method to provide their own description.
-        * <p>
-        * The default implementation returns the description from the 
following locations (whichever matches first):
-        * </p>
-        * <ol>
-        *      <li>{@link RestMethod#description() @RestMethod.description()} 
annotation on the method.
-        *      <li><ck>[ClassName].[javaMethodName].description</ck> property 
in resource bundle identified by {@link RestResource#messages() 
@RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>[javaMethodName].description</ck> property in resource 
bundle identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        * </ol>
-        *
-        * @param javaMethodName The name of the Java method whose description 
we're retrieving.
-        * @param req The current request.
-        * @return The localized description of the method, or a blank string 
if no description was found.
-        */
-       public String getMethodDescription(String javaMethodName, RestRequest 
req) {
-               MethodMeta m = javaRestMethods.get(javaMethodName);
-               if (m != null)
-                       return m.getDescription(req);
-               return "";
-       }
-
-       /**
-        * Returns the localized title of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own title.
-        * <p>
-        * The default implementation returns the description from the 
following locations (whichever matches first):
-        * <p>
-        * <ol>
-        *      <li>{@link RestResource#title() @RestResourcel.title()} 
annotation on this class, and then any parent classes.
-        *      <li><ck>[ClassName].title</ck> property in resource bundle 
identified by {@link RestResource#messages() @ResourceBundle.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>title</ck> in resource bundle identified by {@link 
RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/title</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized description of this REST resource, or 
<jk>null</jk> if no resource description was found.
-        */
-       public String getTitle(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               if (title != null)
-                       return vr.resolve(title);
-               String title = msgs.findFirstString(req.getLocale(), "title");
-               if (title != null)
-                       return vr.resolve(title);
-               Swagger s = req.getSwaggerFromFile();
-               if (s != null && s.getInfo() != null)
-                       return s.getInfo().getTitle();
-               return null;
-       }
-
-       /**
-        * Returns the localized description of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own description.
-        * <p>
-        * The default implementation returns the description from the 
following locations (whichever matches first):
-        * <ol>
-        *      <li>{@link RestResource#description() 
@RestResource.description()} annotation on this class, and then any parent 
classes.
-        *      <li><ck>[ClassName].description</ck> property in resource 
bundle identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>description</ck> property in resource bundle identified 
by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/description</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized description of this REST resource, or 
<jk>null</jk> if no resource description was found.
-        */
-       public String getDescription(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               if (description != null)
-                       return vr.resolve(description);
-               String description = msgs.findFirstString(req.getLocale(), 
"description");
-               if (description != null)
-                       return vr.resolve(description);
-               Swagger s = req.getSwaggerFromFile();
-               if (s != null && s.getInfo() != null)
-                       return s.getInfo().getDescription();
-               return null;
-       }
-
-       /**
-        * Returns the localized contact information of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own contact 
information.
-        * <p>
-        * The default implementation returns the contact information from the 
following locations (whichever matches first):
-        * <ol>
-        *      <li>{@link RestResource#contact() @RestResource.contact()} 
annotation on this class, and then any parent classes.
-        *      <li><ck>[ClassName].contact</ck> property in resource bundle 
identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>contact</ck> property in resource bundle identified by 
{@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/contact</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized contact information of this REST resource, or 
<jk>null</jk> if no contact information was found.
-        */
-       public Contact getContact(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               JsonParser jp = JsonParser.DEFAULT;
-               try {
-                       if (contact != null)
-                               return jp.parse(vr.resolve(contact), 
Contact.class);
-                       String contact = msgs.findFirstString(req.getLocale(), 
"contact");
-                       if (contact != null)
-                               return jp.parse(vr.resolve(contact), 
Contact.class);
-                       Swagger s = req.getSwaggerFromFile();
-                       if (s != null && s.getInfo() != null)
-                               return s.getInfo().getContact();
-                       return null;
-               } catch (ParseException e) {
-                       throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
-               }
-       }
-
-       /**
-        * Returns the localized license information of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own license 
information.
-        * <p>
-        * The default implementation returns the license information from the 
following locations (whichever matches first):
-        * <ol>
-        *      <li>{@link RestResource#license() @RestResource.license()} 
annotation on this class, and then any parent classes.
-        *      <li><ck>[ClassName].license</ck> property in resource bundle 
identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>license</ck> property in resource bundle identified by 
{@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/license</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized contact information of this REST resource, or 
<jk>null</jk> if no contact information was found.
-        */
-       public License getLicense(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               JsonParser jp = JsonParser.DEFAULT;
-               try {
-                       if (license != null)
-                               return jp.parse(vr.resolve(license), 
License.class);
-                       String license = msgs.findFirstString(req.getLocale(), 
"license");
-                       if (license != null)
-                               return jp.parse(vr.resolve(license), 
License.class);
-                       Swagger s = req.getSwaggerFromFile();
-                       if (s != null && s.getInfo() != null)
-                               return s.getInfo().getLicense();
-                       return null;
-               } catch (ParseException e) {
-                       throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
-               }
-       }
-
-       /**
-        * Returns the terms-of-service information of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own 
terms-of-service information.
-        * <p>
-        * The default implementation returns the terms-of-service information 
from the following locations (whichever matches first):
-        * <ol>
-        *      <li>{@link RestResource#termsOfService() 
@RestResource.termsOfService()} annotation on this class, and then any parent 
classes.
-        *      <li><ck>[ClassName].termsOfService</ck> property in resource 
bundle identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>termsOfService</ck> property in resource bundle 
identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/termsOfService</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized contact information of this REST resource, or 
<jk>null</jk> if no contact information was found.
-        */
-       public String getTermsOfService(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               if (termsOfService != null)
-                       return vr.resolve(termsOfService);
-               String termsOfService = msgs.findFirstString(req.getLocale(), 
"termsOfService");
-               if (termsOfService != null)
-                       return vr.resolve(termsOfService);
-               Swagger s = req.getSwaggerFromFile();
-               if (s != null && s.getInfo() != null)
-                       return s.getInfo().getTermsOfService();
-               return null;
-       }
-
-       /**
-        * Returns the version information of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own version 
information.
-        * <p>
-        * The default implementation returns the version information from the 
following locations (whichever matches first):
-        * <ol>
-        *      <li>{@link RestResource#version() @RestResource.version()} 
annotation on this class, and then any parent classes.
-        *      <li><ck>[ClassName].version</ck> property in resource bundle 
identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>version</ck> property in resource bundle identified by 
{@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/version</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized contact information of this REST resource, or 
<jk>null</jk> if no contact information was found.
-        */
-       public String getVersion(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               if (version != null)
-                       return vr.resolve(version);
-               String version = msgs.findFirstString(req.getLocale(), 
"version");
-               if (version != null)
-                       return vr.resolve(version);
-               Swagger s = req.getSwaggerFromFile();
-               if (s != null && s.getInfo() != null)
-                       return s.getInfo().getVersion();
-               return null;
-       }
-
-       /**
-        * Returns the version information of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own version 
information.
-        * <p>
-        * The default implementation returns the version information from the 
following locations (whichever matches first):
-        * <ol>
-        *      <li>{@link RestResource#version() @RestResource.version()} 
annotation on this class, and then any parent classes.
-        *      <li><ck>[ClassName].version</ck> property in resource bundle 
identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>version</ck> property in resource bundle identified by 
{@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/version</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized contact information of this REST resource, or 
<jk>null</jk> if no contact information was found.
-        */
-       public List<Tag> getTags(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               JsonParser jp = JsonParser.DEFAULT;
-               try {
-                       if (tags != null)
-                               return jp.parse(vr.resolve(tags), 
ArrayList.class, Tag.class);
-                       String tags = msgs.findFirstString(req.getLocale(), 
"tags");
-                       if (tags != null)
-                               return jp.parse(vr.resolve(tags), 
ArrayList.class, Tag.class);
-                       Swagger s = req.getSwaggerFromFile();
-                       if (s != null)
-                               return s.getTags();
-                       return null;
-               } catch (Exception e) {
-                       throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
-               }
-       }
-
-       /**
-        * Returns the version information of this REST resource.
-        * <p>
-        * Subclasses can override this method to provide their own version 
information.
-        * <p>
-        * The default implementation returns the version information from the 
following locations (whichever matches first):
-        * <ol>
-        *      <li>{@link RestResource#version() @RestResource.version()} 
annotation on this class, and then any parent classes.
-        *      <li><ck>[ClassName].version</ck> property in resource bundle 
identified by {@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>version</ck> property in resource bundle identified by 
{@link RestResource#messages() @RestResource.messages()}
-        *              annotation for this class, then any parent classes.
-        *      <li><ck>/info/version</ck> entry in swagger file.
-        * </ol>
-        *
-        * @param req The current request.
-        * @return The localized contact information of this REST resource, or 
<jk>null</jk> if no contact information was found.
-        */
-       public ExternalDocumentation getExternalDocs(RestRequest req) {
-               VarResolverSession vr = req.getVarResolverSession();
-               JsonParser jp = JsonParser.DEFAULT;
-               try {
-                       if (externalDocs != null)
-                               return jp.parse(vr.resolve(externalDocs), 
ExternalDocumentation.class);
-                       String externalDocs = 
msgs.findFirstString(req.getLocale(), "externalDocs");
-                       if (externalDocs != null)
-                               return jp.parse(vr.resolve(externalDocs), 
ExternalDocumentation.class);
-                       Swagger s = req.getSwaggerFromFile();
-                       if (s != null)
-                               return s.getExternalDocs();
-                       return null;
-               } catch (Exception e) {
-                       throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
-               }
-       }
-
-       /**
-        * Returns the resource bundle identified by the {@link 
RestResource#messages() @RestResource.messages()} annotation for the default 
locale.
-        *
-        * @return The resource bundle.  Never <jk>null</jk>.
-        */
-       public MessageBundle getMessages() {
-               return msgs;
-       }
-
-       /**
-        * Returns the resource bundle identified by the {@link 
RestResource#messages() @RestResource.messages()} annotation for the specified 
locale.
-        *
-        * @param locale The resource bundle locale.
-        * @return The resource bundle.  Never <jk>null</jk>.
-        */
-       public MessageBundle getMessages(Locale locale) {
-               return msgs.getBundle(locale);
-       }
-
-       /**
-        * Gets a localized message from the resource bundle identified by the 
{@link RestResource#messages() @RestResource.messages()} annotation.
-        * <p>
-        * If resource bundle location was not specified, or the resource 
bundle was not found,
-        *      returns the string <js>"{!!key}"</js>.
-        * <p>
-        * If message was not found in the resource bundle, returns the string 
<js>"{!key}"</js>.
-        *
-        * @param locale The client locale.
-        * @param key The resource bundle key.
-        * @param args Optional {@link MessageFormat}-style arguments.
-        * @return The localized message.
-        */
-       public String getMessage(Locale locale, String key, Object...args) {
-               return msgs.getString(locale, key, args);
-       }
-
-       /**
-        * Programmatically adds the specified resource as a child to this 
resource.
-        * <p>
-        * This method can be used in a resources {@link #init()} method to 
define child resources
-        *      accessible through a child URL.
-        * <p>
-        * Typically, child methods are defined via {@link 
RestResource#children() @RestResource.children()}.  However, this
-        *      method is provided to handle child resources determined at 
runtime.
-        *
-        * @param name The sub-URL under which this resource is accessible.<br>
-        * For example, if the parent resource URL is <js>"/foo"</js>, and this 
name is <js>"bar"</js>, then
-        *      the child resource will be accessible via the URL 
<js>"/foo/bar"</js>.
-        * @param resource The child resource.
-        * @throws ServletException Thrown by the child init() method.
-        */
-       protected void addChildResource(String name, RestServlet resource) 
throws ServletException {
-               resource.init(getServletConfig());
-               childResources.put(name, resource);
-       }
-
-       /**
-        * Returns the child resources associated with this servlet.
-        *
-        * @return An unmodifiable map of child resources.
-        * Keys are the {@link RestResource#path() @RestResource.path()} 
annotation defined on the child resource.
-        */
-       public Map<String,RestServlet> getChildResources() {
-               return Collections.unmodifiableMap(childResources);
-       }
-
-       /**
-        * Returns the path for this servlet as defined by the {@link 
RestResource#path()} annotation
-        * on this class concatenated with those on all parent classes.
-        * <p>
-        * If path is not specified, returns <js>"/"</js>.
-        * <p>
-        * Path always starts with <js>"/"</js>.
-        *
-        * @return The servlet path.
-        */
-       public String getPath() {
-               if (path == null) {
-                       LinkedList<String> l = new LinkedList<String>();
-                       RestServlet r = this;
-                       while (r != null) {
-                               String p = r.findPath();
-                               if (p == null)
-                                       break;
-                               l.addFirst(p);
-                               r = r.parentResource;
-                       }
-                       StringBuilder sb = new StringBuilder();
-                       for (String p : l)
-                               sb.append('/').append(p);
-                       path = sb.toString();
-               }
-               return path;
-       }
-
-       private String findPath() {
-               List<RestResource> rrc = 
ReflectionUtils.findAnnotations(RestResource.class, getClass());
-               for (RestResource rc : rrc) {
-                       String p = rc.path();
-                       if (StringUtils.startsWith(p, '/'))
-                               p = p.substring(1);
-                       if (! p.isEmpty())
-                               return p;
-               }
-               return null;
-       }
-
-       /**
-        * Returns the config file for this servlet.
-        * <p>
-        * Subclasses can override this method to provide their own config file.
-        * <p>
-        * The default implementation uses the path defined by the {@link 
RestResource#config() @RestResource.config()} property resolved
-        *      by {@link ConfigMgr#DEFAULT}.
-        * @param vrb
-        *
-        * @return The config file for this servlet.
-        * @throws IOException
-        */
-       protected ConfigFile createConfigFile(VarResolverBuilder vrb) throws 
IOException {
-               String cf = vrb.build().resolve(configPath);
-               if (cf.isEmpty())
-                       return getConfigMgr().create();
-               return getConfigMgr().get(cf);
-       }
-
-       /**
-        * Creates the stylesheet for this servlet.
-        * <p>
-        * The stylesheet is made available on the path 
<js>"/servlet-path/style.css"</js>.
-        * <p>
-        * Subclasses can override this method to provide their own stylesheet.
-        * <p>
-        * The default implementation uses the {@link RestResource#stylesheet() 
@RestResource.stylesheet()} annotation
-        *      to determine the stylesheet name and then searches the 
classpath then working directory
-        *      for that stylesheet.
-        *
-        * @return The stylesheet to use for this servlet, or <jk>null</jk> if 
the stylesheet could not be found.
-        * @throws IOException If stylesheet could not be loaded.
-        */
-       protected StreamResource createStyleSheet() throws IOException {
-               for (RestResource r : 
restResourceAnnotationsChildFirst.values())
-                       if (! r.stylesheet().isEmpty()) {
-                               List<InputStream> contents = new 
ArrayList<InputStream>();
-
-                               for (String path : 
StringUtils.split(getVarResolver().resolve(r.stylesheet()), ','))
-                                       contents.add(getResource(path, null));
-
-                               return new 
StreamResource(MediaType.forString("text/css"), contents.toArray());
-                       }
-               return null;
-       }
-
-       /**
-        * Creates the favicon for this servlet.
-        * <p>
-        * The favicon is made available on the path 
<js>"/servlet-path/favicon.ico"</js>.
-        * <p>
-        * Subclasses can override this method to provide their own favorites 
icon.
-        * <p>
-        * The default implementation uses the {@link RestResource#favicon() 
@RestResource.favicon()} annotation
-        *      to determine the file name and then searches the classpath then 
working directory
-        *      for that file.
-        *
-        * @return The icon file to use for this servlet.
-        * @throws IOException If icon file could not be loaded.
-        */
-       protected StreamResource createFavIcon() throws IOException {
-               for (RestResource r : 
restResourceAnnotationsChildFirst.values()) {
-                       if (! r.favicon().isEmpty()) {
-                               String path = 
getVarResolver().resolve(r.favicon());
-                               InputStream is = getResource(path, null);
-                               if (is != null) {
-                                       try {
-                                               return new 
StreamResource(MediaType.forString("image/x-icon"), is);
-                                       } finally {
-                                               is.close();
-                                       }
-                               }
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Creates the static files map for this servlet.
-        * <p>
-        * This map defines static files that can be served up through subpaths 
on this servlet.
-        * The map keys are subpaths (e.g. <js>"htdocs"</js>) and the values 
are locations to look in
-        *      the classpath and working directory for those files.
-        * <p>
-        * Subclasses can override this method to provide their own mappings.
-        * <p>
-        * The default implementation uses the {@link 
RestResource#staticFiles() @RestResource.staticFiles()} annotation
-        *      to determine the mappings.
-        *
-        * @return The list of static file mappings.
-        * @throws ParseException
-        */
-       @SuppressWarnings("unchecked")
-       protected Map<String,String> createStaticFilesMap() throws 
ParseException {
-               Map<String,String> m = new LinkedHashMap<String,String>();
-       

<TRUNCATED>

Reply via email to