How are Spring HandlerInterceptors instantiated? - java

Is there a new instance of Spring HandlerInterceptors for each request?
I have an interceptor in Spring, which has a class field.
public class MyInterceptor extends HandlerInterceptorAdapter {
Private boolean state = false;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
state = true;
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
if (state == true) {
System.out.println("Success");
}
}
If this interceptor is used will it always print "Success"? (No matter how many threads are doing this at the same time?)

How the interceptor is instantiated depends how you configiure it as a bean. If you don't explicitly specify a scope for the bean, then it'll be a singleton like any other bean, and so the state field will be shared by all requests.
In this sense, interceptors are no different to controllers - be very careful about putting conversation state in them, since the objects will be shared across requests.
if you really need a stateful interceptor and you don't want to share the state between requests, then use a request-scoped bean.

Related

Spring Boot - determining a sub-domain (with wildcard)?

New to Spring Boot here. Spring MVC provides the #SubdomainMapping annotation, which does not seem to be available from what I can see in Spring Boot. I've seen a few people discuss using a filter to handle this. Or other approaches that seem overly convoluted.
Would there not be a (simple/cleaner) way to handle all sub-domains within a standard controller such as:
#SubdomainMapping(value = {"**"}
public String data(ModelMap modelMap, HttpServletRequest request) {
//Code to handles subdomain logic here ....
}
This would be a simple approach where all values are treated equally with minor differences.
Any suggestions would be helpful!
I have worked on this myself and I have an answer that isn't as simple as you wanted, but I don't think there is one that simple.
So, you can create a handler interceptor adapter that will grab every request before it gets to your controller and grabs and processes the subdomain. This would require something like this:
#Component
public class SubDomainInterceptor extends HandlerInterceptorAdapter {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception arg3)
throws Exception {
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView model)
throws Exception {
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
String mysub = request.getRequestURL().toString();
//...
// Do whatever you need to do with the subdomain
//
if (isGoodSubdomain){
session.sendAttribute("subdomain", mysub);
} else {
response.sendRedirect("http://www.basesite.com"):
}
return true;
}
You then use that session variable in your controllers to filter values or whatever you need to use them for. I know this isn't the simple answer you wanted, but it was the best one that I have found so far.

why does interceptor not get fired on an EJB method called from servlet filter?

I want to implement high level resource filtering on URLs with a servlet filter and lower level action filtering on methods with an interceptor but my interceptor does not get fired on the EJB method called from the servlet filter.
Interceptor annotation Interface:
#Inherited
#InterceptorBinding
#Retention (RUNTIME)
#Target({TYPE, METHOD})
public #interface Permit {
#Nonbinding
String[] actions() default "N/A";
}
The Interceptor:
#Permit
#Interceptor
public class PermitInterceptor {
#AroundInvoke
public Object verifyPermission(InvocationContext context) throws Exception {
Method method = context.getMethod();
if(method.isAnnotationPresent(Permit.class)) {
Permit permitAnnotation = method.getAnnotation(Permit.class);
List<String> permittedActions = Arrays.asList(permitAnnotation.actions());
List<String> userActions = SecurityContextHandler.getActiveUser().getActions();
if(!Collections.disjoint(permittedActions, userActions)){
return context.proceed();
}
}
throw new PermissionException("You do NOT have the required permissions to perform this action");
}
}
Servlet Filter:
#WebFilter(urlPatterns = {"/*"})
public class AccessFilter implements Filter {
#EJB
private RulesBean rules;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
try{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getRequestURI();
if(rules.isAllowed(url)){
chain.doFilter(request, response);
}else{
//handle as necessary
}
}catch(Exception ex){
//handle as necessary
}
}
}
And finally here's what the EJB RulesBean that I want to use to manage routing/interception for all my servlets looks like;
Rules:
#Stateless
#LocalBean
public class RulesBean {
private static final String CUSTOMERS = "/customers"
public boolean isAllowed(String url) throws PermissionException {
switch(url){
case CUSTOMERS: return canViewAllCustomers();
default: return true;
}
}
/*This should trigger PermitInterceptor before entering method and
should throw my custom PermissionException if permission fails*/
#Permit(actions={"ViewCustomers"})
private boolean canViewAllCustomers(){
return true;
}
...
//Other tests carried out here ...
}
Unfortunately PermitInterceptor doesn't get called before entering canViewAllCustomers() method.
Amazingly however, PermitInterceptor gets triggered when canViewAllCustomers() is made public and called directly as rules.canViewAllCustomers() instead of through the helper method rules.isAllowed(String url). But this isn't helpful in my case, as it gives me no single entry point for my URL checks which essentially means I have to do all the checks in the Servlet Filter.
QUESTION: Please can anybody shed more light on the reason why things are occurring in this manner?... and suggestions about the best way to implement this scenario is highly welcome. Thanks.
NOTE: (To give more perspective)
You may be wondering why I want to do this OR more specifically why the RuleBean even exists at all... The reason is simply because a good number of my Servlets aren't doing much except route response to a view that triggers a server-side DataTables ajax call which populates the tables, hence I really need to ensure that the request for the view doesn't even get through to the if...else condition that fetches the view unless the permission checks in the interceptor is satisfied.
See sample servlet below;
#WebServlet ("/customers/*")
public class CustomerServlet extends VelocityViewServlet {
private static final String CUSTOMERS = "/customers"
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String uri = request.getRequestURI();
if(uri.equals(CUSTOMERS)){
String view = Path.getTemplate("/customers/index.vm");
request.setAttribute("headerTitle", "Customers");
request.getRequestDispatcher(view).forward(request, response);
}else if(...){
...
}
}
}
You invoke canViewAllCustomers() within isAllowed() directly, which gives the Application Server no chance to intercept the call.
Interception works with proxy classes. When you inject the EJB into your servlet, like you did with:
#EJB
private RulesBean rules;
what actually gets injected is not an EJB instance, but a proxy class, that the application server created at runtime (you can see this with the debugger). Invocations on that proxy class will be intercepted for transactions, custom interceptors, etc. and then delegated to the actual class instance.
So what you need to do is either put canViewAllCustomers() into a new EJB, that you can let the application server inject into your RulesBean class,
or you can retrieve a reference of your RulesBean class from inside isAllowed() like so:
#Stateless
#LocalBean
public class RulesBean {
private static final String CUSTOMERS = "/customers"
#Resource
SessionContext ctx;
public boolean isAllowed(String url) throws PermissionException {
switch(url){
case CUSTOMERS: return self().canViewAllCustomers();
default: return true;
}
}
private RulesBean self() {
return ctx.getBusinessObject(RulesBean.class);
}
/*This should trigger PermitInterceptor before entering method and
should throw my custom PermissionException if permission fails*/
#Permit(actions={"ViewCustomers"})
public boolean canViewAllCustomers(){
return true;
}
}

Spring MVC InterceptorHandler called twice with DeferredResult

When I am using custom HandlerInterceptor and my controller returns DeferredResult, the preHandle method of my custom interceptor called twice on each request. Consider a toy example.
My custom interceptor:
public class MyInterceptor implements HandlerInterceptor {
static int i = 0;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(i++);
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
My Spring Java configuration:
#Configuration
#EnableWebMvc
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}
My Controller:
#Controller
public class MyController {
#RequestMapping(value = "/test", method = RequestMethod.GET)
public DeferredResult<String> test() {
DeferredResult<String> df = new DeferredResult<String>();
df.setResult("blank");
return df;
}
}
So, on each page load I see two outputs from preHandle method. However, if I modify MyController in order to return just "blank" template (instead of DeferredResult with "blank" template), I see just one output from preHandle on each page load.
So, my question is why preHandle called twice when I use DeferredResult and is it possible to avoid this?
You need to use org.springframework.web.servlet.AsyncHandlerInterceptor:
public interface AsyncHandlerInterceptor extends HandlerInterceptor {
void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
}
Spring MVC execute sequence:
preHandle
afterConcurrentHandlingStarted
preHandle
postHandle
afterCompletion
The difference between the two invocations can be seen by examining the value of request.getDispatcherType().
I followed what #thunder mentioned by checking the value of request.getDispatcherType() and this worked for me.
public class MyInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// NOTE: For all dispatchers that are not "REQUEST" like "ERROR", do
// an early return which prevents the preHandle function from
// running multiple times
if (request.getDispatcherType() != DispatcherType.REQUEST) {
return true;
}
// ... do other stuff and then do a final return
return true;
}
}
As I'm exploring adding filter and Interceptor, I'm prettry sure that's caused by async calling. You use a DeferredResult here, which spring will do the filter in origin thread and filtering it again in a new thread. If you set log level to Debug, you will notice log like this.
15:14:06.948 [http-nio-8199-exec-5] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#efe6068
15:14:06.948 [http-nio-8199-exec-5] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
15:14:06.948 [http-nio-8199-exec-5] DEBUG o.s.b.w.f.OrderedRequestContextFilter - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade#163cab73
15:14:07.148 [http-nio-8199-exec-6] DEBUG o.s.b.w.f.OrderedRequestContextFilter - Bound request context to thread: SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ org.apache.catalina.core.ApplicationHttpRequest#42f1262]]
In a word, it's executed once in one thread, but here're two threads.
As I digged the google, I found there's no good solution.
If you have something like auth in request, a walk around way is add
security.filter-dispatcher-types=REQUEST, ERROR
Then the new thread(async one) will not get the security context. You need to check it and stop the filter chain inside it.
Or you just use the tranditional sync call like:
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test() {
return "blank";
}
I found another helpful answer. https://jira.spring.io/browse/SPR-12608
Hope it helps!
Inside preHandle method, If you have response.sendError(<>, <>), then this preHandle method will execute twice for each API request. So remove sendError() method to execute this only once.
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.sendError(401, "Token is invalid");
return false;
}
The prehandle method of the AsyncHandlerInterceptor will always be executed twice in async processing.

Bare bones servlet application, where to store config settings that I can reference?

I have a bare bones servlet application.
Do I store config related information in my web.xml file?
Is there an event that fires in my servlet that I should save the config value to to a static readonly variable?
I have a single servlet right now, but is there another file where the lifecycle begins at a global level?
Like in .net, you have your pages, but there is a global.asax.cs class that fires at specific events like:
application_startup
application_shutdown
application_beginRequest
application_endRequest
Does servlets have this, or is it on a per-servlet basis?
application_startup
application_shutdown
Implement ServletContextListener.
#WebListener
public class ApplicationListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
// Do your job here on application startup.
}
#Override
public void contextDestroyed(ServletContextEvent event) {
// Do your job here on application shutdown.
}
}
You can store application wide variables as an attribute of the ServletContext.
event.getServletContext().setAttribute("foo" new Foo());
It's available in servlets by the inherited getServletContext() method.
Foo foo = (Foo) getServletContext().getAttribute("foo");
And in JSPs by just EL.
${foo.someProperty}
application_beginRequest
application_endRequest
Implement ServletRequestListener:
#WebListener
public class RequestListener implements ServletRequestListener {
#Override
public void requestInitialized(ServletRequestEvent event) {
// Do your job here on request begin.
}
#Override
public void requestDestroyed(ServletRequestEvent event) {
// Do your job here on request end.
}
}
You can store request wide variables as an attribute of the ServletRequest.
event.getServletRequest().setAttribute("foo" new Foo());
It's available in servlets by the passed-in HttpServletRequest argument.
Foo foo = (Foo) request.getAttribute("foo");
And in JSPs by just EL.
${foo.someProperty}
You can even implement the both interfaces in a single class:
#WebListener
public class GlobalListener implements ServletContextListener, ServletRequestListener {
// ...
}
Or, more common, for sure if you want to be able to modify/control requests more globally, a Filter:
#WebFilter(urlPatterns={"/some/*"})
public class SomeFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
// Do here your application startup job.
// If you have any <init-param> in web.xml, then you could get them
// here by config.getInitParameter("name") and assign it as field.
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Do here your request/response preprocessing job.
// Continue the request/response (if you haven't already forwarded/redirected the request/response beforehand).
chain.doFilter(request, response);
// Do here your request/response postprocessing job.
}
#Override
public void destroy() {
// Do here your application shutdown job.
// If you have assigned any expensive resources as field of
// this Filter class, then you could clean/close them here.
}
}
See also https://stackoverflow.com/tags/servlet-filters/info.
All other listeners of the Servlet API can be found as interfaces in the javax.servlet package. Learn to find your way in the Javadocs.
For application_startup and application_shutdown check out javax.servlet.ServletContextListener.
For application_beginRequest and application_endRequestcheck out javax.servlet.Filter.
Both enable you to manage a scope (in the form of a map or initalization parameters) where you can put your configuration and/or initialize/finalize components, through the corresponding level events.
Servlets have a load order; it used to bee typical to have a startup servlet that performed initialization tasks, loaded before other servlets.
Nowadays this is usually handled by a startup listener.
http://download.oracle.com/docs/cd/B14099_19/web.1012/b14017/filters.htm#i1000654
You may store parameters in init-params, but there are other options like JNDI, property files, etc.

Spring Controllers: Can I call a method before each #RequestMapping method is called?

I have some common components that are always present in every page served by a given Controller class.
At the beginning of each #RequestMapping method I populate the model with these common components.
Is there a way to define a method be called prior to each of the controller methods so that I can get all of this copy/paste into one place?
Just annotate a method with #ModelAttribute
The below would add a Foo instance to the model under the name "foo"
#ModelAttribute("foo")
public Foo foo() {
return new Foo();
}
See the #ModelAttribute documentation
Interceptor is the solution. It has methods preHandler and postHandler, which will be called before and after each request respectively. You can hook into each HTTPServletRequest object and also by pass few by digging it.
here is a sample code:
#Component
public class AuthCodeInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// set few parameters to handle ajax request from different host
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.addHeader("Access-Control-Max-Age", "1000");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Cache-Control", "private");
String reqUri = request.getRequestURI();
String serviceName = reqUri.substring(reqUri.lastIndexOf("/") + 1,
reqUri.length());
if (serviceName.equals("SOMETHING")) {
}
return super.preHandle(request, response, handler);
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
}
All methods that have the #ModelAttribute annotation are called before the specific handler and the return values are added to the Model instance. Then you can use this attributes in your views and as handler parameters.
I found this blog very useful.
Yes, you can use an interceptor. You can define them by <mvc:interceptors>
Another option is to use s Filter, but you won't be able to inject spring beans into it.
Another approach would be to annotate the controller class as request-scoped (#Scope('request')) so that every request will create a new instance of the controller to invoke the matching method on it.
You can then put all your pre-processing work into a post-construct method (i.e. a normal method annotated with #PostConstruct) which will always be called after a new controller instance is initialized (i.e created and all dependencies are resolved) and before the request-matching method is invoked.
I suppose that this would be a bit inefficient if controller's initialization is heavy (e.g. costly computations or many dependencies to resolve); but yet is another approach to this problem.

Categories

Resources