Tuesday 2 September 2014

AEM Dispatcher - Manual cache flushing/invalidation

CQ comes with a Default flush agent that flushes cache on activation. But what if you manually want to flush or invalidate the cache?

The solution is:

The CQ cache can be deleted by using an HTTP request which looks like:

POST /dispatcher/invalidate.cache HTTP/1.1
CQ-Action: Activate
CQ-Handle: path-pattern
Content-Length: 0


CQ Actions:  

1.Activate
  • It touches the .stat file( at and above the CQ-handle path heirarchy) to the latest timestamp
2.Delete/Deactivate
  • It touches the .stat file( at and above the CQ-handle path heirarchy) to the latest timestamp 
  • It deletes the cache at the CQ-Handle path provided

We can write a flushcache servlet to serve the purpose:

package com.adobe.example;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Property;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;

@Component(metatype=true)
@Service
public class Flushcache extends SlingSafeMethodsServlet {

    @Property(value="/bin/flushcache/html")
    static final String SERVLET_PATH="sling.servlet.paths";

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
        try{
            //retrieve the request parameters
            String handle = request.getParameter("handle");
            String page = request.getParameter("page");

            //hard-coding connection properties is a bad practice, but is done here to simplify the example
            String server = "localhost:80";
            String uri = "/dispatcher/invalidate.cache";

            HttpClient client = new HttpClient();

            PostMethod post = new PostMethod("http://"+server+uri);
            post.setRequestHeader("CQ-Action", "Activate");
            post.setRequestHeader("CQ-Handle",handle);

            StringRequestEntity body = new StringRequestEntity(page,null,null);
            post.setRequestEntity(body);
            post.setRequestHeader("Content-length", String.valueOf(body.getContentLength()));
            client.executeMethod(post);
            post.releaseConnection();
            //log the results
            logger.info("result: " + post.getResponseBodyAsString());
        }
        catch(Exception e){
            logger.error("Flushcache servlet exception: " + e.getMessage());
        }
    }
}

 

How it works:
The .stat file is touched to the latest timestamp everytime we hit the servlet.

Demo:

Initial .stat file


After hitting http://localhost:4503/bin/flushcache/html?handle=/content&page=/content, the stat file timestamp gets updated: