Hisham
Hisham

Reputation: 593

Struts2 Interceptor *after* JSP is rendered - how?

I was wondering if I can capture the result of an action after the result returns and the JSP is rendered. I want to be able to take the entire result (generated HTML) and push it into memcached so I can bring it via Nginx with-out hitting the application server. Any ideas?

PS: I know I can run the interceptor after the action executes but before the result returns and the JSP is rendered, but not after the JSP is rendered.

Upvotes: 3

Views: 4366

Answers (5)

samarjit samanta
samarjit samanta

Reputation: 1315

Hey I know its quite late now to answer you might have already found out the answer, however for others to benefit I am posting the answer. One thing that is very similar to what you are doing is done by sitemesh filter. Yes, filter comes before and after the Struts2 filter itself, so you can mess with the inputs and outputs easily. But struts does evaluate JSP/freemarker/velocity and generate the final html which is passed to the user. JSP is a bit trickey because internally a servlet is called but check out org.apache.struts2.views.freemarker.FreemarkerResult class, you can see the actual html getting generated in template.process(model, writer);. This writer is actually ServletActionContext.getResponse().getWriter();

Now to get the html all you need to do is ServletActionContext.getResponse().getWriter().toString() //This does not work out of box. To get the toString() to work you need to use a ResponseWrapper - which is the same method to get result html in Filters. See- Programming Customized Requests and Responses.

Listing to modify resulting html in struts 2. This is not tested, but it is extracted from my code I have written earlier for custom template engine. I will probably post full description in Custom template engine for struts2

public class DecoratorInterceptor implements Interceptor {
    public String intercept(ActionInvocation invocation) throws Exception {
       final ActionContext context = invocation.getInvocationContext ();
       HttpServletResponse responseParent = (HttpServletResponse) 
                               context.get(ServletActionContext.HTTP_RESPONSE);
       CharResponseWrapper wrapper = new CharResponseWrapper(responseParent);

       ServletActionContext.setResponse(wrapper);

       //Actual Action called
       String result =  invocation.invoke();

       String htmlReturned = wrapper.toString();
       //play with htmlReturned ...
       String modifiedhtml = pushintoMemCache(htmlReturned );           

       CharArrayWriter car = new CharArrayWriter();           
       car.write(modifiedhtml );

       PrintWriter out = responseParent.getWriter();
        out.write(car.toString());
        out.flush();
   }

  @Override
    public void destroy() {
    // TODO Auto-generated method stub

    }

  @Override
    public void init() {
    // TODO Auto-generated method stub

    }

}         

Upvotes: 1

Hanno Fietz
Hanno Fietz

Reputation: 31360

Within your interceptor's intercept() method, the ActionInvocation parameter has a getResult() method which returns null before Action execution (i. e. before you call invocation.invoke() in your intercept() method) and contains an implementation of Result afterwards. That object should give you some way to access the data you need, but how this is done probably depends on the class that is actually used.

See also my somewhat related question and the answer I posted after figuring it out.

Upvotes: 0

Kartik
Kartik

Reputation: 2609

Question: How do you determine if the view has been generated? Do you set a request header or an some sort of a flag to determine if the view has been generated?

You could try throwing a MemCachedException to indicate that it is time to load into a mem cache. Your interceptor code could read

try {
   return invocation.invoke();
} catch (MemCachedException mce) {
   // Your code to upload to MemCache.
} finally {
  // blah blah clean up.
}

Upvotes: 0

user174009
user174009

Reputation:

I haven't found a way to do this inside of struts2, your best bet it to create a servlet Filter and have it modify the OutputStream.

http://onjava.com/pub/a/onjava/2003/11/19/filters.html

Upvotes: 1

KV Prajapati
KV Prajapati

Reputation: 94645

Read this article - http://struts.apache.org/2.0.6/docs/interceptors.html

SUMMARY:When you request a resource that maps to an "action", the framework invokes the Action object. But, before the Action is executed, the invocation can be intercepted by another object. After the Action executes, the invocation could be intercepted again. Unsurprisingly, we call these objects "Interceptors."

Upvotes: 0

Related Questions