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 2020/03/15 22:55:18 UTC
[juneau] branch master updated: JUNEAU-186
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 015fb11 JUNEAU-186
015fb11 is described below
commit 015fb1195a7010152f18ffc10bd7ae73ffc15cbb
Author: JamesBognar <ja...@apache.org>
AuthorDate: Sun Mar 15 18:55:03 2020 -0400
JUNEAU-186
REST classes should allow themselves to implement helper classes.
---
juneau-doc/docs/ReleaseNotes/8.1.4.html | 61 +++
.../juneau/rest/mock2/MockServletRequest.java | 2 +-
.../apache/juneau/rest/BasicRestCallHandler.java | 4 +-
.../org/apache/juneau/rest/RestCallHandler.java | 2 +-
.../java/org/apache/juneau/rest/RestContext.java | 10 +-
.../java/org/apache/juneau/rest/RestServlet.java | 407 ++++++++++++++++++++-
.../apache/juneau/rest/annotation/HookEvent.java | 2 +-
.../juneau/rest/mock/MockServletRequest.java | 2 +-
8 files changed, 475 insertions(+), 15 deletions(-)
diff --git a/juneau-doc/docs/ReleaseNotes/8.1.4.html b/juneau-doc/docs/ReleaseNotes/8.1.4.html
index 4fc0812..df120ac 100644
--- a/juneau-doc/docs/ReleaseNotes/8.1.4.html
+++ b/juneau-doc/docs/ReleaseNotes/8.1.4.html
@@ -153,6 +153,67 @@
<h5 class='topic w800'>juneau-rest-server</h5>
<ul class='spaced-list'>
+ <li>
+ {@link oajr.annotation.Rest}-annotated classes can now implement the following interfaces directly instead of having
+ to define secondary classes and hook them up through annotations:
+ <ul>
+ <li class='jic'>{@link oajr.RestCallHandler} - Normally defined through {@link oajr.annotation.Rest#callHandler() @Rest.callHandler()}.
+ <li class='jic'>{@link oajr.RestInfoProvider} - Normally defined through {@link oajr.annotation.Rest#infoProvider() @Rest.infoProvider()}.
+ <li class='jic'>{@link oajr.RestCallLogger} - Normally defined through {@link oajr.annotation.Rest#callLogger() @Rest.callLogger()}.
+ </ul>
+ <li>
+ {@link oajr.RestServlet} now implements the {@link oajr.RestCallHandler}, {@link oajr.RestInfoProvider}, and {@link oajr.RestCallLogger}
+ interfaces directly and provides the same functionality as {@link oajr.BasicRestCallHandler}, {@link oajr.BasicRestInfoProvider}, and
+ {@link oajr.BasicRestCallLogger}. This makes it easier to tweak these methods without having to implement your own classes.
+ <br>The methods added for {@link oajr.RestCallHandler} are:
+ <ul>
+ <li class='jac'>{@link oaj.RestServlet}
+ <ul>
+ <li class='jm'>{@link oaj.RestServlet#execute(HttpServletRequest, HttpServletResponse) execute(HttpServletRequest, HttpServletResponse)}
+ <li class='jm'>{@link oaj.RestServlet#createCall(HttpServletRequest, HttpServletResponse) createCall(HttpServletRequest, HttpServletResponse)}
+ <li class='jm'>{@link oaj.RestServlet#createRequest(RestCall) createRequest(RestCall)}
+ <li class='jm'>{@link oaj.RestServlet#createResponse(RestCall) createResponse(RestCall)}
+ <li class='jm'>{@link oaj.RestServlet#handleResponse(RestCall) handleResponse(RestCall)}
+ <li class='jm'>{@link oaj.RestServlet#handleNotFound(RestCall) handleNotFound(RestCall)}
+ <li class='jm'>{@link oaj.RestServlet#handleError(RestCall,Throwable) handleError(RestCall,Throwable)}
+ <li class='jm'>{@link oaj.RestServlet#convertThrowable(Throwable) throwable(Throwable)}
+ <li class='jm'>{@link oaj.RestServlet#getSessionObjects(RestRequest req, RestResponse res) getSessionObjects(RestRequest,RestResponse)}
+ </ul>
+ </ul>
+ <br>The methods added for {@link oajr.RestInfoProvider} are:
+ <ul>
+ <li class='jac'>{@link oaj.RestServlet}
+ <ul>
+ <li class='jm'>{@link oaj.RestServlet#getSwagger(RestRequest) getSwagger(RestRequest)}
+ <li class='jm'>{@link oaj.RestServlet#getSiteName(RestRequest) getSiteName(RestRequest)}
+ <li class='jm'>{@link oaj.RestServlet#getTitle(RestRequest) getTitle(RestRequest)}
+ <li class='jm'>{@link oaj.RestServlet#getDescription(RestRequest) getDescription(RestRequest)}
+ <li class='jm'>{@link oaj.RestServlet#getMethodSummary(Method,RestRequest) getMethodSummary(Method,RestRequest)}
+ <li class='jm'>{@link oaj.RestServlet#getMethodDescription(Method,RestRequest) getMethodDescription(Method,RestRequest)}
+ </ul>
+ </ul>
+ <br>The methods added for {@link oajr.RestCallLogger} are:
+ <ul>
+ <li class='jac'>{@link oaj.RestServlet}
+ <ul>
+ <li class='jm'>{@link oaj.RestServlet#log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse) log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse)}
+ </ul>
+ </ul>
+ <li>
+ Added the following convenience hook methods on the {@link RestServlet} class:
+ <ul>
+ <li class='jac'>{@link oaj.RestServlet}
+ <ul>
+ <li class='jm'>{@link oaj.RestServlet#onInit(RestContextBuilder) onInit(RestContextBuilder)}
+ <li class='jm'>{@link oaj.RestServlet#onPostInit(RestContext) onPostInit(RestContext)}
+ <li class='jm'>{@link oaj.RestServlet#onPostInitChildFirst(RestContext) onPostInitChildFirst(RestContext)}
+ <li class='jm'>{@link oaj.RestServlet#onDestroy(RestContext) onDestroy(RestContext)}
+ <li class='jm'>{@link oaj.RestServlet#onStartCall(HttpServletRequest,HttpServletResponse) onStartCall(HttpServletRequest,HttpServletResponse)}
+ <li class='jm'>{@link oaj.RestServlet#onPreCall(RestRequest,RestResponse) onPreCall(RestRequest,RestResponse)}
+ <li class='jm'>{@link oaj.RestServlet#onPostCall(RestRequest,RestResponse) onPostCall(RestRequest,RestResponse)}
+ <li class='jm'>{@link oaj.RestServlet#onEndCall(HttpServletRequest,HttpServletResponse) onEndCall(HttpServletRequest,HttpServletResponse)}
+ </ul>
+ </ul>
</ul>
<h5 class='topic w800'>juneau-rest-server-springboot</h5>
diff --git a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletRequest.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletRequest.java
index 132c78c..e8f332c 100644
--- a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletRequest.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletRequest.java
@@ -281,7 +281,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
@Override /* MockHttpRequest */
public MockServletResponse execute() throws ServletException, IOException {
MockServletResponse res = MockServletResponse.create();
- restContext.getCallHandler().service(this, res);
+ restContext.getCallHandler().execute(this, res);
// If the status isn't set, something's broken.
if (res.getStatus() == 0)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
index 9c6e4a1..9a4be75 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
@@ -86,7 +86,7 @@ public class BasicRestCallHandler implements RestCallHandler {
* @throws IOException Thrown by underlying stream.
*/
@Override /* RestCallHandler */
- public void service(HttpServletRequest r1, HttpServletResponse r2) throws ServletException, IOException {
+ public void execute(HttpServletRequest r1, HttpServletResponse r2) throws ServletException, IOException {
RestCall call = createCall(r1, r2);
@@ -127,7 +127,7 @@ public class BasicRestCallHandler implements RestCallHandler {
HttpServletRequest childRequest = new OverrideableHttpServletRequest(call.getRequest())
.pathInfo(nullIfEmpty(urlDecode(uppm.getSuffix())))
.servletPath(call.getServletPath() + uppm.getPrefix());
- rc.getCallHandler().service(childRequest, call.getResponse());
+ rc.getCallHandler().execute(childRequest, call.getResponse());
} else {
call.debug(isDebug(call)).status(SC_NOT_FOUND).finish();
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
index 6946f12..9d24fe7 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
@@ -45,7 +45,7 @@ public interface RestCallHandler {
* @throws ServletException Error occurred.
* @throws IOException Thrown by underlying stream.
*/
- public void service(HttpServletRequest r1, HttpServletResponse r2) throws ServletException, IOException;
+ public void execute(HttpServletRequest r1, HttpServletResponse r2) throws ServletException, IOException;
/**
* Wraps an incoming servlet request/response pair into a single {@link RestCall} object.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 0472e78..c01ea17 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -3668,7 +3668,8 @@ public final class RestContext extends BeanContext {
this.stackTraceDb = new StackTraceDatabase(callLoggerConfig.getStackTraceHashingTimeout(), RestMethodContext.class);
- callLogger = getInstanceProperty(REST_callLogger, resource, RestCallLogger.class, BasicRestCallLogger.class, resourceResolver, this);
+ Object defaultRestCallLogger = resource instanceof RestCallLogger ? resource : BasicRestCallLogger.class;
+ callLogger = getInstanceProperty(REST_callLogger, resource, RestCallLogger.class, defaultRestCallLogger, resourceResolver, this);
properties = builder.properties;
serializers =
@@ -3983,8 +3984,11 @@ public final class RestContext extends BeanContext {
childResources.put(path, rc2);
}
- callHandler = getInstanceProperty(REST_callHandler, resource, RestCallHandler.class, BasicRestCallHandler.class, resourceResolver, this);
- infoProvider = getInstanceProperty(REST_infoProvider, resource, RestInfoProvider.class, BasicRestInfoProvider.class, resourceResolver, this);
+ Object defaultRestCallHandler = resource instanceof RestCallHandler ? resource : BasicRestCallHandler.class;
+ callHandler = getInstanceProperty(REST_callHandler, resource, RestCallHandler.class, defaultRestCallHandler, resourceResolver, this);
+
+ Object defaultRestInfoProvider = resource instanceof RestInfoProvider ? resource : BasicRestInfoProvider.class;
+ infoProvider = getInstanceProperty(REST_infoProvider, resource, RestInfoProvider.class, defaultRestInfoProvider, resourceResolver, this);
} catch (HttpException e) {
_initException = e;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
index 3d75307..5fe912a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
@@ -16,9 +16,12 @@ import static java.util.logging.Level.*;
import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.rest.HttpRuntimeException.*;
+import static org.apache.juneau.rest.annotation.HookEvent.*;
import java.io.*;
+import java.lang.reflect.Method;
import java.text.*;
+import java.util.*;
import java.util.logging.*;
import javax.servlet.*;
@@ -27,6 +30,7 @@ import javax.servlet.http.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.reflect.*;
import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.dto.swagger.*;
import org.apache.juneau.http.exception.*;
/**
@@ -36,7 +40,7 @@ import org.apache.juneau.http.exception.*;
* <li class='link'>{@doc juneau-rest-server.Instantiation.RestServlet}
* </ul>
*/
-public abstract class RestServlet extends HttpServlet {
+public abstract class RestServlet extends HttpServlet implements RestCallHandler, RestInfoProvider, RestCallLogger {
private static final long serialVersionUID = 1L;
@@ -46,7 +50,9 @@ public abstract class RestServlet extends HttpServlet {
private boolean isInitialized = false; // Should not be volatile.
private volatile RestResourceResolver resourceResolver;
private JuneauLogger logger = JuneauLogger.getLogger(getClass());
-
+ private RestCallHandler callHandler;
+ private RestInfoProvider infoProvider;
+ private RestCallLogger callLogger;
@Override /* Servlet */
public final synchronized void init(ServletConfig servletConfig) throws ServletException {
@@ -89,6 +95,9 @@ public abstract class RestServlet extends HttpServlet {
this.builder = context.builder;
this.context = context;
isInitialized = true;
+ callHandler = new BasicRestCallHandler(context);
+ infoProvider = new BasicRestInfoProvider(context);
+ callLogger = new BasicRestCallLogger(context);
context.postInit();
}
@@ -176,12 +185,33 @@ public abstract class RestServlet extends HttpServlet {
@Override /* GenericServlet */
public void log(String msg) {
- logger.info(msg);
+ super.log(msg);
}
@Override /* GenericServlet */
public void log(String msg, Throwable cause) {
- logger.info(cause, msg);
+ super.log(msg, cause);
+ }
+
+ /**
+ * Convenience method for calling {@link #log(String)} with message arguments.
+ *
+ * @param msg The message containing {@link MessageFormat}-style arguments.
+ * @param args The arguments.
+ */
+ public void log(String msg, Object...args) {
+ super.log(args.length == 0 ? msg : MessageFormat.format(msg, args));
+ }
+
+ /**
+ * Convenience method for calling {@link #log(String)} with message arguments.
+ *
+ * @param msg The message containing {@link MessageFormat}-style arguments.
+ * @param cause The cause.
+ * @param args The arguments.
+ */
+ public void log(String msg, Throwable cause, Object...args) {
+ super.log(args.length == 0 ? msg : MessageFormat.format(msg, args), cause);
}
/**
@@ -240,7 +270,7 @@ public abstract class RestServlet extends HttpServlet {
isInitialized = true;
}
- context.getCallHandler().service(r1, r2);
+ context.getCallHandler().execute(r1, r2);
} catch (Throwable e) {
r2.sendError(SC_INTERNAL_SERVER_ERROR, e.getLocalizedMessage());
@@ -255,7 +285,280 @@ public abstract class RestServlet extends HttpServlet {
}
//-----------------------------------------------------------------------------------------------------------------
- // Request-time methods.
+ // Hook events
+ //-----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Method that gets called during servlet initialization.
+ *
+ * <p>
+ * This method is called from within the {@link Servlet#init(ServletConfig)} method after the {@link RestContextBuilder}
+ * object has been created and initialized with the annotations defined on the class, but before the
+ * {@link RestContext} object has been created.
+ *
+ * <p>
+ * An example of this is the <c>PetStoreResource</c> class that uses an init method to perform initialization
+ * of an internal data structure.
+ *
+ * <h5 class='figure'>Example:</h5>
+ * <p class='bcode w800'>
+ * <ja>@Rest</ja>(...)
+ * <jk>public class</jk> PetStoreResource <jk>extends</jk> ResourceJena {
+ *
+ * <jc>// Our database.</jc>
+ * <jk>private</jk> Map<Integer,Pet> <jf>petDB</jf>;
+ *
+ * <ja>@Override</ja>
+ * <jk>public void</jk> onInit(RestContextBuilder builder) <jk>throws</jk> Exception {
+ * <jc>// Load our database from a local JSON file.</jc>
+ * <jf>petDB</jf> = JsonParser.<jsf>DEFAULT</jsf>.parse(getClass().getResourceAsStream(<js>"PetStore.json"</js>), LinkedHashMap.<jk>class</jk>, Integer.<jk>class</jk>, Pet.<jk>class</jk>);
+ * }
+ * }
+ * </p>
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple INIT methods can be defined on a class.
+ * <br>INIT methods on parent classes are invoked before INIT methods on child classes.
+ * <br>The order of INIT method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * The method can throw any exception causing initialization of the servlet to fail.
+ * </ul>
+ *
+ * @param builder Context builder which can be used to configure the servlet.
+ * @throws Exception Any exception thrown will cause servlet to fail startup.
+ */
+ @RestHook(INIT)
+ public void onInit(RestContextBuilder builder) throws Exception {}
+
+ /**
+ * Method that gets called immediately after servlet initialization.
+ *
+ * <p>
+ * This method is called from within the {@link Servlet#init(ServletConfig)} method after the {@link RestContext}
+ * object has been created.
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple POST_INIT methods can be defined on a class.
+ * <br>POST_INIT methods on parent classes are invoked before POST_INIT methods on child classes.
+ * <br>The order of POST_INIT method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * The method can throw any exception causing initialization of the servlet to fail.
+ * </ul>
+ *
+ * @param context The initialized context object.
+ * @throws Exception Any exception thrown will cause servlet to fail startup.
+ */
+ @RestHook(POST_INIT)
+ public void onPostInit(RestContext context) throws Exception {}
+
+ /**
+ * Identical to {@link #onPostInit(RestContext)} except the order of execution is child-resources first.
+ *
+ * <p>
+ * Use this method if you need to perform any kind of initialization on child resources before the parent resource.
+ *
+ * <p>
+ * This method is called from within the {@link Servlet#init(ServletConfig)} method after the {@link RestContext}
+ * object has been created and after the {@link #POST_INIT} methods have been called.
+ *
+ * <p>
+ * The only valid parameter type for this method is {@link RestContext} which can be used to retrieve information
+ * about the servlet.
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple POST_INIT_CHILD_FIRST methods can be defined on a class.
+ * <br>POST_INIT_CHILD_FIRST methods on parent classes are invoked before POST_INIT_CHILD_FIRST methods on child classes.
+ * <br>The order of POST_INIT_CHILD_FIRST method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * The method can throw any exception causing initialization of the servlet to fail.
+ * </ul>
+ *
+ * @param context The initialized context object.
+ * @throws Exception Any exception thrown will cause servlet to fail startup.
+ */
+ @RestHook(POST_INIT_CHILD_FIRST)
+ public void onPostInitChildFirst(RestContext context) throws Exception {}
+
+ /**
+ * Method that gets called during servlet destroy.
+ *
+ * <p>
+ * This method is called from within the {@link Servlet#destroy()}.
+ *
+ * <h5 class='figure'>Example:</h5>
+ * <p class='bcode w800'>
+ * <ja>@Rest</ja>(...)
+ * <jk>public class</jk> PetStoreResource <jk>extends</jk> ResourceJena {
+ *
+ * <jc>// Our database.</jc>
+ * <jk>private</jk> Map<Integer,Pet> <jf>petDB</jf>;
+ *
+ * <ja>@Override</ja>
+ * <jk>public void</jk> onDestroy(RestContext context) {
+ * <jf>petDB</jf> = <jk>null</jk>;
+ * }
+ * }
+ * </p>
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple DESTROY methods can be defined on a class.
+ * <br>DESTROY methods on child classes are invoked before DESTROY methods on parent classes.
+ * <br>The order of DESTROY method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * In general, destroy methods should not throw any exceptions, although if any are thrown, the stack trace will be
+ * printed to <c>System.err</c>.
+ * </ul>
+ *
+ * @param context The initialized context object.
+ * @throws Exception Any exception thrown will cause stack trace to be printed to <c>System.err</c>.
+ */
+ @RestHook(DESTROY)
+ public void onDestroy(RestContext context) throws Exception {}
+
+ /**
+ * A method that is called immediately after the <c>HttpServlet.service(HttpServletRequest, HttpServletResponse)</c>
+ * method is called.
+ *
+ * <p>
+ * Note that you only have access to the raw request and response objects at this point.
+ *
+ * <h5 class='figure'>Example:</h5>
+ * <p class='bcode w800'>
+ * <ja>@Rest</ja>(...)
+ * <jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {
+ *
+ * <jc>// Add a request attribute to all incoming requests.</jc>
+ * <ja>@Override</ja>
+ * <jk>public void</jk> onStartCall(HttpServletRequest req, HttpServletResponse res) {
+ * req.setAttribute(<js>"foobar"</js>, <jk>new</jk> FooBar());
+ * }
+ * }
+ * </p>
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple START_CALL methods can be defined on a class.
+ * <br>START_CALL methods on parent classes are invoked before START_CALL methods on child classes.
+ * <br>The order of START_CALL method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * The method can throw any exception.
+ * <br>{@link HttpException HttpExceptions} can be thrown to cause a particular HTTP error status code.
+ * <br>All other exceptions cause an HTTP 500 error status code.
+ * </ul>
+ *
+ * @param req The HTTP servlet request object.
+ * @param res The HTTP servlet response object.
+ * @throws Exception Any exception.
+ */
+ @RestHook(START_CALL)
+ public void onStartCall(HttpServletRequest req, HttpServletResponse res) throws Exception {}
+
+ /**
+ * Method that gets called immediately before the <ja>@RestMethod</ja> annotated method gets called.
+ *
+ * <p>
+ * At this point, the {@link RestRequest} object has been fully initialized, and all {@link RestGuard} and
+ * {@link RestMatcher} objects have been called.
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple PRE_CALL methods can be defined on a class.
+ * <br>PRE_CALL methods on parent classes are invoked before PRE_CALL methods on child classes.
+ * <br>The order of PRE_CALL method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * The method can throw any exception.
+ * <br>{@link HttpException HttpExceptions} can be thrown to cause a particular HTTP error status code.
+ * <br>All other exceptions cause an HTTP 500 error status code.
+ * <li>
+ * It's advisable not to mess around with the HTTP body itself since you may end up consuming the body
+ * before the actual REST method has a chance to use it.
+ * </ul>
+ *
+ * @param req The request object.
+ * @param res The response object.
+ * @throws Exception Any exception.
+ */
+ @RestHook(PRE_CALL)
+ public void onPreCall(RestRequest req, RestResponse res) throws Exception {}
+
+ /**
+ * Method that gets called immediately after the <ja>@RestMethod</ja> annotated method gets called.
+ *
+ * <p>
+ * At this point, the output object returned by the method call has been set on the response, but
+ * {@link RestConverter RestConverters} have not yet been executed and the response has not yet been written.
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple POST_CALL methods can be defined on a class.
+ * <br>POST_CALL methods on parent classes are invoked before POST_CALL methods on child classes.
+ * <br>The order of POST_CALL method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * The method can throw any exception, although at this point it is too late to set an HTTP error status code.
+ * </ul>
+ *
+ * @param req The request object.
+ * @param res The response object.
+ * @throws Exception Any exception.
+ */
+ @RestHook(POST_CALL)
+ public void onPostCall(RestRequest req, RestResponse res) throws Exception {}
+
+ /**
+ * Method that gets called right before we exit the servlet service method.
+ *
+ * <p>
+ * At this point, the output has been written and flushed.
+ *
+ * <p>
+ * The following attributes are set on the {@link HttpServletRequest} object that can be useful for logging purposes:
+ * <ul>
+ * <li><js>"Exception"</js> - Any exceptions thrown during the request.
+ * <li><js>"ExecTime"</js> - Execution time of the request.
+ * </ul>
+ *
+ * <ul class='notes'>
+ * <li>
+ * The default implementation of this method is a no-op.
+ * <li>
+ * Multiple END_CALL methods can be defined on a class.
+ * <br>END_CALL methods on parent classes are invoked before END_CALL methods on child classes.
+ * <br>The order of END_CALL method invocations within a class is alphabetical, then by parameter count, then by parameter types.
+ * <li>
+ * The method can throw any exception, although at this point it is too late to set an HTTP error status code.
+ * <li>
+ * Note that if you override a parent method, you probably need to call <code><jk>super</jk>.parentMethod(...)</code>.
+ * <br>The method is still considered part of the parent class for ordering purposes even though it's
+ * overridden by the child class.
+ * </ul>
+ *
+ * @param req The HTTP servlet request object.
+ * @param res The HTTP servlet response object.
+ * @throws Exception Any exception.
+ */
+ @RestHook(END_CALL)
+ public void onEndCall(HttpServletRequest req, HttpServletResponse res) throws Exception {}
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // Other methods.
//-----------------------------------------------------------------------------------------------------------------
/**
@@ -275,4 +578,96 @@ public abstract class RestServlet extends HttpServlet {
public synchronized RestResponse getResponse() {
return getContext().getResponse();
}
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // RestCallHandler
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Override /* RestCallHandler */
+ public void execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
+ callHandler.execute(req, res);
+ }
+
+ @Override /* RestCallHandler */
+ public RestCall createCall(HttpServletRequest req, HttpServletResponse res) {
+ return callHandler.createCall(req, res);
+ }
+
+ @Override /* RestCallHandler */
+ public RestRequest createRequest(RestCall call) throws ServletException {
+ return callHandler.createRequest(call);
+ }
+
+ @Override /* RestCallHandler */
+ public RestResponse createResponse(RestCall call) throws ServletException {
+ return callHandler.createResponse(call);
+ }
+
+ @Override /* RestCallHandler */
+ public void handleResponse(RestCall call) throws Exception {
+ callHandler.handleResponse(call);
+ }
+
+ @Override /* RestCallHandler */
+ public void handleNotFound(RestCall call) throws Exception {
+ callHandler.handleNotFound(call);
+ }
+
+ @Override /* RestCallHandler */
+ public void handleError(RestCall call, Throwable e) throws Exception {
+ callHandler.handleError(call, e);
+ }
+
+ @Override /* RestCallHandler */
+ public Throwable convertThrowable(Throwable t) {
+ return callHandler.convertThrowable(t);
+ }
+
+ @Override /* RestCallHandler */
+ public Map<String,Object> getSessionObjects(RestRequest req, RestResponse res) {
+ return callHandler.getSessionObjects(req, res);
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // RestInfoProvider
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Override /* RestInfoProvider */
+ public Swagger getSwagger(RestRequest req) throws Exception {
+ return infoProvider.getSwagger(req);
+ }
+
+ @Override /* RestInfoProvider */
+ public String getSiteName(RestRequest req) throws Exception {
+ return infoProvider.getSiteName(req);
+ }
+
+ @Override /* RestInfoProvider */
+ public String getTitle(RestRequest req) throws Exception {
+ return infoProvider.getTitle(req);
+ }
+
+ @Override /* RestInfoProvider */
+ public String getDescription(RestRequest req) throws Exception {
+ return infoProvider.getDescription(req);
+ }
+
+ @Override /* RestInfoProvider */
+ public String getMethodSummary(Method method, RestRequest req) throws Exception {
+ return infoProvider.getMethodSummary(method, req);
+ }
+
+ @Override /* RestInfoProvider */
+ public String getMethodDescription(Method method, RestRequest req) throws Exception {
+ return infoProvider.getMethodDescription(method, req);
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // RestCallLogger
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Override /* RestCallLogger */
+ public void log(RestCallLoggerConfig config, HttpServletRequest req, HttpServletResponse res) {
+ callLogger.log(config, req, res);
+ }
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HookEvent.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HookEvent.java
index cf12769..79889f7 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HookEvent.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HookEvent.java
@@ -39,7 +39,7 @@ import org.apache.juneau.utils.*;
public enum HookEvent {
/**
- * Identifies a method that should be called immediately after the <c>HttpServlet.service(HttpServletRequest, HttpServletResponse)</c>
+ * Identifies a method that is called immediately after the <c>HttpServlet.service(HttpServletRequest, HttpServletResponse)</c>
* method is called.
*
* <p>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
index 575b301..173fb5d 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
@@ -217,7 +217,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
@Override /* MockHttpRequest */
public MockServletResponse execute() throws Exception {
MockServletResponse res = MockServletResponse.create();
- restContext.getCallHandler().service(this, res);
+ restContext.getCallHandler().execute(this, res);
// If the status isn't set, something's broken.
if (res.getStatus() == 0)