File Source: CacheManager.java

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   *  contributor license agreements.  The ASF licenses this file to You
     4   * under the Apache License, Version 2.0 (the "License"); you may not
     5   * use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.  For additional information regarding
    15   * copyright in this work, please see the NOTICE file in the top level
    16   * directory of this distribution.
    17   */
    18  
    19  package org.apache.roller.weblogger.util.cache;
    20  
    21  import java.util.Date;
    22  import java.util.HashMap;
    23  import java.util.HashSet;
    24  import java.util.Iterator;
    25  import java.util.Map;
    26  import java.util.Set;
    27  import org.apache.commons.logging.Log;
    28  import org.apache.commons.logging.LogFactory;
    29  import org.apache.roller.weblogger.WebloggerException;
    30  import org.apache.roller.weblogger.business.runnable.ContinuousWorkerThread;
    31  import org.apache.roller.weblogger.business.runnable.Job;
    32  import org.apache.roller.weblogger.config.WebloggerConfig;
    33  import org.apache.roller.weblogger.business.WebloggerFactory;
    34  import org.apache.roller.weblogger.business.UserManager;
    35  import org.apache.roller.weblogger.pojos.WeblogBookmark;
    36  import org.apache.roller.weblogger.pojos.WeblogEntryComment;
    37  import org.apache.roller.weblogger.pojos.WeblogBookmarkFolder;
    38  import org.apache.roller.weblogger.pojos.WeblogReferrer;
    39  import org.apache.roller.weblogger.pojos.User;
    40  import org.apache.roller.weblogger.pojos.WeblogCategory;
    41  import org.apache.roller.weblogger.pojos.WeblogEntry;
    42  import org.apache.roller.weblogger.pojos.WeblogTemplate;
    43  import org.apache.roller.weblogger.pojos.Weblog;
    44  
    45  
    46  /**
    47   * A governing class for Roller cache objects.
    48   *
    49   * The purpose of the CacheManager is to provide a level of abstraction between
    50   * classes that use a cache and the implementations of a cache.  This allows
    51   * us to create easily pluggable cache implementations.
    52   * 
    53   * The other purpose is to provide a single interface for interacting with all
    54   * Roller caches at the same time.  This is beneficial because as data
    55   * changes in the system we often need to notify all caches that some part of
    56   * their cached data needs to be invalidated, and the CacheManager makes that
    57   * process easier.
    58   */
    59  public class CacheManager {
    60      
             /* 
    P/P       *  Method: org.apache.roller.weblogger.util.cache.CacheManager__static_init
              * 
              *  Presumptions:
              *    java.lang.Class:forName(...)@82 != null
              *    java.lang.Class:forName(...)@95 != null
              *    java.lang.Object:getClass(...)@103 != null
              *    org.apache.commons.logging.LogFactory:getLog(...)@61 != null
              * 
              *  Postconditions:
              *    " falling back on default"._tainted == 0
              *    "Cache Factory = "._tainted == 0
              *    "Unable to instantiate cache factory ["._tainted == 0
              *    "Unable to instantiate cache handler ["._tainted == 0
              *    "]"._tainted == 0
              *    cacheFactory != null
              *    cacheHandlers == &new HashSet(CacheManager__static_init#1)
              *    caches == &new HashMap(CacheManager__static_init#2)
              *    (soft) log != null
              *    new HashMap(CacheManager__static_init#2) num objects == 1
              *    ...
              * 
              *  Test Vectors:
              *    java.lang.String:length(...)@108: {0}, {1..232-1}
              *    org.apache.roller.weblogger.config.WebloggerConfig:getProperty(...)@107: Addr_Set{null}, Inverse{null}
              */
    61      private static Log log = LogFactory.getLog(CacheManager.class);
    62      
    63      private static final String DEFAULT_FACTORY = 
    64              "org.apache.roller.weblogger.util.cache.ExpiringLRUCacheFactoryImpl";
    65      
    66      // a reference to the cache factory in use
    67      private static CacheFactory cacheFactory = null;
    68      
    69      // a set of all registered cache handlers
    70      private static Set cacheHandlers = new HashSet();
    71      
    72      // a map of all registered caches
    73      private static Map caches = new HashMap();
    74      
    75      
    76      static {
    77          // lookup what cache factory we want to use
    78          String classname = WebloggerConfig.getProperty("cache.defaultFactory");
    79          
    80          // use reflection to instantiate our factory class
    81          try {
    82              Class factoryClass = Class.forName(classname);
    83              cacheFactory = (CacheFactory) factoryClass.newInstance();
    84          } catch(ClassCastException cce) {
    85              log.error("It appears that your factory does not implement "+
    86                      "the CacheFactory interface",cce);
    87          } catch(Exception e) {
    88              log.error("Unable to instantiate cache factory ["+classname+"]"+
    89                      " falling back on default", e);
    90          }
    91          
    92          if(cacheFactory == null) try {
    93              // hmm ... failed to load the specified cache factory
    94              // lets try our default
    95              Class factoryClass = Class.forName(DEFAULT_FACTORY);
    96              cacheFactory = (CacheFactory) factoryClass.newInstance();
    97          } catch(Exception e) {
    98              log.fatal("Failed to instantiate a cache factory", e);
    99              throw new RuntimeException(e);
   100          }
   101          
   102          log.info("Cache Manager Initialized.");
   103          log.info("Cache Factory = "+cacheFactory.getClass().getName());
   104          
   105          
   106          // add custom handlers
   107          String customHandlers = WebloggerConfig.getProperty("cache.customHandlers");
   108          if(customHandlers != null && customHandlers.trim().length() > 0) {
   109              
   110              String[] cHandlers = customHandlers.split(",");
+  111              for(int i=0; i < cHandlers.length; i++) {
   112                  // use reflection to instantiate the handler class
   113                  try {
+  114                      Class handlerClass = Class.forName(cHandlers[i]);
   115                      CacheHandler customHandler = 
   116                              (CacheHandler) handlerClass.newInstance();
   117                      
   118                      cacheHandlers.add(customHandler);
   119                  } catch(ClassCastException cce) {
   120                      log.error("It appears that your handler does not implement "+
   121                              "the CacheHandler interface",cce);
   122                  } catch(Exception e) {
   123                      log.error("Unable to instantiate cache handler ["+cHandlers[i]+"]", e);
   124                  }
   125              }
   126          }
   127      }
   128      
   129      
   130      // a non-instantiable class
             /* 
    P/P       *  Method: void org.apache.roller.weblogger.util.cache.CacheManager()
              */
   131      private CacheManager() {}
   132      
   133      
   134      /**
   135       * Ask the CacheManager to construct a cache.
   136       *
   137       * Normally the CacheManager will use whatever CacheFactory has been
   138       * chosen for the system via the cache.defaultFactory property.
   139       * However, it is possible to override the use of the default factory by
   140       * supplying a "factory" property to this method.  The value should
   141       * be the full classname for the factory you want to use for constructing
   142       * the cache.
   143       *
   144       * example:
   145       *   factory -> org.apache.roller.weblogger.util.cache.LRUCacheFactoryImpl
   146       *
   147       * This allows Roller admins the ability to choose a caching strategy to
   148       * use for the whole system, but override it in certain places where they
   149       * see fit.  It also allows users to write their own caching modifications
   150       * and have them used only by specific caches.
   151       */
   152      public static Cache constructCache(CacheHandler handler, Map properties) {
   153          
                 /* 
    P/P           *  Method: Cache constructCache(CacheHandler, Map)
                  * 
                  *  Preconditions:
                  *    caches != null
                  *    log != null
                  *    properties != null
                  *    (soft) cacheFactory != null
                  *    (soft) cacheHandlers != null
                  * 
                  *  Presumptions:
                  *    java.lang.Class:forName(...)@164 != null
                  * 
                  *  Postconditions:
                  *    return_value != null
                  *    init'ed(new Date(LRUCacheImpl#1) num objects)
                  *    init'ed(new ExpiringLRUCacheImpl(constructCache#1*) num objects)
                  *    possibly_updated(new ExpiringLRUCacheImpl(constructCache#1*).cache)
                  *    possibly_updated(new ExpiringLRUCacheImpl(constructCache#1*).hits)
                  *    possibly_updated(new ExpiringLRUCacheImpl(constructCache#1*).id)
                  *    possibly_updated(new ExpiringLRUCacheImpl(constructCache#1*).misses)
                  *    possibly_updated(new ExpiringLRUCacheImpl(constructCache#1*).puts)
                  *    possibly_updated(new ExpiringLRUCacheImpl(constructCache#1*).removes)
                  *    possibly_updated(new ExpiringLRUCacheImpl(constructCache#1*).startTime)
                  *    ...
                  * 
                  *  Test Vectors:
                  *    handler: Addr_Set{null}, Inverse{null}
                  *    java.util.Map:containsKey(...)@158: {0}, {1}
                  */
   154          log.debug("Constructing new cache with props "+properties);
   155          
   156          Cache cache = null;
   157          
+  158          if(properties != null && properties.containsKey("factory")) {
   159              // someone wants a custom cache instance
   160              String classname = (String) properties.get("factory");
   161              
   162              try {
   163                  // use reflection to instantiate the factory class
   164                  Class factoryClass = Class.forName(classname);
   165                  CacheFactory factory = (CacheFactory) factoryClass.newInstance();
   166                  
   167                  // now ask for a new cache
   168                  cache = factory.constructCache(properties);
   169              } catch(ClassCastException cce) {
   170                  log.error("It appears that your factory ["+classname+
   171                          "] does not implement the CacheFactory interface",cce);
   172              } catch(Exception e) {
   173                  log.error("Unable to instantiate cache factory ["+classname+
   174                          "] falling back on default", e);
   175              }
   176          }
   177          
   178          if(cache == null) {
   179              // ask our default cache factory for a new cache instance
   180              cache = cacheFactory.constructCache(properties);
   181          }
   182          
+  183          if(cache != null) {
   184              caches.put(cache.getId(), cache);
   185              
   186              // register the handler for this new cache
   187              if(handler != null) {
   188                  cacheHandlers.add(handler);
   189              }
   190          }
   191  
   192          return cache;
   193      }
   194      
   195      
   196      /**
   197       * Register a CacheHandler to listen for object invalidations.
   198       *
   199       * This is here so that it's possible to to add classes which would respond
   200       * to object invalidations without necessarily having to create a cache.
   201       *
   202       * An example would be a handler designed to notify other machines in a 
   203       * cluster when an object has been invalidated, or possibly the search
   204       * index management classes are interested in knowing when objects are
   205       * invalidated.
   206       */
   207      public static void registerHandler(CacheHandler handler) {
   208          
                 /* 
    P/P           *  Method: void registerHandler(CacheHandler)
                  * 
                  *  Preconditions:
                  *    log != null
                  *    (soft) cacheHandlers != null
                  * 
                  *  Test Vectors:
                  *    handler: Addr_Set{null}, Inverse{null}
                  */
   209          log.debug("Registering handler "+handler);
   210          
   211          if(handler != null) {
   212              cacheHandlers.add(handler);
   213          }
   214      }
   215      
   216      
   217      public static void invalidate(WeblogEntry entry) {
   218          
                 /* 
    P/P           *  Method: void invalidate(WeblogEntry)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    entry != null
                  *    log != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@223 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@222: {0}, {1}
                  */
   219          log.debug("invalidating entry = "+entry.getAnchor());
   220          
   221          Iterator handlers = cacheHandlers.iterator();
   222          while(handlers.hasNext()) {
   223              ((CacheHandler) handlers.next()).invalidate(entry);
   224          }
   225      }
   226      
   227      
   228      public static void invalidate(Weblog website) {
   229          
                 /* 
    P/P           *  Method: void invalidate(Weblog)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    log != null
                  *    website != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@234 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@233: {0}, {1}
                  */
   230          log.debug("invalidating website = "+website.getHandle());
   231          
   232          Iterator handlers = cacheHandlers.iterator();
   233          while(handlers.hasNext()) {
   234              ((CacheHandler) handlers.next()).invalidate(website);
   235          }
   236      }
   237      
   238      
   239      public static void invalidate(WeblogBookmark bookmark) {
   240          
                 /* 
    P/P           *  Method: void invalidate(WeblogBookmark)
                  * 
                  *  Preconditions:
                  *    bookmark != null
                  *    cacheHandlers != null
                  *    log != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@245 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@244: {0}, {1}
                  */
   241          log.debug("invalidating bookmark = "+bookmark.getId());
   242          
   243          Iterator handlers = cacheHandlers.iterator();
   244          while(handlers.hasNext()) {
   245              ((CacheHandler) handlers.next()).invalidate(bookmark);
   246          }
   247      }
   248      
   249      
   250      public static void invalidate(WeblogBookmarkFolder folder) {
   251          
                 /* 
    P/P           *  Method: void invalidate(WeblogBookmarkFolder)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    folder != null
                  *    log != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@256 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@255: {0}, {1}
                  */
   252          log.debug("invalidating folder = "+folder.getId());
   253          
   254          Iterator handlers = cacheHandlers.iterator();
   255          while(handlers.hasNext()) {
   256              ((CacheHandler) handlers.next()).invalidate(folder);
   257          }
   258      }
   259      
   260      
   261      public static void invalidate(WeblogEntryComment comment) {
   262          
                 /* 
    P/P           *  Method: void invalidate(WeblogEntryComment)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    comment != null
                  *    log != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@267 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@266: {0}, {1}
                  */
   263          log.debug("invalidating comment = "+comment.getId());
   264          
   265          Iterator handlers = cacheHandlers.iterator();
   266          while(handlers.hasNext()) {
   267              ((CacheHandler) handlers.next()).invalidate(comment);
   268          }
   269      }
   270      
   271      
   272      public static void invalidate(WeblogReferrer referer) {
   273          
                 /* 
    P/P           *  Method: void invalidate(WeblogReferrer)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    log != null
                  *    referer != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@282 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@281: {0}, {1}
                  */
   274          log.debug("invalidating referer = "+referer.getId());
   275          
   276          // NOTE: Invalidating an entire website for each referer is not
   277          //       good for our caching.  This may need reevaluation later.
   278          //lastExpiredCache.put(referer.getWebsite().getHandle(), new Date());
   279          
   280          Iterator handlers = cacheHandlers.iterator();
   281          while(handlers.hasNext()) {
   282              ((CacheHandler) handlers.next()).invalidate(referer);
   283          }
   284      }
   285      
   286      
   287      public static void invalidate(User user) {
   288          
                 /* 
    P/P           *  Method: void invalidate(User)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    log != null
                  *    user != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@293 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@292: {0}, {1}
                  */
   289          log.debug("invalidating user = "+user.getUserName());
   290          
   291          Iterator handlers = cacheHandlers.iterator();
   292          while(handlers.hasNext()) {
   293              ((CacheHandler) handlers.next()).invalidate(user);
   294          }
   295      }
   296      
   297      
   298      public static void invalidate(WeblogCategory category) {
   299          
                 /* 
    P/P           *  Method: void invalidate(WeblogCategory)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    category != null
                  *    log != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@304 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@303: {0}, {1}
                  */
   300          log.debug("invalidating category = "+category.getId());
   301          
   302          Iterator handlers = cacheHandlers.iterator();
   303          while(handlers.hasNext()) {
   304              ((CacheHandler) handlers.next()).invalidate(category);
   305          }
   306      }
   307      
   308      
   309      public static void invalidate(WeblogTemplate template) {
   310          
                 /* 
    P/P           *  Method: void invalidate(WeblogTemplate)
                  * 
                  *  Preconditions:
                  *    cacheHandlers != null
                  *    log != null
                  *    template != null
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@315 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@314: {0}, {1}
                  */
   311          log.debug("invalidating template = "+template.getId());
   312          
   313          Iterator handlers = cacheHandlers.iterator();
   314          while(handlers.hasNext()) {
   315              ((CacheHandler) handlers.next()).invalidate(template);
   316          }
   317      }
   318  
   319      
   320      /**
   321       * Flush the entire cache system.
   322       */
   323      public static void clear() {
   324          
   325          // loop through all caches and trigger a clear
                 /* 
    P/P           *  Method: void clear()
                  * 
                  *  Preconditions:
                  *    caches != null
                  * 
                  *  Presumptions:
                  *    cache.cache@329 != null
                  *    java.util.Iterator:next(...)@329 != null
                  *    java.util.Map:values(...)@327 != null
                  * 
                  *  Postconditions:
                  *    init'ed(new Date(clear#1*) num objects)
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@328: {0}, {1}
                  */
   326          Cache cache = null;
   327          Iterator cachesIT = caches.values().iterator();
   328          while(cachesIT.hasNext()) {
   329              cache = (Cache) cachesIT.next();
   330              
   331              cache.clear();
   332          }
   333      }
   334      
   335      
   336      /**
   337       * Flush a single cache.
   338       */
   339      public static void clear(String cacheId) {
   340          
                 /* 
    P/P           *  Method: void clear(String)
                  * 
                  *  Preconditions:
                  *    caches != null
                  * 
                  *  Presumptions:
                  *    cache.cache@341 != null
                  * 
                  *  Postconditions:
                  *    new Date(clear#1*) num objects <= 1
                  * 
                  *  Test Vectors:
                  *    java.util.Map:get(...)@341: Addr_Set{null}, Inverse{null}
                  */
   341          Cache cache = (Cache) caches.get(cacheId);
   342          if(cache != null) {
   343              cache.clear();
   344          }
   345      }
   346      
   347      
   348      /**
   349       * Compile stats from all registered caches.
   350       *
   351       * This is basically a hacky version of instrumentation which is being
   352       * thrown in because we don't have a full instrumentation strategy yet.
   353       * This is here with the full expectation that it will be replaced by
   354       * something a bit more elaborate, like JMX.
   355       */
   356      public static Map getStats() {
   357          
                 /* 
    P/P           *  Method: Map getStats()
                  * 
                  *  Preconditions:
                  *    caches != null
                  * 
                  *  Presumptions:
                  *    cache.hits@363 + cache.misses@363 != +0
                  *    java.util.Iterator:next(...)@363 != null
                  *    java.util.Map:values(...)@361 != null
                  * 
                  *  Postconditions:
                  *    return_value == &new HashMap(getStats#1)
                  *    new HashMap(getStats#1) num objects == 1
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@362: {0}, {1}
                  */
   358          Map allStats = new HashMap();
   359          
   360          Cache cache = null;
   361          Iterator cachesIT = caches.values().iterator();
   362          while(cachesIT.hasNext()) {
   363              cache = (Cache) cachesIT.next();
   364              
   365              allStats.put(cache.getId(), cache.getStats());
   366          }
   367          
   368          return allStats;
   369      }
   370      
   371      
   372      /**
   373       * Place to do any cleanup tasks for cache system.
   374       */
   375      public static void shutdown() {
   376          // no-op
             /* 
    P/P       *  Method: void shutdown()
              */
   377      }
   378      
   379  }








SofCheck Inspector Build Version : 2.18479
CacheManager.java 2009-Jan-02 14:25:42
CacheManager.class 2009-Sep-04 03:12:32