Coverage Report - org.apache.shiro.cache.ehcache.EhCacheManager
 
Classes in this File Line Coverage Branch Coverage Complexity
EhCacheManager
71%
38/53
40%
9/22
3.1
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.shiro.cache.ehcache;
 20  
 
 21  
 import org.apache.shiro.cache.Cache;
 22  
 import org.apache.shiro.cache.CacheException;
 23  
 import org.apache.shiro.cache.CacheManager;
 24  
 import org.apache.shiro.config.ConfigurationException;
 25  
 import org.apache.shiro.io.ResourceUtils;
 26  
 import org.apache.shiro.util.Destroyable;
 27  
 import org.apache.shiro.util.Initializable;
 28  
 import org.slf4j.Logger;
 29  
 import org.slf4j.LoggerFactory;
 30  
 
 31  
 import java.io.IOException;
 32  
 import java.io.InputStream;
 33  
 
 34  
 /**
 35  
  * Shiro {@code CacheManager} implementation utilizing the Ehcache framework for all cache functionality.
 36  
  * <p/>
 37  
  * This class can {@link #setCacheManager(net.sf.ehcache.CacheManager) accept} a manually configured
 38  
  * {@link net.sf.ehcache.CacheManager net.sf.ehcache.CacheManager} instance,
 39  
  * or an {@code ehcache.xml} path location can be specified instead and one will be constructed. If neither are
 40  
  * specified, Shiro's failsafe <code><a href="./ehcache.xml">ehcache.xml</a>} file will be used by default.
 41  
  * <p/>
 42  
  * This implementation requires EhCache 1.2 and above. Make sure EhCache 1.1 or earlier
 43  
  * is not in the classpath or it will not work.
 44  
  * <p/>
 45  
  * Please see the <a href="http://ehcache.sf.net" target="_top">Ehcache website</a> for their documentation.
 46  
  *
 47  
  * @see <a href="http://ehcache.sf.net" target="_top">The Ehcache website</a>
 48  
  * @since 0.2
 49  
  */
 50  
 public class EhCacheManager implements CacheManager, Initializable, Destroyable {
 51  
 
 52  
     /**
 53  
      * This class's private log instance.
 54  
      */
 55  1
     private static final Logger log = LoggerFactory.getLogger(EhCacheManager.class);
 56  
 
 57  
     /**
 58  
      * The EhCache cache manager used by this implementation to create caches.
 59  
      */
 60  
     protected net.sf.ehcache.CacheManager manager;
 61  
 
 62  
     /**
 63  
      * Indicates if the CacheManager instance was implicitly/automatically created by this instance, indicating that
 64  
      * it should be automatically cleaned up as well on shutdown.
 65  
      */
 66  2
     private boolean cacheManagerImplicitlyCreated = false;
 67  
 
 68  
     /**
 69  
      * Classpath file location of the ehcache CacheManager config file.
 70  
      */
 71  2
     private String cacheManagerConfigFile = "classpath:org/apache/shiro/cache/ehcache/ehcache.xml";
 72  
 
 73  
     /**
 74  
      * Default no argument constructor
 75  
      */
 76  2
     public EhCacheManager() {
 77  2
     }
 78  
 
 79  
     /**
 80  
      * Returns the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
 81  
      *
 82  
      * @return the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
 83  
      */
 84  
     public net.sf.ehcache.CacheManager getCacheManager() {
 85  6
         return manager;
 86  
     }
 87  
 
 88  
     /**
 89  
      * Sets the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
 90  
      *
 91  
      * @param manager the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
 92  
      */
 93  
     public void setCacheManager(net.sf.ehcache.CacheManager manager) {
 94  0
         this.manager = manager;
 95  0
     }
 96  
 
 97  
     /**
 98  
      * Returns the resource location of the config file used to initialize a new
 99  
      * EhCache CacheManager instance.  The string can be any resource path supported by the
 100  
      * {@link org.apache.shiro.io.ResourceUtils#getInputStreamForPath(String)} call.
 101  
      * <p/>
 102  
      * This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
 103  
      * lazily create a CacheManager if one is not already provided.
 104  
      *
 105  
      * @return the resource location of the config file used to initialize the wrapped
 106  
      *         EhCache CacheManager instance.
 107  
      */
 108  
     public String getCacheManagerConfigFile() {
 109  2
         return this.cacheManagerConfigFile;
 110  
     }
 111  
 
 112  
     /**
 113  
      * Sets the resource location of the config file used to initialize the wrapped
 114  
      * EhCache CacheManager instance.  The string can be any resource path supported by the
 115  
      * {@link org.apache.shiro.io.ResourceUtils#getInputStreamForPath(String)} call.
 116  
      * <p/>
 117  
      * This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
 118  
      * lazily create a CacheManager if one is not already provided.
 119  
      *
 120  
      * @param classpathLocation resource location of the config file used to create the wrapped
 121  
      *                          EhCache CacheManager instance.
 122  
      */
 123  
     public void setCacheManagerConfigFile(String classpathLocation) {
 124  0
         this.cacheManagerConfigFile = classpathLocation;
 125  0
     }
 126  
 
 127  
     /**
 128  
      * Acquires the InputStream for the ehcache configuration file using
 129  
      * {@link ResourceUtils#getInputStreamForPath(String) ResourceUtils.getInputStreamForPath} with the
 130  
      * path returned from {@link #getCacheManagerConfigFile() getCacheManagerConfigFile()}.
 131  
      *
 132  
      * @return the InputStream for the ehcache configuration file.
 133  
      */
 134  
     protected InputStream getCacheManagerConfigFileInputStream() {
 135  2
         String configFile = getCacheManagerConfigFile();
 136  
         try {
 137  2
             return ResourceUtils.getInputStreamForPath(configFile);
 138  0
         } catch (IOException e) {
 139  0
             throw new ConfigurationException("Unable to obtain input stream for cacheManagerConfigFile [" +
 140  
                     configFile + "]", e);
 141  
         }
 142  
     }
 143  
 
 144  
     /**
 145  
      * Loads an existing EhCache from the cache manager, or starts a new cache if one is not found.
 146  
      *
 147  
      * @param name the name of the cache to load/create.
 148  
      */
 149  
     public final <K, V> Cache<K, V> getCache(String name) throws CacheException {
 150  
 
 151  1
         if (log.isTraceEnabled()) {
 152  1
             log.trace("Acquiring EhCache instance named [" + name + "]");
 153  
         }
 154  
 
 155  
         try {
 156  1
             net.sf.ehcache.Ehcache cache = ensureCacheManager().getEhcache(name);
 157  1
             if (cache == null) {
 158  1
                 if (log.isInfoEnabled()) {
 159  1
                     log.info("Cache with name '{}' does not yet exist.  Creating now.", name);
 160  
                 }
 161  1
                 this.manager.addCache(name);
 162  
 
 163  1
                 cache = manager.getCache(name);
 164  
 
 165  1
                 if (log.isInfoEnabled()) {
 166  1
                     log.info("Added EhCache named [" + name + "]");
 167  
                 }
 168  
             } else {
 169  0
                 if (log.isInfoEnabled()) {
 170  0
                     log.info("Using existing EHCache named [" + cache.getName() + "]");
 171  
                 }
 172  
             }
 173  1
             return new EhCache<K, V>(cache);
 174  0
         } catch (net.sf.ehcache.CacheException e) {
 175  0
             throw new CacheException(e);
 176  
         }
 177  
     }
 178  
 
 179  
     /**
 180  
      * Initializes this instance.
 181  
      * <p/>
 182  
      * If a {@link #setCacheManager CacheManager} has been
 183  
      * explicitly set (e.g. via Dependency Injection or programatically) prior to calling this
 184  
      * method, this method does nothing.
 185  
      * <p/>
 186  
      * However, if no {@code CacheManager} has been set, the default Ehcache singleton will be initialized, where
 187  
      * Ehcache will look for an {@code ehcache.xml} file at the root of the classpath.  If one is not found,
 188  
      * Ehcache will use its own failsafe configuration file.
 189  
      * <p/>
 190  
      * Because Shiro cannot use the failsafe defaults (fail-safe expunges cached objects after 2 minutes,
 191  
      * something not desirable for Shiro sessions), this class manages an internal default configuration for
 192  
      * this case.
 193  
      *
 194  
      * @throws org.apache.shiro.cache.CacheException
 195  
      *          if there are any CacheExceptions thrown by EhCache.
 196  
      * @see net.sf.ehcache.CacheManager#create
 197  
      */
 198  
     public final void init() throws CacheException {
 199  1
         ensureCacheManager();
 200  1
     }
 201  
 
 202  
     private net.sf.ehcache.CacheManager ensureCacheManager() {
 203  
         try {
 204  2
             if (this.manager == null) {
 205  2
                 if (log.isDebugEnabled()) {
 206  2
                     log.debug("cacheManager property not set.  Constructing CacheManager instance... ");
 207  
                 }
 208  
                 //using the CacheManager constructor, the resulting instance is _not_ a VM singleton
 209  
                 //(as would be the case by calling CacheManager.getInstance().  We do not use the getInstance here
 210  
                 //because we need to know if we need to destroy the CacheManager instance - using the static call,
 211  
                 //we don't know which component is responsible for shutting it down.  By using a single EhCacheManager,
 212  
                 //it will always know to shut down the instance if it was responsible for creating it.
 213  2
                 this.manager = new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream());
 214  2
                 if (log.isTraceEnabled()) {
 215  2
                     log.trace("instantiated Ehcache CacheManager instance.");
 216  
                 }
 217  2
                 cacheManagerImplicitlyCreated = true;
 218  2
                 if (log.isDebugEnabled()) {
 219  2
                     log.debug("implicit cacheManager created successfully.");
 220  
                 }
 221  
             }
 222  2
             return this.manager;
 223  0
         } catch (Exception e) {
 224  0
             throw new CacheException(e);
 225  
         }
 226  
     }
 227  
 
 228  
     /**
 229  
      * Shuts-down the wrapped Ehcache CacheManager <b>only if implicitly created</b>.
 230  
      * <p/>
 231  
      * If another component injected
 232  
      * a non-null CacheManager into this instace before calling {@link #init() init}, this instance expects that same
 233  
      * component to also destroy the CacheManager instance, and it will not attempt to do so.
 234  
      */
 235  
     public void destroy() {
 236  2
         if (cacheManagerImplicitlyCreated) {
 237  
             try {
 238  2
                 net.sf.ehcache.CacheManager cacheMgr = getCacheManager();
 239  2
                 cacheMgr.shutdown();
 240  0
             } catch (Exception e) {
 241  0
                 if (log.isWarnEnabled()) {
 242  0
                     log.warn("Unable to cleanly shutdown implicitly created CacheManager instance.  " +
 243  
                             "Ignoring (shutting down)...");
 244  
                 }
 245  2
             }
 246  2
             cacheManagerImplicitlyCreated = false;
 247  
         }
 248  2
     }
 249  
 }