+package de.halbekunst.juplo.cachecontrol;
+
+import de.halbekunst.juplo.cachecontrol.CacheControl.CacheMethodHandle;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.zip.GZIPOutputStream;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Configurable;
+
+
+
+/**
+ *
+ * @author kai
+ */
+@Configurable
+public class AcceleratorFilter implements Filter {
+ private final static Logger log = LoggerFactory.getLogger(AcceleratorFilter.class);
+
+ public final static String REQUEST_URI_ATTRIBUTE = "javax.servlet.include.request_uri";
+
+
+ @Autowired CacheControl cacheControl;
+ @Autowired(required=true) Integer buffer;
+ @Autowired(required=true) String eTag;
+ @Autowired(required=true) Boolean weak;
+ @Autowired(required=true) Long lastModified;
+ @Autowired(required=true) Integer cacheSeconds;
+
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ if (!(request instanceof HttpServletRequest)) {
+ log.error("AcceleratorFilter can only handle HTTP-requests");
+ chain.doFilter(request, response);
+ return;
+ }
+
+ /** Prüfen, ob es sich um eine Anfrage für einen JSP-Include handelt */
+ if (request.getAttribute(REQUEST_URI_ATTRIBUTE) != null) {
+ log.debug("Includes cannot be accelerated");
+ chain.doFilter(request, response);
+ return;
+ }
+
+ AccelerationWrapper wrapper = new AccelerationWrapper((HttpServletRequest)request, (HttpServletResponse)response);
+ cacheControl.init(wrapper);
+ chain.doFilter(request, wrapper);
+ wrapper.finish();
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+
+ class AccelerationWrapper extends HttpServletResponseWrapper implements CacheMethodHandle {
+
+ private final HttpServletRequest request;
+ private final HttpServletResponse response;
+
+ private boolean zipped;
+ private GZIPServletOutputStream out;
+
+ private long now;
+ private int buffer;
+ private int status;
+ private String type;
+
+
+ AccelerationWrapper(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ super(response);
+
+ this.request = request;
+ this.response = response;
+
+ now = System.currentTimeMillis();
+ buffer = AcceleratorFilter.this.buffer;
+ status = HttpServletResponse.SC_OK;
+
+ zipped = false;
+ Enumeration values = request.getHeaders(HeaderNames.HEADER_ACCEPT_ENCODING);
+ while (values.hasMoreElements()) {
+ String value = (String) values.nextElement();
+ if (value.indexOf("gzip") != -1) {
+ zipped = true;
+ response.addHeader(HeaderNames.HEADER_CONTENT_ENCODING, "gzip");
+ break;
+ }
+ }
+ }
+
+
+ public void finish() throws IOException {
+ if (zipped && out != null)
+ out.zout.finish();
+ }
+
+
+ @Override
+ public void setStatus(int sc) {
+ response.setStatus(sc);
+ status = sc;
+ try {
+ cacheControl.decorate(request, response, this);
+ }
+ catch (Exception e) {
+ log.error("Error while decorating response", e);
+ }
+ }
+
+ @Override
+ public void setStatus(int sc, String sm) {
+ response.setStatus(sc,sm);
+ status = sc;
+ try {
+ cacheControl.decorate(request, response, this);
+ }
+ catch (Exception e) {
+ log.error("Error while decorating response", e);
+ }
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ if (out == null)
+ out = new GZIPServletOutputStream(response.getOutputStream(), zipped);
+ return out;
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return new PrintWriter(getOutputStream());
+ }
+
+ @Override
+ public void setContentType(String type) {
+ this.type = type;
+ response.setContentType(type);
+ }
+
+ @Override
+ public void setBufferSize(int size) {
+ this.buffer = size;
+ response.setBufferSize(size);
+ }
+
+ @Override
+ public int getBufferSize() {
+ return buffer;
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {
+ cacheControl.decorate(request, response, this);
+ if (zipped && out != null) {
+ out.zout.finish();
+ }
+ response.flushBuffer();
+ }
+
+ @Override
+ public void resetBuffer() {
+ response.resetBuffer();
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return response.isCommitted();
+ }
+
+ @Override
+ public void reset() {
+ response.reset();
+ }
+
+
+
+ @Override
+ public long getTimestamp() {
+ return now;
+ }
+
+ @Override
+ public int accepts(HttpServletRequest request) {
+ return status;
+ }
+
+ @Override
+ public int getCacheSeconds(HttpServletRequest request) {
+ return cacheSeconds;
+ }
+
+ @Override
+ public long getLastModified(HttpServletRequest request) {
+ return lastModified;
+ }
+
+ @Override
+ public String getETag(HttpServletRequest request) {
+ return eTag;
+ }
+
+ @Override
+ public boolean isETagWeak() {
+ return weak;
+ }
+
+ @Override
+ public void cacheControl(HttpServletRequest request, Map<String, String> cacheControlMap) {
+ }
+
+
+ class GZIPServletOutputStream extends ServletOutputStream {
+
+ private final OutputStream out;
+ private final GZIPOutputStream zout;
+ private boolean untouched = true;
+
+ public GZIPServletOutputStream(ServletOutputStream out, boolean zipped) throws IOException {
+ if (zipped) {
+ this.zout = new GZIPOutputStream(out, buffer);
+ this.out = this.zout;
+ }
+ else {
+ this.out = out;
+ this.zout = null;
+ }
+ }
+
+
+ @Override
+ public void write(int i) throws IOException {
+ if (untouched) {
+ untouched = false;
+ try {
+ AcceleratorFilter.this.cacheControl.decorate(AccelerationWrapper.this.request, response, buffer);
+ }
+ catch (Exception e) {
+ log.error("Error while guessing Cache-Header's", e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+ out.write(i);
+ }
+ }
+ }
+}