|
Programmation d'un filtre de cache avec un ServletFilter
Les Filters
interceptent en amont toutes les requêtes entrantes vers l’application et en
aval toutes les réponses sortant de celle-ci. Cette position intermédiaire les
qualifie pour jouer un rôle clé dans la gestion du cache. Dans cet article
nous présenterons un exemple qui montre comment implémenter la gestion du cache
au niveau d’un Filter (Cf. classe CacheFilter). Cet exemple a été initialement
publié dans le livre: Servlets and JavaServer Pages™: The J2EE™ Technology Web
Tier [209].
Classe CacheFilter
package com.jspbook;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Calendar;
public class CacheFilter implements Filter {ServletContext sc;
FilterConfig fc;
long cacheTimeout = Long.MAX_VALUE;
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request =
(HttpServletRequest) req;
HttpServletResponse response =
(HttpServletResponse) res;
// check if was a resource that shouldn't be cached.
String r = sc.getRealPath("");
String path =
fc.getInitParameter(request.getRequestURI());
if (path!= null && path.equals("nocache")) {
chain.doFilter(request, response);
return;}
path = r+path;
String id = request.getRequestURI() +
request.getQueryString();
File tempDir = (File)sc.getAttribute(
"javax.servlet.context.tempdir");
// get possible cache
String temp = tempDir.getAbsolutePath();
File file = new File(temp+id);
// get current resource
if (path == null) { path = sc.getRealPath(request.getRequestURI()); }
File current = new File(path);
try { long now =
Calendar.getInstance().getTimeInMillis();
//set timestamp check
if (!file.exists() || (file.exists() &&
current.lastModified() > file.lastModified()) ||
cacheTimeout < now - file.lastModified()) {
String name = file.getAbsolutePath();
name =
name.substring(0,name.lastIndexOf("/"));
new File(name).mkdirs();
ByteArrayOutputStream baos =
new ByteArrayOutputStream();
CacheResponseWrapper wrappedResponse =
new CacheResponseWrapper(response, baos);
chain.doFilter(req, wrappedResponse);
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();}} catch (ServletException e) {
if (!file.exists()) {
throw new ServletException(e);}}
catch (IOException e) {
if (!file.exists()) {
throw e;}}
FileInputStream fis = new FileInputStream(file);
String mt = sc.getMimeType(request.getRequestURI());
response.setContentType(mt);
ServletOutputStream sos = res.getOutputStream();
for (int i = fis.read(); i!= -1; i = fis.read()) {
sos.write((byte)i);}}
public void init(FilterConfig filterConfig) {
this.fc = filterConfig;
String ct =
fc.getInitParameter("cacheTimeout");
if (ct != null) {
cacheTimeout = 60*1000*Long.parseLong(ct);}
this.sc = filterConfig.getServletContext();}
public void destroy() {this.sc = null; this.fc = null;}}
Le filtre implémenté par la classe CacheFilter peut s’appliquer à n’importe
quelle servlet ou JSP de l’application. A partir de l’URI de la requête et des
paramètres qu’elle transporte, il construit un identifiant unique pour
référencer les JSP/servlets dans le cache :
String id = request.getRequestURI()+request.getQueryString();
Le premier paramètre transporté par la requête permet d’indiquer si la JSP/servlet
demandée peut être mise en cache. Par défaut toutes les JSP/servlets peuvent
être mises en cache sauf si ce paramètre est égal à ‘nocache’. Si tel est le
cas, le filtre interrompt son activité et passe la main à la prochaine ressource
de l’application (servlet, autre filtre…)
// check if was a resource that shouldn't be cached.
String path = fc.getInitParameter(request.getRequestURI());
if (path!= null && path.equals("nocache")) {chain.doFilter(request, response);
return;}
Si la JSP/servlet
demandée par la requête peut être mise en cache, le Filtre vérifie si elle a
déjà été mise en cache. Si tel est le cas le Filtre vérifie si la date de la
dernière modification de la JSP/servlet est postérieure à celle du cache. Si
c’est le cas le filtre met en cache la nouvelle version de la JSP /servlet sinon
il répond au client à partir du cache.
Dans le reste des cas, le filtre passe la main aux autres ressources de
l’application puis intercepte la réponse pour la mettre en cache dans le
répertoire temporaire javax.servlet.context.tempdir avant de l’envoyer au
client.
Notes de bas de
page
[209] Jayson
Falkner, Kevin Jones, Servlets and JavaServer Pages™: The J2EE™ Technology Web
Tier, Addison Wesley, September 19, 2003, ISBN: 0-321-13649-7, pages 784
|