You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/03/17 02:17:08 UTC
[3/7] incubator-juneau git commit: Allow @RestResource/@RestMethod
annotations to be used on any classes.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
new file mode 100644
index 0000000..2b55b47
--- /dev/null
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
@@ -0,0 +1,233 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import static javax.servlet.http.HttpServletResponse.*;
+
+import java.text.*;
+import java.util.logging.*;
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Logging utility class.
+ * <p>
+ * Subclasses can override these methods to tailor logging of HTTP requests.
+ * Subclasses MUST implement a no-arg public constructor.
+ * <p>
+ * RestLoggers are associated with servlets/resources in one of the following ways:
+ * <ul>
+ * <li>The {@link RestResource#logger @RestResource.logger()} annotation.
+ * <li>The {@link RestConfig#setLogger(Class)}/{@link RestConfig#setLogger(RestLogger)} methods.
+ * </ul>
+ */
+public abstract class RestLogger {
+
+ /**
+ * Returns the Java logger used for logging.
+ * <p>
+ * Subclasses can provide their own logger.
+ * The default implementation returns the logger created using <code>Logger.getLogger(getClass())</code>.
+ *
+ * @return The logger used for logging.
+ */
+ protected abstract Logger getLogger();
+
+ /**
+ * Log a message to the logger.
+ * <p>
+ * Subclasses can override this method if they wish to log messages using a library other than
+ * Java Logging (e.g. Apache Commons Logging).
+ *
+ * @param level The log level.
+ * @param cause The cause.
+ * @param msg The message to log.
+ * @param args Optional {@link MessageFormat}-style arguments.
+ */
+ protected abstract void log(Level level, Throwable cause, String msg, Object...args);
+
+ /**
+ * Log a message.
+ * <p>
+ * Equivalent to calling <code>log(level, <jk>null</jk>, msg, args);</code>
+ *
+ * @param level The log level.
+ * @param msg The message to log.
+ * @param args Optional {@link MessageFormat}-style arguments.
+ */
+ protected void log(Level level, String msg, Object...args) {
+ log(level, null, msg, args);
+ }
+
+ /**
+ * Same as {@link #log(Level, String, Object...)} excepts runs the arguments through {@link JsonSerializer#DEFAULT_LAX_READABLE}.
+ * <p>
+ * Serialization of arguments do not occur if message is not logged, so it's safe to use this method from within debug log statements.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * logObjects(<jsf>DEBUG</jsf>, <js>"Pojo contents:\n{0}"</js>, myPojo);
+ * </p>
+ *
+ * @param level The log level.
+ * @param msg The message to log.
+ * @param args Optional {@link MessageFormat}-style arguments.
+ */
+ protected void logObjects(Level level, String msg, Object...args) {
+ for (int i = 0; i < args.length; i++)
+ args[i] = JsonSerializer.DEFAULT_LAX_READABLE.toStringObject(args[i]);
+ log(level, null, msg, args);
+ }
+
+ /**
+ * Callback method for logging errors during HTTP requests.
+ * <p>
+ * Typically, subclasses will override this method and log errors themselves.
+ * <p>
+ * The default implementation simply logs errors to the <code>RestServlet</code> logger.
+ * <p>
+ * Here's a typical implementation showing how stack trace hashing can be used to reduce log file sizes...
+ * </p>
+ * <p class='bcode'>
+ * <jk>protected void</jk> onError(HttpServletRequest req, HttpServletResponse res, RestException e, <jk>boolean</jk> noTrace) {
+ * String qs = req.getQueryString();
+ * String msg = <js>"HTTP "</js> + req.getMethod() + <js>" "</js> + e.getStatus() + <js>" "</js> + req.getRequestURI() + (qs == <jk>null</jk> ? <js>""</js> : <js>"?"</js> + qs);
+ * <jk>int</jk> c = e.getOccurrence();
+ *
+ * <jc>// REST_useStackTraceHashes is disabled, so we have to log the exception every time.</jc>
+ * <jk>if</jk> (c == 0)
+ * myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%s] %s"</js>, e.getStatus(), msg), e);
+ *
+ * <jc>// This is the first time we've countered this error, so log a stack trace
+ * // unless ?noTrace was passed in as a URL parameter.</jc>
+ * <jk>else if</jk> (c == 1 && ! noTrace)
+ * myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%h.%s.%s] %s"</js>, e.hashCode(), e.getStatus(), c, msg), e);
+ *
+ * <jc>// This error occurred before.
+ * // Only log the message, not the stack trace.</jc>
+ * <jk>else</jk>
+ * myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%h.%s.%s] %s, %s"</js>, e.hashCode(), e.getStatus(), c, msg, e.getLocalizedMessage()));
+ * }
+ * </p>
+ *
+ * @param req The servlet request object.
+ * @param res The servlet response object.
+ * @param e Exception indicating what error occurred.
+ */
+ protected void onError(HttpServletRequest req, HttpServletResponse res, RestException e) {
+ if (shouldLog(req, res, e)) {
+ String qs = req.getQueryString();
+ String msg = "HTTP " + req.getMethod() + " " + e.getStatus() + " " + req.getRequestURI() + (qs == null ? "" : "?" + qs);
+ int c = e.getOccurrence();
+ if (shouldLogStackTrace(req, res, e)) {
+ msg = '[' + Integer.toHexString(e.hashCode()) + '.' + e.getStatus() + '.' + c + "] " + msg;
+ log(Level.WARNING, e, msg);
+ } else {
+ msg = '[' + Integer.toHexString(e.hashCode()) + '.' + e.getStatus() + '.' + c + "] " + msg + ", " + e.getLocalizedMessage();
+ log(Level.WARNING, msg);
+ }
+ }
+ }
+
+ /**
+ * Returns <jk>true</jk> if the specified exception should be logged.
+ * <p>
+ * Subclasses can override this method to provide their own logic for determining when exceptions are logged.
+ * <p>
+ * The default implementation will return <jk>false</jk> if <js>"noTrace=true"</js> is passed in the query string.
+ *
+ * @param req The HTTP request.
+ * @param res The HTTP response.
+ * @param e The exception.
+ * @return <jk>true</jk> if exception should be logged.
+ */
+ protected boolean shouldLog(HttpServletRequest req, HttpServletResponse res, RestException e) {
+ String q = req.getQueryString();
+ return (q == null ? true : q.indexOf("noTrace=true") == -1);
+ }
+
+ /**
+ * Returns <jk>true</jk> if a stack trace should be logged for this exception.
+ * <p>
+ * Subclasses can override this method to provide their own logic for determining when stack traces are logged.
+ * <p>
+ * The default implementation will only log a stack trace if {@link RestException#getOccurrence()} returns <code>1</code>
+ * and the exception is not one of the following:
+ * </p>
+ * <ul>
+ * <li>{@link HttpServletResponse#SC_UNAUTHORIZED}
+ * <li>{@link HttpServletResponse#SC_FORBIDDEN}
+ * <li>{@link HttpServletResponse#SC_NOT_FOUND}
+ * </ul>
+ *
+ * @param req The HTTP request.
+ * @param res The HTTP response.
+ * @param e The exception.
+ * @return <jk>true</jk> if stack trace should be logged.
+ */
+ protected boolean shouldLogStackTrace(HttpServletRequest req, HttpServletResponse res, RestException e) {
+ if (e.getOccurrence() == 1) {
+ switch (e.getStatus()) {
+ case SC_UNAUTHORIZED:
+ case SC_FORBIDDEN:
+ case SC_NOT_FOUND: return false;
+ default: return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * NO-OP logger.
+ * <p>
+ * Disables all logging.
+ *
+ * @author James Bognar (james.bognar@salesforce.com)
+ */
+ public static class NoOp extends RestLogger {
+
+ @Override /* RestLogger */
+ protected Logger getLogger() {
+ return null;
+ }
+
+ @Override /* RestLogger */
+ protected void log(Level level, Throwable cause, String msg, Object...args) {}
+ }
+
+ /**
+ * Default logger.
+ * <p>
+ * Logs all messages to the logger returned by <code>Logger.<jsm>getLogger</jsm>(getClass().getName())</code>
+ */
+ public static class Normal extends RestLogger {
+
+ private final JuneauLogger logger = JuneauLogger.getLogger(getClass());
+
+ @Override /* RestLogger */
+ protected Logger getLogger() {
+ return logger;
+ }
+
+ @Override /* RestLogger */
+ protected void log(Level level, Throwable cause, String msg, Object...args) {
+ if (args.length > 0)
+ msg = MessageFormat.format(msg, args);
+ getLogger().log(level, msg, cause);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
index 4a2619d..2a1cc16 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestMatcherReflecting.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest;
import java.lang.reflect.*;
/**
- * Subclass of {@link RestMatcher} that gives access to the servlet and Java method it's applied to.
+ * Subclass of {@link RestMatcher} that gives access to the servlet/resource and Java method it's applied to.
* <p>
* Essentially the same as {@link RestMatcher} except has a constructor where the
* Java method is passed in so that you can access annotations defined on it to tailor
@@ -26,8 +26,8 @@ public abstract class RestMatcherReflecting extends RestMatcher {
/**
* Constructor.
*
- * @param servlet The REST servlet.
+ * @param resource The REST servlet.
* @param javaMethod The Java method that this rest matcher is defined on.
*/
- protected RestMatcherReflecting(RestServlet servlet, Method javaMethod) {}
+ protected RestMatcherReflecting(Object resource, Method javaMethod) {}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
index cc60feb..98aba93 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -19,6 +19,7 @@ import static javax.servlet.http.HttpServletResponse.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
+import java.nio.charset.*;
import java.text.*;
import java.util.*;
import java.util.logging.*;
@@ -63,13 +64,15 @@ import org.apache.juneau.utils.*;
@SuppressWarnings("unchecked")
public final class RestRequest extends HttpServletRequestWrapper {
- private final RestServlet servlet;
+ private final RestContext context;
+
private final String method;
private String pathRemainder, body;
private Method javaMethod;
private ObjectMap properties;
private SerializerGroup serializerGroup;
private ParserGroup parserGroup;
+ private EncoderGroup encoders;
private Encoder encoder;
private int contentLength;
private final boolean debug;
@@ -89,17 +92,17 @@ public final class RestRequest extends HttpServletRequestWrapper {
/**
* Constructor.
*/
- RestRequest(RestServlet servlet, HttpServletRequest req) throws ServletException {
+ RestRequest(RestContext context, HttpServletRequest req) throws ServletException {
super(req);
+ this.context = context;
try {
- this.servlet = servlet;
isPost = req.getMethod().equalsIgnoreCase("POST");
// If this is a POST, we want to parse the query parameters ourselves to prevent
// the servlet code from processing the HTTP body as URL-Encoded parameters.
if (isPost)
- queryParams = servlet.getUrlEncodingParser().parseIntoSimpleMap(getQueryString());
+ queryParams = context.getUrlEncodingParser().parseIntoSimpleMap(getQueryString());
else {
queryParams = req.getParameterMap();
}
@@ -109,23 +112,23 @@ public final class RestRequest extends HttpServletRequestWrapper {
String _method = super.getMethod();
String m = getQueryParameter("method");
- if (! StringUtils.isEmpty(m) && (servlet.context.allowMethodParams.contains(m) || servlet.context.allowMethodParams.contains("*")))
+ if (context.allowMethodParam(m))
_method = m;
method = _method;
- if (servlet.context.allowBodyParam) {
+ if (context.isAllowBodyParam()) {
body = getQueryParameter("body");
if (body != null)
setHeader("Content-Type", UonSerializer.DEFAULT.getResponseContentType());
}
- defaultServletHeaders = servlet.getDefaultRequestHeaders();
+ defaultServletHeaders = context.getDefaultRequestHeaders();
debug = "true".equals(getQueryParameter("debug", "false"));
if (debug) {
- servlet.log(Level.INFO, toString());
+ context.getLogger().log(Level.INFO, toString());
}
} catch (RestException e) {
@@ -139,7 +142,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
* Called from RestServlet after a match has been made but before the guard or method invocation.
*/
@SuppressWarnings("hiding")
- final void init(Method javaMethod, String pathRemainder, ObjectMap properties, Map<String,String> mDefaultRequestHeaders, String defaultCharset, SerializerGroup mSerializers, ParserGroup mParsers, UrlEncodingParser mUrlEncodingParser) {
+ final void init(Method javaMethod, String pathRemainder, ObjectMap properties, Map<String,String> mDefaultRequestHeaders, String defaultCharset, SerializerGroup mSerializers, ParserGroup mParsers, UrlEncodingParser mUrlEncodingParser, EncoderGroup encoders) {
this.javaMethod = javaMethod;
this.pathRemainder = pathRemainder;
this.properties = properties;
@@ -149,6 +152,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
this.urlEncodingParser = mUrlEncodingParser;
this.beanSession = urlEncodingParser.getBeanContext().createSession();
this.defaultCharset = defaultCharset;
+ this.encoders = encoders;
}
/**
@@ -403,7 +407,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
}
if (charset == null)
charset = defaultCharset;
- if (! RestServlet.availableCharsets.containsKey(charset))
+ if (! Charset.isSupported(charset))
throw new RestException(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported charset in header ''Content-Type'': ''{0}''", h);
}
return charset;
@@ -1299,11 +1303,11 @@ public final class RestRequest extends HttpServletRequestWrapper {
properties.append("mediaType", mediaType).append("characterEncoding", getCharacterEncoding());
if (! p.isReaderParser()) {
InputStreamParser p2 = (InputStreamParser)p;
- ParserSession session = p2.createSession(getInputStream(), properties, getJavaMethod(), getServlet(), locale, timeZone, mediaType);
+ ParserSession session = p2.createSession(getInputStream(), properties, getJavaMethod(), context.getResource(), locale, timeZone, mediaType);
return p2.parseSession(session, cm);
}
ReaderParser p2 = (ReaderParser)p;
- ParserSession session = p2.createSession(getUnbufferedReader(), properties, getJavaMethod(), getServlet(), locale, timeZone, mediaType);
+ ParserSession session = p2.createSession(getUnbufferedReader(), properties, getJavaMethod(), context.getResource(), locale, timeZone, mediaType);
return p2.parseSession(session, cm);
} catch (ParseException e) {
throw new RestException(SC_BAD_REQUEST,
@@ -1576,45 +1580,45 @@ public final class RestRequest extends HttpServletRequestWrapper {
/**
* Returns the localized servlet title.
* <p>
- * Equivalent to calling {@link RestServlet#getTitle(RestRequest)} with this object.
+ * Equivalent to calling {@link RestInfoProvider#getTitle(RestRequest)} with this object.
*
* @return The localized servlet label.
*/
public String getServletTitle() {
- return servlet.getTitle(this);
+ return context.getInfoProvider().getTitle(this);
}
/**
* Returns the localized servlet description.
* <p>
- * Equivalent to calling {@link RestServlet#getDescription(RestRequest)} with this object.
+ * Equivalent to calling {@link RestInfoProvider#getDescription(RestRequest)} with this object.
*
* @return The localized servlet description.
*/
public String getServletDescription() {
- return servlet.getDescription(this);
+ return context.getInfoProvider().getDescription(this);
}
/**
* Returns the localized method summary.
* <p>
- * Equivalent to calling {@link RestServlet#getMethodSummary(String, RestRequest)} with this object.
+ * Equivalent to calling {@link RestInfoProvider#getMethodSummary(String, RestRequest)} with this object.
*
* @return The localized method description.
*/
public String getMethodSummary() {
- return servlet.getMethodSummary(javaMethod.getName(), this);
+ return context.getInfoProvider().getMethodSummary(javaMethod.getName(), this);
}
/**
* Returns the localized method description.
* <p>
- * Equivalent to calling {@link RestServlet#getMethodDescription(String, RestRequest)} with this object.
+ * Equivalent to calling {@link RestInfoProvider#getMethodDescription(String, RestRequest)} with this object.
*
* @return The localized method description.
*/
public String getMethodDescription() {
- return servlet.getMethodDescription(javaMethod.getName(), this);
+ return context.getInfoProvider().getMethodDescription(javaMethod.getName(), this);
}
@@ -1713,14 +1717,14 @@ public final class RestRequest extends HttpServletRequestWrapper {
}
/**
- * Shortcut method for calling {@link RestServlet#getMessage(Locale, String, Object...)} based on the request locale.
+ * Shortcut method for calling {@link MessageBundle#getString(Locale, String, Object...)} based on the request locale.
*
* @param key The message key.
* @param args Optional {@link MessageFormat}-style arguments.
* @return The localized message.
*/
public String getMessage(String key, Object...args) {
- return servlet.getMessage(getLocale(), key, args);
+ return context.getMessages().getString(getLocale(), key, args);
}
/**
@@ -1729,7 +1733,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
* @return The resource bundle. Never <jk>null</jk>.
*/
public MessageBundle getResourceBundle() {
- return servlet.getMessages(getLocale());
+ return context.getMessages().getBundle(getLocale());
}
/**
@@ -1740,8 +1744,8 @@ public final class RestRequest extends HttpServletRequestWrapper {
*
* @return The servlet handling the request.
*/
- public RestServlet getServlet() {
- return servlet;
+ public RestContext getContext() {
+ return context;
}
/**
@@ -1772,13 +1776,13 @@ public final class RestRequest extends HttpServletRequestWrapper {
}
/**
- * Returns the variable resolver session for this request using session objects created by {@link RestServlet#getSessionObjects(RestRequest)}.
+ * Returns the variable resolver session for this request using session objects created by {@link RestCallHandler#getSessionObjects(RestRequest)}.
*
* @return The variable resolver for this request.
*/
public VarResolverSession getVarResolverSession() {
if (varSession == null)
- varSession = servlet.getVarResolver().createSession(servlet.getSessionObjects(this));
+ varSession = context.getVarResolver().createSession(context.getCallHandler().getSessionObjects(this));
return varSession;
}
@@ -1803,7 +1807,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
* @throws IOException
*/
public ReaderResource getReaderResource(String name, boolean resolveVars, MediaType mediaType) throws IOException {
- String s = servlet.getResourceAsString(name, getLocale());
+ String s = context.getResourceAsString(name, getLocale());
if (s == null)
return null;
ReaderResource.Builder b = new ReaderResource.Builder().mediaType(mediaType).contents(s);
@@ -1813,8 +1817,8 @@ public final class RestRequest extends HttpServletRequestWrapper {
}
/**
- * Same as {@link #getReaderResource(String, boolean, MediaType)} except uses {@link RestServlet#getMimetypesFileTypeMap()}
- * to determine the media type.
+ * Same as {@link #getReaderResource(String, boolean, MediaType)} except uses the resource mime-type map
+ * constructed using {@link RestConfig#addMimeTypes(String...)} to determine the media type.
*
* @param name The name of the resource (i.e. the value normally passed to {@link Class#getResourceAsStream(String)}.
* @param resolveVars If <jk>true</jk>, any {@link org.apache.juneau.rest.annotation.Parameter} variables will be resolved by the variable resolver returned
@@ -1823,7 +1827,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
* @throws IOException
*/
public ReaderResource getReaderResource(String name, boolean resolveVars) throws IOException {
- return getReaderResource(name, resolveVars, MediaType.forString(servlet.getMimetypesFileTypeMap().getContentType(name)));
+ return getReaderResource(name, resolveVars, MediaType.forString(context.getMediaTypeForName(name)));
}
/**
@@ -1834,7 +1838,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
* @throws IOException
*/
public ReaderResource getReaderResource(String name) throws IOException {
- return getReaderResource(name, false, MediaType.forString(servlet.getMimetypesFileTypeMap().getContentType(name)));
+ return getReaderResource(name, false, MediaType.forString(context.getMediaTypeForName(name)));
}
/**
@@ -1842,9 +1846,9 @@ public final class RestRequest extends HttpServletRequestWrapper {
*
* @return The config file associated with the servlet, or <jk>null</jk> if servlet does not have a config file associated with it.
*/
- public ConfigFile getConfig() {
+ public ConfigFile getConfigFile() {
if (cf == null)
- cf = servlet.getConfig().getResolving(getVarResolverSession());
+ cf = context.getConfigFile().getResolving(getVarResolverSession());
return cf;
}
@@ -1855,7 +1859,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
*/
public Swagger getSwagger() {
if (swagger == null)
- swagger = servlet.getSwagger(this);
+ swagger = context.getInfoProvider().getSwagger(this);
return swagger;
}
@@ -1871,7 +1875,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
*/
protected Swagger getSwaggerFromFile() {
if (fileSwagger == null)
- fileSwagger = servlet.getSwaggerFromFile(this.getLocale());
+ fileSwagger = context.getInfoProvider().getSwaggerFromFile(this.getLocale());
if (fileSwagger == null)
fileSwagger = Swagger.NULL;
return fileSwagger == Swagger.NULL ? null : fileSwagger;
@@ -1895,7 +1899,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
sb.append(getBodyAsString()).append("\n");
} catch (Exception e1) {
sb.append(e1.getLocalizedMessage());
- servlet.log(WARNING, e1, "Error occurred while trying to read debug input.");
+ context.getLogger().log(WARNING, e1, "Error occurred while trying to read debug input.");
}
}
return sb.toString();
@@ -1942,11 +1946,11 @@ public final class RestRequest extends HttpServletRequestWrapper {
String ce = getHeader("content-encoding");
if (! (ce == null || ce.isEmpty())) {
ce = ce.trim();
- encoder = servlet.getEncoders().getEncoder(ce);
+ encoder = encoders.getEncoder(ce);
if (encoder == null)
throw new RestException(SC_UNSUPPORTED_MEDIA_TYPE,
"Unsupported encoding in request header ''Content-Encoding'': ''{0}''\n\tSupported codings: {1}",
- getHeader("content-encoding"), servlet.getEncoders().getSupportedEncodings()
+ getHeader("content-encoding"), encoders.getSupportedEncodings()
);
}
@@ -1966,7 +1970,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
*/
private String getOverriddenHeader(String name) {
String h = null;
- if (servlet.context.allowHeaderParams)
+ if (context.isAllowHeaderParams())
h = getQueryParameter(name);
if (h != null)
return h;
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
new file mode 100644
index 0000000..7989eb9
--- /dev/null
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
@@ -0,0 +1,80 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Class used to resolve {@link Class} objects to instances.
+ * <p>
+ * Used to convert classes defined via {@link RestResource#children() @RestResource.children()} into child instances.
+ * <p>
+ * Subclasses can be created to provide customized resource resolution.
+ * These can be associated with REST resources in one of the following ways:
+ * <ul>
+ * <li>{@link RestResource#resourceResolver() @RestResource.resourceResolver()} annotation.
+ * <li>{@link RestConfig#setResourceResolver(Class)}/{@link RestConfig#setResourceResolver(RestResourceResolver)} methods.
+ * </ul>
+ * <p>
+ * The default implementation simply instantiates the class using one of the following constructors:
+ * <ul>
+ * <li><code><jk>public</jk> T(RestConfig)</code>
+ * <li><code><jk>public</jk> T()</code>
+ * </ul>
+ * The former constructor can be used to get access to the {@link RestConfig} object to get access to the
+ * config file and initialization information or make programmatic modifications to the resource before
+ * full initialization.
+ * <p>
+ * Non-<code>RestServlet</code> classes can also add the following two methods to get access to the
+ * {@link RestConfig} and {@link RestContext} objects:
+ * <ul>
+ * <li><jk>public void</jk> init(RestConfig);</code>
+ * <li><jk>public void</jk> init(RestContext);</code>
+ * </ul>
+ */
+public class RestResourceResolver {
+
+ /**
+ * Denotes the default resolver.
+ */
+ public static final class DEFAULT extends RestResourceResolver {}
+
+ /**
+ * Resolves the specified class to a resource object.
+ * <p>
+ * Subclasses can override this method to provide their own custom resolution.
+ * <p>
+ * The default implementation simply creates a new class instance using {@link Class#newInstance()}.
+ *
+ * @param c The class to resolve.
+ * @param config The initialization configuration for the resource.
+ * @return The instance of that class.
+ * @throws RestServletException If class could not be resolved.
+ */
+ public Object resolve(Class<?> c, RestConfig config) throws RestServletException {
+ try {
+ Constructor<?> c1 = ClassUtils.findPublicConstructor(c, RestConfig.class);
+ if (c1 != null)
+ return c1.newInstance(config);
+ c1 = ClassUtils.findPublicConstructor(c);
+ if (c1 != null)
+ return c1.newInstance();
+ } catch (Exception e) {
+ throw new RestServletException("Could not instantiate resource class ''{0}''", c.getName()).initCause(e);
+ }
+ throw new RestServletException("Could not find public constructor for class ''{0}''.", c);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/07843d64/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
index 3fa5398..637dc7e 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -13,6 +13,7 @@
package org.apache.juneau.rest;
import java.io.*;
+import java.nio.charset.*;
import java.util.*;
import javax.servlet.*;
@@ -55,24 +56,22 @@ public final class RestResponse extends HttpServletResponseWrapper {
SerializerGroup serializerGroup;
UrlEncodingSerializer urlEncodingSerializer; // The serializer used to convert arguments passed into Redirect objects.
private EncoderGroup encoders;
- private final RestServlet servlet;
private ServletOutputStream os;
/**
* Constructor.
*/
- RestResponse(RestServlet servlet, RestRequest req, HttpServletResponse res) {
+ RestResponse(RestContext context, RestRequest req, HttpServletResponse res) {
super(res);
this.request = req;
- this.servlet = servlet;
- for (Map.Entry<String,Object> e : servlet.getDefaultResponseHeaders().entrySet())
+ for (Map.Entry<String,Object> e : context.getDefaultResponseHeaders().entrySet())
setHeader(e.getKey(), e.getValue().toString());
try {
String passThroughHeaders = req.getHeader("x-response-headers");
if (passThroughHeaders != null) {
- ObjectMap m = servlet.getUrlEncodingParser().parseParameter(passThroughHeaders, ObjectMap.class);
+ ObjectMap m = context.getUrlEncodingParser().parseParameter(passThroughHeaders, ObjectMap.class);
for (Map.Entry<String,Object> e : m.entrySet())
setHeader(e.getKey(), e.getValue().toString());
}
@@ -101,7 +100,7 @@ public final class RestResponse extends HttpServletResponseWrapper {
MediaType mt = r.getMediaType();
if (mt.getType().equals("*"))
charset = defaultCharset;
- else if (RestServlet.availableCharsets.containsKey(mt.getType()))
+ else if (Charset.isSupported(mt.getType()))
charset = mt.getType();
if (charset != null)
break;
@@ -138,7 +137,7 @@ public final class RestResponse extends HttpServletResponseWrapper {
* @throws RestServletException
*/
public List<String> getSupportedEncodings() throws RestServletException {
- return servlet.getEncoders().getSupportedEncodings();
+ return encoders.getSupportedEncodings();
}
/**