/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.das2.util.filesystem; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.das2.util.LoggerManager; /** * This simply reduces invocations of an expensive operation by * caching the result for a given number of milliseconds. This was * introduced to remove the number of HEAD requests to the server for * a given file. * @author jbf */ public class ExpensiveOpCache { private static final Logger logger= LoggerManager.getLogger("das2.filesystem.opcache"); public static interface Op { Object doOp( String key ) throws Exception; } /** * Cache the result of op for no more than limitMs milliseconds. * @param op * @param limitMs */ public ExpensiveOpCache( Op op, int limitMs ) { this.limitMs= limitMs; this.op= op; } Op op; int limitMs; Map results= new HashMap(); Map times= new HashMap(); /** * Do the operation if it has not been done, or if it has not been * done recently. * @param key * @throws Exception, see the given op. * @return the result of the operation */ public Object doOp( String key ) throws Exception { Long t; Object result; synchronized (this ) { t = times.get(key); result= results.get(key); } long t0= System.currentTimeMillis(); long dt= t!=null ? t0 - t : 99999; if ( t==null ) { logger.log(Level.FINE, "no cache entry for: {0}", new Object[]{ key }); result= op.doOp(key); synchronized ( this ) { times.put( key, t0 ); results.put( key, result ); } } else if ( dt > limitMs ) { logger.log(Level.FINE, "stale ({0}s) cache entry {1}: {2}", new Object[]{ dt/1000, key, result.toString()}); result= op.doOp(key); synchronized ( this ) { times.put( key, t0 ); results.put( key, result ); } } else { logger.log(Level.FINE, "using cached value for {0}: {1}", new Object[]{key, result.toString()}); } return result; } public synchronized void reset() { times.clear(); results.clear(); } }