Coverage report

  %line %branch
org.apache.jetspeed.cache.file.FileCache$FileCacheScanner
0% 
0% 

 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  * 
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  * 
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.jetspeed.cache.file;
 19  
 
 20  
 import java.util.Collection;
 21  
 import java.util.Collections;
 22  
 import java.util.Date;
 23  
 import java.util.Map;
 24  
 import java.util.HashMap;
 25  
 import java.util.List;
 26  
 import java.util.LinkedList;
 27  
 import java.util.Iterator;
 28  
 import java.io.File;
 29  
 import java.io.FileNotFoundException;
 30  
 
 31  
 import org.apache.commons.logging.Log;
 32  
 import org.apache.commons.logging.LogFactory;
 33  
 
 34  
 /**
 35  
  * FileCache keeps a cache of files up-to-date with a most simple eviction policy.
 36  
  * The eviction policy will keep n items in the cache, and then start evicting
 37  
  * the items ordered-by least used first. The cache runs a thread to check for
 38  
  * both evictions and refreshes.
 39  
  *
 40  
  *  @author David S. Taylor <a href="mailto:taylor@apache.org">David Sean Taylor</a>
 41  
  *  @version $Id: FileCache.java 516448 2007-03-09 16:25:47Z ate $
 42  
  */
 43  
 
 44  
 public class FileCache implements java.util.Comparator
 45  
 {
 46  
     protected long scanRate = 300;  // every 5 minutes
 47  
     protected int maxSize = 100; // maximum of 100 items
 48  
     protected List listeners = new LinkedList();
 49  
 
 50  
     private FileCacheScanner scanner = null;
 51  
     private Map cache = null;
 52  
 
 53  
     private final static Log log = LogFactory.getLog(FileCache.class);
 54  
 
 55  
     /**
 56  
      * Default constructor. Use default values for scanReate and maxSize
 57  
      *
 58  
      */
 59  
     public FileCache()
 60  
     {
 61  
         cache = Collections.synchronizedMap(new HashMap());
 62  
         this.scanner = new FileCacheScanner();
 63  
         this.scanner.setDaemon(true);
 64  
     }
 65  
 
 66  
     /**
 67  
      * Set scanRate and maxSize
 68  
      *
 69  
      * @param scanRate how often in seconds to refresh and evict from the cache
 70  
      * @param maxSize the maximum allowed size of the cache before eviction starts
 71  
      */
 72  
     public FileCache(long scanRate, 
 73  
                      int maxSize)
 74  
     {
 75  
         
 76  
         cache = Collections.synchronizedMap(new HashMap());
 77  
 
 78  
         this.scanRate = scanRate;
 79  
         this.maxSize = maxSize;
 80  
         this.scanner = new FileCacheScanner();
 81  
         this.scanner.setDaemon(true);
 82  
     }
 83  
 
 84  
     /**
 85  
      * Set all parameters on the cache
 86  
      *
 87  
      * @param initialCapacity the initial size of the cache as passed to HashMap
 88  
      * @param loadFactor how full the hash table is allowed to get before increasing
 89  
      * @param scanRate how often in seconds to refresh and evict from the cache
 90  
      * @param maxSize the maximum allowed size of the cache before eviction starts
 91  
      */
 92  
     public FileCache(int initialCapacity, 
 93  
                      int loadFactor, 
 94  
                      long scanRate, 
 95  
                      int maxSize)
 96  
     {
 97  
         cache = Collections.synchronizedMap(new HashMap(initialCapacity, loadFactor));
 98  
 
 99  
         this.scanRate = scanRate;
 100  
         this.maxSize = maxSize;
 101  
         this.scanner = new FileCacheScanner();
 102  
         this.scanner.setDaemon(true);
 103  
     }
 104  
 
 105  
     /**
 106  
      * Set the new refresh scan rate on managed files.
 107  
      *
 108  
      * @param scanRate the new scan rate in seconds
 109  
      */
 110  
     public void setScanRate(long scanRate)
 111  
     {
 112  
         this.scanRate= scanRate;
 113  
     }
 114  
 
 115  
     /**
 116  
      * Get the refresh scan rate 
 117  
      *
 118  
      * @return the current refresh scan rate in seconds
 119  
      */
 120  
     public long getScanRate()
 121  
     {
 122  
         return scanRate;
 123  
     }
 124  
 
 125  
     /**
 126  
      * Set the new maximum size of the cache 
 127  
      *
 128  
      * @param maxSize the maximum size of the cache
 129  
      */
 130  
     public void setMaxSize(int maxSize)
 131  
     {
 132  
         this.maxSize = maxSize;
 133  
     }
 134  
 
 135  
     /**
 136  
      * Get the maximum size of the cache 
 137  
      *
 138  
      * @return the current maximum size of the cache
 139  
      */
 140  
     public int getMaxSize()
 141  
     {
 142  
         return maxSize;
 143  
     }
 144  
 
 145  
     /**
 146  
      * Gets an entry from the cache given a key
 147  
      *
 148  
      * @param key the key to look up the entry by
 149  
      * @return the entry
 150  
      */
 151  
     public FileCacheEntry get(String key)
 152  
     {
 153  
         return (FileCacheEntry) cache.get(key);
 154  
     }
 155  
 
 156  
     /**
 157  
      * Gets an entry from the cache given a key
 158  
      *
 159  
      * @param key the key to look up the entry by
 160  
      * @return the entry
 161  
      */
 162  
     public Object getDocument(String key)
 163  
     {
 164  
         FileCacheEntry entry = (FileCacheEntry) cache.get(key);
 165  
         if (entry != null)
 166  
         {
 167  
             return entry.getDocument();
 168  
         }
 169  
         return null;
 170  
     }
 171  
 
 172  
     /**
 173  
      * Puts a file entry in the file cache
 174  
      *
 175  
      * @param file The file to be put in the cache
 176  
      * @param document the cached document
 177  
      */
 178  
     public void put(File file, Object document)
 179  
         throws java.io.IOException
 180  
     {
 181  
         if(!file.exists())
 182  
         {
 183  
             throw new FileNotFoundException("File to cache: "+file.getAbsolutePath()+" does not exist.");
 184  
         }
 185  
         FileCacheEntry entry = new FileCacheEntryImpl(file, document);
 186  
         cache.put(file.getCanonicalPath(), entry);
 187  
     }
 188  
 
 189  
     /**
 190  
      * Puts a file entry in the file cache
 191  
      *
 192  
      * @param path the full path name of the file
 193  
      * @param document the cached document
 194  
      */
 195  
     public void put(String key, Object document, File rootFile)
 196  
         throws java.io.IOException
 197  
     {
 198  
         File file = new File(rootFile, key);
 199  
         if(!file.exists())
 200  
         {
 201  
             throw new FileNotFoundException("File to cache: "+file.getAbsolutePath()+" does not exist.");
 202  
         }
 203  
         FileCacheEntry entry = new FileCacheEntryImpl(file, document);
 204  
         cache.put(key, entry);
 205  
     }
 206  
 
 207  
     /**
 208  
      * Removes a file entry from the file cache
 209  
      *
 210  
      * @param key the full path name of the file
 211  
      * @return the entry removed
 212  
      */
 213  
     public Object remove(String key)
 214  
     {
 215  
         return cache.remove(key);
 216  
     }
 217  
 
 218  
 
 219  
     /**
 220  
      * Add a File Cache Event Listener 
 221  
      *
 222  
      * @param listener the event listener
 223  
      */
 224  
     public void addListener(FileCacheEventListener listener)
 225  
     {
 226  
         listeners.add(listener);
 227  
     }
 228  
 
 229  
     /**
 230  
      * Start the file Scanner running at the current scan rate.
 231  
      *
 232  
      */
 233  
     public void startFileScanner()
 234  
     {
 235  
         try
 236  
         {
 237  
 
 238  
             this.scanner.start();
 239  
         }
 240  
         catch (java.lang.IllegalThreadStateException e)
 241  
         {
 242  
             log.error("Exception starting scanner", e);
 243  
         }
 244  
     }
 245  
 
 246  
     /**
 247  
      * Stop the file Scanner 
 248  
      *
 249  
      */
 250  
     public void stopFileScanner()
 251  
     {
 252  
         this.scanner.setStopping(true);
 253  
     }
 254  
 
 255  
     /**
 256  
      * Evicts entries based on last accessed time stamp
 257  
      *
 258  
      */
 259  
     protected void evict()        
 260  
     {
 261  
         synchronized (cache)
 262  
         {
 263  
             if (this.getMaxSize() >= cache.size())
 264  
             {
 265  
                 return;
 266  
             }
 267  
     
 268  
             List list = new LinkedList(cache.values());
 269  
             Collections.sort(list, this);
 270  
     
 271  
             int count = 0;
 272  
             int limit = cache.size() - this.getMaxSize();
 273  
     
 274  
             for (Iterator it = list.iterator(); it.hasNext(); )
 275  
             {
 276  
                 if (count >= limit)
 277  
                 {
 278  
                     break;
 279  
                 }
 280  
     
 281  
                 FileCacheEntry entry = (FileCacheEntry) it.next();
 282  
                 String key = null;
 283  
                 try
 284  
                 {
 285  
                     key = entry.getFile().getCanonicalPath();
 286  
                 }                    
 287  
                 catch (java.io.IOException e)
 288  
                 {
 289  
                     log.error("Exception getting file path: ", e);
 290  
                 }
 291  
                 // notify that eviction will soon take place
 292  
                 for (Iterator lit = this.listeners.iterator(); lit.hasNext(); )
 293  
                 {
 294  
                     FileCacheEventListener listener = 
 295  
                         (FileCacheEventListener) lit.next();
 296  
                     try
 297  
                     {
 298  
                         listener.evict(entry);
 299  
                     }
 300  
                     catch (Exception e1)
 301  
                     {
 302  
                         log.warn("Unable to evict cache entry.  "+e1.toString(), e1);
 303  
                     }                                    
 304  
                 }
 305  
                 cache.remove(key);
 306  
     
 307  
                 count++;
 308  
             }        
 309  
         }
 310  
     }
 311  
 
 312  
     /**
 313  
      * Evicts all entries
 314  
      *
 315  
      */
 316  
     public void evictAll()        
 317  
     {
 318  
         synchronized (cache)
 319  
         {
 320  
             // evict all cache entries
 321  
             List list = new LinkedList(cache.values());
 322  
             for (Iterator it = list.iterator(); it.hasNext(); )
 323  
             {
 324  
                 // evict cache entry
 325  
                 FileCacheEntry entry = (FileCacheEntry) it.next();
 326  
                 // notify that eviction will soon take place
 327  
                 for (Iterator lit = this.listeners.iterator(); lit.hasNext(); )
 328  
                 {
 329  
                     FileCacheEventListener listener = 
 330  
                         (FileCacheEventListener) lit.next();
 331  
                     try
 332  
                     {
 333  
                         listener.evict(entry);
 334  
                     }
 335  
                     catch (Exception e1)
 336  
                     {
 337  
                         log.warn("Unable to evict cache entry.  "+e1.toString(), e1);
 338  
                     }                                    
 339  
                 }
 340  
                 // remove from cache by key
 341  
                 String key = null;
 342  
                 try
 343  
                 {
 344  
                     key = entry.getFile().getCanonicalPath();
 345  
                 }                    
 346  
                 catch (java.io.IOException e)
 347  
                 {
 348  
                     log.error("Exception getting file path: ", e);
 349  
                 }
 350  
                 cache.remove(key);
 351  
             }        
 352  
         }
 353  
     }
 354  
 
 355  
     /**
 356  
      * Comparator function for sorting by last accessed during eviction
 357  
      *
 358  
      */
 359  
     public int compare(Object o1, Object o2)
 360  
     {
 361  
         FileCacheEntry e1 = (FileCacheEntry)o1;
 362  
         FileCacheEntry e2 = (FileCacheEntry)o2;
 363  
         if (e1.getLastAccessed() < e2.getLastAccessed())
 364  
         {
 365  
             return -1;
 366  
         }
 367  
         else if (e1.getLastAccessed() == e2.getLastAccessed())
 368  
         {
 369  
             return 0;
 370  
         }
 371  
         return 1;
 372  
     }
 373  
 
 374  
     /**
 375  
      * inner class that runs as a thread to scan the cache for updates or evictions
 376  
      *
 377  
      */
 378  0
     protected class FileCacheScanner extends Thread
 379  
     {
 380  0
         private boolean stopping = false;
 381  
 
 382  
         public void setStopping(boolean flag)
 383  
         {
 384  0
             this.stopping = flag;
 385  0
         }
 386  
 
 387  
         /**
 388  
          * Run the file scanner thread
 389  
          *
 390  
          */
 391  
         public void run()
 392  
         {
 393  0
             boolean done = false;
 394  
     
 395  
             try
 396  
             {
 397  0
                 while(!done)
 398  
                 {
 399  
                     try
 400  
                     {
 401  0
                         int count = 0;
 402  0
                         Collection values = Collections.synchronizedCollection(FileCache.this.cache.values());
 403  0
                         synchronized (values)
 404  
                         {
 405  0
                             for (Iterator it = values.iterator(); it.hasNext(); )
 406  
                             {
 407  0
                                 FileCacheEntry entry = (FileCacheEntry) it.next();
 408  0
                                 Date modified = new Date(entry.getFile().lastModified());
 409  
         
 410  0
                                 if (modclass="keyword">ified.after(entry.getLastModclass="keyword">ified()))
 411  
                                 {                            
 412  0
                                     for (Iterator lit = FileCache.this.listeners.iterator(); lit.hasNext(); )
 413  
                                     {
 414  0
                                         FileCacheEventListener listener = 
 415  
                                             (FileCacheEventListener) lit.next();
 416  
                                         try
 417  
                                         {
 418  0
                                             listener.refresh(entry);
 419  
                                         }
 420  0
                                         catch (Exception e1)
 421  
                                         {
 422  0
                                             log.warn("Unable to refresh cached document:  "+e1.toString(), e1);
 423  0
                                         }                                    
 424  0
                                         entry.setLastModified(modified);
 425  0
                                     }
 426  
                                 }
 427  0
                                 count++;
 428  0
                             }
 429  0
                         }
 430  0
                         if (count > FileCache.this.getMaxSize())
 431  
                         {
 432  0
                             FileCache.this.evict();
 433  
                         }
 434  
                     }
 435  0
                     catch (Exception e)
 436  
                     {
 437  0
                         log.error("FileCache Scanner: Error in iteration...", e);
 438  0
                     }
 439  
     
 440  0
                     sleep(FileCache.this.getScanRate() * 1000);                
 441  
 
 442  0
                     if (this.stopping)
 443  
                     {
 444  0
                         this.stopping = false;
 445  0
                         done = true;
 446  
                     }
 447  
                 }
 448  
             }
 449  0
             catch (InterruptedException e)
 450  
             {
 451  0
                 log.error("FileCacheScanner: recieved interruption, exiting.", e);
 452  0
             }
 453  0
         }
 454  
     } // end inner class:  FileCacheScanner
 455  
 
 456  
 
 457  
     /**
 458  
      * get an iterator over the cache values
 459  
      *
 460  
      * @return iterator over the cache values
 461  
      */
 462  
     public Iterator getIterator()
 463  
     {
 464  
         return cache.values().iterator();
 465  
     }
 466  
 
 467  
     /**
 468  
       * get the size of the cache
 469  
       *
 470  
       * @return the size of the cache
 471  
       */
 472  
     public int getSize()
 473  
     {
 474  
         return cache.size();
 475  
     }
 476  
 }
 477  
 

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.