Pratap A.K
Pratap A.K

Reputation: 4517

Call another method after Spring MVC handler returns

I have a requirement where I need to return some status/Long value from a rest controller and then execute code to send push notification.

@RequestMapping(value="/create")
public String createTicket() throws InterruptedException {
    // code to create ticket
    return "ticket created";
    // need to call sendPushNotifiction() after I return status
}

    public void sendPushNotifiction() throws InterruptedException {
    // code to send push notification
    System.out.println("Sent push notification successfully!!");    
}

Can some one please tell me how to achieve this? Is it possible to use Spring AOP for this? I don't think thread will guaranteed execution of sendPushNotifiction method only after return. So what are the ways to achieve this effectively? Thanks in advance

Upvotes: 6

Views: 11314

Answers (7)

Italo Borssatto
Italo Borssatto

Reputation: 15679

The HandlerInterceptor is the solution, but the code get a little bit more complex than expected. Here's a code suggestion to make it simpler by putting the whole solution in a single class:

@RequestMapping(value = "/create")
public String createTicket() throws InterruptedException {
    String ticket = "ticket created";
    result.set(ticket); // Save the ticket to be used after response
    return ticket;
}

public void sendPushNotifiction(String ticket) throws InterruptedException {
    System.out.println("Sent push notification successfully!!");
}

private static final ThreadLocal<String> result = new ThreadLocal<String>();

@Bean
public MappedInterceptor interceptor() {
    return new MappedInterceptor(Arrays.array("/create"), new HandlerInterceptor() {
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            // Get the saved object and clean for the next request
            String ticket = result.get();
            result.set(null);

            // Execute after response
            sendPushNotifiction(ticket);
        }
    });
}

Upvotes: 2

Sanjay
Sanjay

Reputation: 8955

I think it might be a good use case for asynchronous processing. Spring has good support for it. Precisely, you need to

  1. Annotate sendPushNotifiction with @Async.
  2. Annotate some configuration class with @EnableAsync.
  3. Call sendPushNotifiction() before the return statement. The execution flow will not wait for sendPushNotifiction to finish.

If it doesn't work, try coding sendPushNotifiction in a separate service.

Upvotes: 3

Sainik Kumar Singhal
Sainik Kumar Singhal

Reputation: 801

createTicket()is called by spring.You can't call it directly.You can use org.springframework.web.servlet.HandlerInterceptor.Just call your sendPushNotifiction() method from postHandle() or afterCompletion() method of your HandlerInterceptor

    package com.sample.interceptor;

   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;

   import org.springframework.web.servlet.HandlerInterceptor;
   import org.springframework.web.servlet.ModelAndView;

   public class NotifictionHandlerInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
        ModelAndView modelAndView) throws Exception {
    //do nothing
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
        throws Exception {

    //call your method here
    //call sendPushNotifiction()

}

}

And register you handler in spring-mvc context

    <mvc:interceptors>
<bean class="com.sample.NotifictionHandlerInterceptor" />
   </mvc:interceptors>

Upvotes: 1

Radu Dumitriu
Radu Dumitriu

Reputation: 116

Another way is to postpone the execution of sendPushNotification() to some thread / thread pool. Before the return, use a queue to enqueue the processing, then in your thread dequeue and process.

However, you should take care to link your requests to the real caller and take care of failures, etc.

Web is full of examples. Look for java.util.concurrent examples, executors, ...

Upvotes: 0

M Sach
M Sach

Reputation: 34424

i agree with youngHobbit solution where you can do like below wh

@RequestMapping(value="/create")
public String entryMethod() throws InterruptedException {
   String response = createTicket();
   sendPushNotifiction();
   return response ;
}

public String createTicket() throws InterruptedException {
    // code to create ticket
    return "ticket created";
    // need to call sendPushNotifiction() after I return status
}

    public void sendPushNotifiction() throws InterruptedException {
    // code to send push notification
    System.out.println("Sent push notification successfully!!");    
}

Though another solution can be to forward/redirect the request to another method once you are done with first one. But take the first approach if it solves your purpose as its simple,clear and readable

AOP is for basically dealing cross cutting concerns which you want to handle across application, should not be used for very specific purpose like this. Why to introduce extra complexity when

Upvotes: 0

Kumaresan Perumal
Kumaresan Perumal

Reputation: 1956

You can call like that:

@RequestMapping(value="/create")
public void create(){
createTicket();
sendPushNotifiction();
}

public String createTicket() throws InterruptedException {
    // code to create ticket
    return "ticket created";
    // need to call sendPushNotifiction() after I return status
}

    public void sendPushNotifiction() throws InterruptedException {
    // code to send push notification
    System.out.println("Sent push notification successfully!!");    
}

Upvotes: 0

YoungHobbit
YoungHobbit

Reputation: 13402

Create another method which first calls the createTicket() method and then calls the sendPushNotifiction(). That will do the job. This the simplest way in my humble opinion.

Upvotes: 1

Related Questions