diff src/cachingfilter/CachingFilter.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cachingfilter/CachingFilter.java	Thu Mar 21 19:15:52 2019 -0600
@@ -0,0 +1,147 @@
+package cachingfilter;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectOutputStream;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public final class CachingFilter implements Filter { 
+	private static final Logger logger = LoggerFactory.getLogger(CachingFilter.class);
+
+	static final Locker<String> locker = new Locker<String>();
+
+//	private static final long sweepFreqSeconds = 60*60*24;
+//	private static final long expiryPeriodMillis = 1000L*60*60*24*10;
+	private static final long sweepFreqSeconds = 60*60;
+	private static final long expiryPeriodMillis = 1000L*60*60*24;
+
+	static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+
+	private File dir;
+	private boolean hasDelayedDelete;
+	private final Set<String> encodings = new HashSet<String>();
+
+	public void init(FilterConfig filterConfig)
+		throws ServletException
+	{
+		String dirS = filterConfig.getInitParameter("dir");
+		if( dirS == null )
+			throw new ServletException("'dir' init parameter must be set");
+		dir = new File(dirS);
+		dir.mkdirs();
+
+		String acceptEncoding = filterConfig.getInitParameter("acceptEncoding");
+		if( acceptEncoding == null )
+			throw new ServletException("'acceptEncoding' init parameter must be set");
+		for( String encoding : acceptEncoding.split(",") ) {
+			encoding = encoding.trim();
+			if( encoding.length() > 0 )
+				encodings.add(encoding);
+		}
+
+		String hasDelayedDeleteS = filterConfig.getInitParameter("hasDelayedDelete");
+		if( hasDelayedDeleteS == null )
+			throw new ServletException("'hasDelayedDelete' init parameter must be set");
+		hasDelayedDelete = Boolean.parseBoolean(hasDelayedDeleteS);
+
+		Runnable sweeper = new Runnable() {
+			public void run() {
+				try {
+					logger.error("starting sweep");
+					final int[] total = new int[1];
+					final long expired = System.currentTimeMillis() - expiryPeriodMillis;
+					File[] files = dir.listFiles(new FileFilter(){
+						public boolean accept(File file) {
+							total[0]++;
+							return file.lastModified() < expired && file.getName().charAt(0) != '~';
+						}
+					});
+					int n = 0;
+					for( File file : files ) {
+						String name = file.getName();
+						locker.lock(name);
+						try {
+							if( newCachedPage(name).delete() )
+								n++;
+						} finally {
+							locker.unlock(name);
+						}
+					}
+					logger.error("finished sweep, deleted "+n+" pages out of "+files.length+" candidates, "+total[0]+" total");
+				} catch(RuntimeException e) {
+					logger.error("exception in sweeper",e);
+					throw e;
+				} catch(Error e) {
+					logger.error("error in sweeper",e);
+					System.exit(-1);
+			}
+			}
+		};
+		executor.scheduleWithFixedDelay( sweeper, sweepFreqSeconds, sweepFreqSeconds, TimeUnit.SECONDS );
+	}
+
+	public void destroy() {}
+
+	public static void shutdown() {}
+
+	CachedPage newCachedPage(String name) {
+		if( name.length() == 0 )
+			throw new RuntimeException("empty filenames not allowed");
+		if( name.charAt(0) == '~' )
+			throw new RuntimeException("invalid filename: "+name);
+		return hasDelayedDelete ? new CachedFile(dir,name) : new CachedDir(dir,name);
+	}
+
+	public void doFilter(
+		ServletRequest req,
+		ServletResponse res,
+		FilterChain chain
+	)
+		throws IOException, ServletException
+	{
+		HttpServletRequest request = (HttpServletRequest)req;
+		HttpServletResponse response = (HttpServletResponse)res;
+		if( !"GET".equals( request.getMethod() ) ) {
+			chain.doFilter(request,response);
+			return;
+		}
+		CachingRequestWrapper wrappedRequest = new CachingRequestWrapper(request);
+		CachingResponseWrapper wrappedResponse = new CachingResponseWrapper(this,wrappedRequest,response);
+		boolean isDone = false;
+		try {
+			chain.doFilter(wrappedRequest,wrappedResponse);
+			isDone = true;
+		} finally {
+			wrappedResponse.finish(isDone);
+		}
+		
+	}
+
+	public Set<String> getEncodings() {
+		return encodings;
+	}
+
+}