[ RESOLVIDO ] Vraptor 3 e controle de cache para css e js

Olá,

Descrição;
Estou procurando melhorar a performance de meu web site, a principio implemente uma forma que monto dinamicamente varios css e gero um cada controller do vraptor atravez de uma anotação, junto todos os css e o comprimo usando o YUI Compressor até ai esta funcionando, faço isso em um interceptor…
isso fica legal porque após criado o arquivo não recrio ele apenas o utilizo o arquivo que esta criado gerando performance…

O meu problema
Preciso que seja cacheado em browser o css e o js, encontrei algumas coisas como por exemplo esta classe q esta abaixo, porém estou usando vraptor 3 e gostaria de saber se tem alguma coisa que posso usar para retornar no response as informações de cache para o browser e ganhar performance na app;

// codigo que encontrei na internet
package control.cache;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.servlets.DefaultServlet;

public class CustomFileServlet extends DefaultServlet {
	private static final long serialVersionUID = 1L;
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		processRequest(request, response);
	}
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		processRequest(request, response);
	}
	public boolean processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		String requestURI = request.getRequestURI();
		String contextPath = request.getContextPath();

		String fileURI = "";
		if (requestURI.indexOf(contextPath) != -1) {
			// Request URI is CONTEXTPATH + RESOURCE URI
			fileURI = requestURI.substring(requestURI.indexOf(contextPath) + contextPath.length());
		}

		File file = new File(request.getSession().getServletContext().getRealPath(fileURI));
		String lowerfile = file.getAbsolutePath().toLowerCase();

		boolean isBasePath = "/".equalsIgnoreCase(fileURI);
		boolean isJSFile = lowerfile.endsWith(".js");
		boolean isCSSFile = lowerfile.endsWith(".css");
		boolean customServing = (!isBasePath) && (isJSFile || isCSSFile);

		if(customServing) {
			String mimetype = request.getSession().getServletContext().getMimeType(fileURI);
			response.setContentType(mimetype);

			// Required Cache Control Headers
			String maxage = "86400"; // One day in Seconds
			response.setHeader("Cache-Control", "max-age="+ maxage);
			long relExpiresInMillis = System.currentTimeMillis() + (1000 * Long.parseLong(maxage));
			response.setHeader("Expires", getGMTTimeString(relExpiresInMillis));
			response.setHeader("Last-Modified", getGMTTimeString(file.lastModified()));

			// Serve the file content
			FileInputStream fis = new FileInputStream(file);
			OutputStream ostream = response.getOutputStream();
			streamIO(fis, ostream);
			fis.close();
			ostream.flush();
			ostream.close();

			return false; // We have taken care of file serving.
		}
		return true; // Let DefaultServlet handle file serving
	}
	
	public static String getGMTTimeString(long milliSeconds) {
		SimpleDateFormat sdf = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'");
		return sdf.format(new Date(milliSeconds));
	}
	
	public static void streamIO(InputStream is, OutputStream os) throws IOException {
		byte[] bytes = new byte[2048];
		int readlen = -1;
		while ((readlen = is.read(bytes)) != -1) {
			os.write(bytes, 0, readlen);
			os.flush(); // Let us flush after bluk write
		}
	}
}

Se puderem me ajudar desde ja agradeço…

Cara fiz um esquema meio que manual e funcionou…
Caso alguem tenha solução melhor posta ai…

Resolução
no web.xml adicionei o filter

[code]

<filter>
	<filter-name>filtro</filter-name>
	<filter-class>control.cache.FiltrosResources</filter-class>
</filter>
<filter-mapping>
	<filter-name>filtro</filter-name>
	<url-pattern>/resource/css/*</url-pattern>
</filter-mapping>
<filter-mapping>
	<filter-name>filtro</filter-name>
	<url-pattern>/resource/js/*</url-pattern>
</filter-mapping>
<!-- fim monitoramento -->[/code]

criei o filter dessa forma

package control.cache;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FiltrosResources implements Filter {

	public void destroy() {
		//System.out.println("--- > destroy");
	}
	
	public void init(FilterConfig config) throws ServletException {
		//System.out.println("--- > init");
	}

	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;  
		  
		String requestURI = request.getRequestURI();
		String contextPath = request.getContextPath();

		String fileURI = "";
		if (requestURI.indexOf(contextPath) != -1) {
			// Request URI is CONTEXTPATH + RESOURCE URI
			fileURI = requestURI.substring(requestURI.indexOf(contextPath) + contextPath.length());
		}

		File file = new File(request.getSession().getServletContext().getRealPath(fileURI));
		String lowerfile = file.getAbsolutePath().toLowerCase();

		boolean isBasePath = "/".equalsIgnoreCase(fileURI);
		boolean isJSFile = lowerfile.endsWith(".js");
		boolean isCSSFile = lowerfile.endsWith(".css");
		boolean customServing = (!isBasePath) && (isJSFile || isCSSFile);

		if(customServing) {
			String mimetype = request.getSession().getServletContext().getMimeType(fileURI);
			response.setContentType(mimetype);

			// Required Cache Control Headers
			String maxage = "86400"; // One day in Seconds
			response.setHeader("Cache-Control", "max-age="+ maxage);
			long relExpiresInMillis = System.currentTimeMillis() + (1000 * Long.parseLong(maxage));
			response.setHeader("Expires", getGMTTimeString(relExpiresInMillis));
			response.setHeader("Last-Modified", getGMTTimeString(file.lastModified()));

			// Serve the file content
			FileInputStream fis = new FileInputStream(file);
			OutputStream ostream = response.getOutputStream();
			streamIO(fis, ostream);
			fis.close();
			ostream.flush();
			ostream.close();

		}

        // Aqui é feito o redirecionamento normal, caso seja um arquivo  
        chain.doFilter(req,resp);
	}

	public static String getGMTTimeString(long milliSeconds) {
		SimpleDateFormat sdf = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'");
		return sdf.format(new Date(milliSeconds));
	}
	
	public static void streamIO(InputStream is, OutputStream os) throws IOException {
		byte[] bytes = new byte[2048];
		int readlen = -1;
		while ((readlen = is.read(bytes)) != -1) {
			os.write(bytes, 0, readlen);
			os.flush(); // Let us flush after bluk write
		}
	}

}

Cara isso intercepta os arquivos e altera o response para retornar fazendo o que eu preciso, não interferio na funcionalidade do vraptor 3 nos testes iniciais…
caso alguem saiba de alguma forma melhor por favor posta ai!!!
vou deixar o topico em aberto por mais um tempo, valew…

Essa é uma boa forma sim…

a geração e compressão dos css e js não tem a ver com as funcionalidades do VRaptor, então implementar num filtro é ok.

Na verdade fiz assim…
Criei uma anotação onde eu digo quais os arquivos quero que envie para aquela view, esta anotação coloco sobre cada metodo e passo um array com os css e outro com os js.
Ai entra um interceptor que retornar para a view um link com cada um o css fica no topo para evitar o efeito flash na pagina e o js coloquei no final da pagina…
nesse interceptor ele também cria um arquivo unico com todos os css passados no array da anotação e outr com os js… e compressiona este arquivo sempre faz isso caso ele não exista…
O papel do Filter é apenas retornar no response o controle de cache dos arquivos retornados, a meta é tentar deixar a performance quanto melhor possivel…
Esta funcionando… acredito que seja uma boa pratica… caso eu estiver fazendo algo de errado por favor me avise kk…
Abraço e obrigado Lucas…