You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2010/05/11 08:29:59 UTC

svn commit: r943004 - in /incubator/shiro/trunk: core/src/main/java/org/apache/shiro/cache/ core/src/main/java/org/apache/shiro/config/ core/src/main/java/org/apache/shiro/realm/ core/src/main/java/org/apache/shiro/realm/ldap/ core/src/main/java/org/ap...

Author: lhazlewood
Date: Tue May 11 06:29:58 2010
New Revision: 943004

URL: http://svn.apache.org/viewvc?rev=943004&view=rev
Log:
SHIRO-95 - created test case to verify explicitly set Cache and CacheManager instances are not overwritten by defaults.  Both AuthorizingRealm and CachingSessionDAO were setting their respective caches to null when a CacheManager instance was set - this behavior has been removed as it is unexpected by end-users.  Also made Cache and CacheManager interfaces and implementations generics-capable.  IniSecurityManagerFactoryTest#testCacheManagerConfigOrderOfOperations test method was added to verify functionality.

Added:
    incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java
Removed:
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/DefaultCacheManager.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/SoftHashMapCache.java
Modified:
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/AbstractCacheManager.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/Cache.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/CacheManager.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MapCache.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/CachingRealm.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java
    incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/IniSecurityManagerFactoryTest.java
    incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCache.java
    incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/AbstractCacheManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/AbstractCacheManager.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/AbstractCacheManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/AbstractCacheManager.java Tue May 11 06:29:58 2010
@@ -56,7 +56,7 @@ public abstract class AbstractCacheManag
      * @throws IllegalArgumentException if the {@code name} argument is {@code null} or does not contain text.
      * @throws CacheException           if there is a problem lazily creating a {@code Cache} instance.
      */
-    public Cache getCache(String name) throws IllegalArgumentException, CacheException {
+    public <K, V> Cache<K, V> getCache(String name) throws IllegalArgumentException, CacheException {
         if (!StringUtils.hasText(name)) {
             throw new IllegalArgumentException("Cache name cannot be null or empty.");
         }
@@ -72,6 +72,7 @@ public abstract class AbstractCacheManag
             }
         }
 
+        //noinspection unchecked
         return cache;
     }
 

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/Cache.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/Cache.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/Cache.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/Cache.java Tue May 11 06:29:58 2010
@@ -18,6 +18,7 @@
  */
 package org.apache.shiro.cache;
 
+import java.util.Collection;
 import java.util.Set;
 
 /**
@@ -32,34 +33,36 @@ import java.util.Set;
  * @author Jeremy Haile
  * @since 0.2
  */
-public interface Cache {
+public interface Cache<K, V> {
 
     /**
-     * Returns the Cached value stored under the specified <code>key</code> or
-     * <code>null</code> if there is no Cache entry for that <code>key</code>.
+     * Returns the Cached value stored under the specified {@code key} or
+     * {@code null} if there is no Cache entry for that {@code key}.
      *
      * @param key the key that the value was previous added with
-     * @return the cached object or <tt>null</tt> if there is no Cache entry for the specified <code>key</code>
+     * @return the cached object or {@code null} if there is no entry for the specified {@code key}
      * @throws CacheException if there is a problem accessing the underlying cache system
      */
-    public Object get(Object key) throws CacheException;
+    public V get(K key) throws CacheException;
 
     /**
      * Adds a Cache entry.
      *
      * @param key   the key used to identify the object being stored.
      * @param value the value to be stored in the cache.
+     * @return the previous value associated with the given {@code key} or {@code null} if there was previous value
      * @throws CacheException if there is a problem accessing the underlying cache system
      */
-    public void put(Object key, Object value) throws CacheException;
+    public V put(K key, V value) throws CacheException;
 
     /**
      * Remove the cache entry corresponding to the specified key.
      *
      * @param key the key of the entry to be removed.
+     * @return the previous value associated with the given {@code key} or {@code null} if there was previous value
      * @throws CacheException if there is a problem accessing the underlying cache system
      */
-    public void remove(Object key) throws CacheException;
+    public V remove(K key) throws CacheException;
 
     /**
      * Clear all entries from the cache.
@@ -80,12 +83,12 @@ public interface Cache {
      *
      * @return a view of all the keys for entries contained in this cache.
      */
-    public Set keys();
+    public Set<K> keys();
 
     /**
      * Returns a view of all of the values contained in this cache.
      *
      * @return a view of all of the values contained in this cache.
      */
-    public Set values();
+    public Collection<V> values();
 }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/CacheManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/CacheManager.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/CacheManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/CacheManager.java Tue May 11 06:29:58 2010
@@ -39,5 +39,5 @@ public interface CacheManager {
      * @return the Cache with the given name
      * @throws CacheException if there is an error acquiring the Cache instance.
      */
-    public Cache getCache(String name) throws CacheException;
+    public <K, V> Cache<K, V> getCache(String name) throws CacheException;
 }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MapCache.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MapCache.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MapCache.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MapCache.java Tue May 11 06:29:58 2010
@@ -18,7 +18,12 @@
  */
 package org.apache.shiro.cache;
 
-import java.util.*;
+import org.apache.shiro.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * A <code>MapCache</code> is a {@link Cache Cache} implementation that uses a backing {@link Map} instance to store
@@ -27,19 +32,19 @@ import java.util.*;
  * @author Les Hazlewood
  * @since 1.0
  */
-public class MapCache implements Cache {
+public class MapCache<K, V> implements Cache<K, V> {
 
     /**
      * Backing instance.
      */
-    private final Map map;
+    private final Map<K, V> map;
 
     /**
      * The name of this cache.
      */
     private final String name;
 
-    public MapCache(String name, Map backingMap) {
+    public MapCache(String name, Map<K, V> backingMap) {
         if (name == null) {
             throw new IllegalArgumentException("Cache name cannot be null.");
         }
@@ -50,17 +55,16 @@ public class MapCache implements Cache {
         this.map = backingMap;
     }
 
-    public Object get(Object key) throws CacheException {
+    public V get(K key) throws CacheException {
         return map.get(key);
     }
 
-    @SuppressWarnings({"unchecked"})
-    public void put(Object key, Object value) throws CacheException {
-        map.put(key, value);
+    public V put(K key, V value) throws CacheException {
+        return map.put(key, value);
     }
 
-    public void remove(Object key) throws CacheException {
-        map.remove(key);
+    public V remove(K key) throws CacheException {
+        return map.remove(key);
     }
 
     public void clear() throws CacheException {
@@ -71,27 +75,20 @@ public class MapCache implements Cache {
         return map.size();
     }
 
-    @SuppressWarnings({"unchecked"})
-    public Set keys() {
-        Set keys = map.keySet();
+    public Set<K> keys() {
+        Set<K> keys = map.keySet();
         if (!keys.isEmpty()) {
             return Collections.unmodifiableSet(keys);
         }
-        return Collections.EMPTY_SET;
+        return Collections.emptySet();
     }
 
-    @SuppressWarnings({"unchecked"})
-    public Set values() {
-        if (!map.isEmpty()) {
-            Collection values = map.values();
-            if (values instanceof Set) {
-                return Collections.unmodifiableSet((Set) values);
-            } else {
-                return Collections.unmodifiableSet(new LinkedHashSet(values));
-            }
-        } else {
-            return Collections.EMPTY_SET;
+    public Collection<V> values() {
+        Collection<V> values = map.values();
+        if (!CollectionUtils.isEmpty(values)) {
+            return Collections.unmodifiableCollection(values);
         }
+        return Collections.emptySet();
     }
 
     public String toString() {

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java Tue May 11 06:29:58 2010
@@ -43,6 +43,6 @@ public class MemoryConstrainedCacheManag
      */
     @Override
     protected Cache createCache(String name) {
-        return new MapCache(name, new SoftHashMap());
+        return new MapCache<Object, Object>(name, new SoftHashMap<Object, Object>());
     }
 }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java Tue May 11 06:29:58 2010
@@ -161,7 +161,6 @@ public class ReflectionBuilder {
                 applySingleProperty(objects, name, property, value);
             }
 
-
         } else {
             throw new IllegalArgumentException("All property keys must contain a '.' character. " +
                     "(e.g. myBean.property = value)  These should already be separated out by buildObjects().");
@@ -240,8 +239,16 @@ public class ReflectionBuilder {
         }
         try {
             PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(object, propertyName);
+            if (descriptor == null) {
+                String msg = "Property '" + propertyName + "' does not exist for object of " +
+                        "type " + object.getClass().getName() + ".";
+                throw new ConfigurationException(msg);
+            }
             Class propertyClazz = descriptor.getPropertyType();
             return clazz.isAssignableFrom(propertyClazz);
+        } catch (ConfigurationException ce) {
+            //let it propagate:
+            throw ce;
         } catch (Exception e) {
             String msg = "Unable to determine if property [" + propertyName + "] represents a " + clazz.getName();
             throw new ConfigurationException(msg, e);
@@ -359,8 +366,9 @@ public class ReflectionBuilder {
             }
             BeanUtils.setProperty(object, propertyName, value);
         } catch (Exception e) {
-            String msg = "Unable to set property [" + propertyName + "] with value [" + stringValue + "].  If " +
-                    "'" + stringValue + "' is a reference to another (previously defined) object, please prefix it with " +
+            String msg = "Unable to set property '" + propertyName + "' with value [" + stringValue + "] on object " +
+                    "of type " + (object != null ? object.getClass().getName() : null) + ".  If " +
+                    "'" + stringValue + "' is a reference to another (previously defined) object, prefix it with " +
                     "'" + OBJECT_REFERENCE_BEGIN_TOKEN + "' to indicate that the referenced " +
                     "object should be used as the actual value.  " +
                     "For example, " + OBJECT_REFERENCE_BEGIN_TOKEN + stringValue;

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java Tue May 11 06:29:58 2010
@@ -78,7 +78,7 @@ public abstract class AuthorizingRealm e
      * The cache used by this realm to store AuthorizationInfo instances associated with individual Subject principals.
      */
     private boolean authorizationCachingEnabled;
-    private Cache authorizationCache;
+    private Cache<Object, AuthorizationInfo> authorizationCache;
     private String authorizationCacheName;
 
     private PermissionResolver permissionResolver;
@@ -91,6 +91,8 @@ public abstract class AuthorizingRealm e
 
     public AuthorizingRealm() {
         this.authorizationCachingEnabled = true;
+        this.authorizationCacheName = getClass().getName() + "-" +
+                INSTANCE_COUNT.getAndIncrement() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;
         this.permissionResolver = new WildcardPermissionResolver();
     }
 
@@ -110,14 +112,11 @@ public abstract class AuthorizingRealm e
     |  A C C E S S O R S / M O D I F I E R S    |
     ============================================*/
 
-    public void setAuthorizationCache(Cache authorizationCache) {
+    public void setAuthorizationCache(Cache<Object, AuthorizationInfo> authorizationCache) {
         this.authorizationCache = authorizationCache;
-        if (this.authorizationCache != null) {
-            afterAuthorizationCacheSet();
-        }
     }
 
-    public Cache getAuthorizationCache() {
+    public Cache<Object, AuthorizationInfo> getAuthorizationCache() {
         return this.authorizationCache;
     }
 
@@ -198,9 +197,8 @@ public abstract class AuthorizingRealm e
      * </ol>
      */
     public final void init() {
-        if (isAuthorizationCachingEnabled()) {
-            initAuthorizationCache();
-        }
+        //trigger obtaining the authorization cache if possible
+        getAvailableAuthorizationCache();
         onInit();
     }
 
@@ -208,62 +206,45 @@ public abstract class AuthorizingRealm e
     }
 
     protected void afterCacheManagerSet() {
-        this.authorizationCache = null;
-        if (isAuthorizationCachingEnabled()) {
-            initAuthorizationCache();
-        }
-    }
-
-    protected void afterAuthorizationCacheSet() {
+        //trigger obtaining the authorization cache if possible
+        getAvailableAuthorizationCache();
     }
 
-    protected final String generateAuthorizationCacheName() {
-        //Simple default in case they didn't provide one:
-        return getClass().getName() + "-" + INSTANCE_COUNT.getAndIncrement() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;
-    }
+    private Cache<Object, AuthorizationInfo> getAuthorizationCacheLazy() {
 
-    public void initAuthorizationCache() {
-        if (!isAuthorizationCachingEnabled()) {
-            log.debug("Authorization caching is disabled.  Returning immediately.");
-            return;
-        }
-
-        if (log.isTraceEnabled()) {
-            log.trace("Initializing authorization cache.");
-        }
-
-        Cache cache = getAuthorizationCache();
-
-        if (cache == null) {
+        if (this.authorizationCache == null) {
 
             if (log.isDebugEnabled()) {
-                log.debug("No cache implementation set.  Checking cacheManager...");
+                log.debug("No authorizationCache instance set.  Checking for a cacheManager...");
             }
 
             CacheManager cacheManager = getCacheManager();
 
             if (cacheManager != null) {
                 String cacheName = getAuthorizationCacheName();
-                if (cacheName == null) {
-                    //Simple default in case they didn't provide one:
-                    cacheName = generateAuthorizationCacheName();
-                    setAuthorizationCacheName(cacheName);
-                }
                 if (log.isDebugEnabled()) {
                     log.debug("CacheManager [" + cacheManager + "] has been configured.  Building " +
                             "authorization cache named [" + cacheName + "]");
                 }
-                cache = cacheManager.getCache(cacheName);
-                setAuthorizationCache(cache);
+                this.authorizationCache = cacheManager.getCache(cacheName);
             } else {
                 if (log.isInfoEnabled()) {
-                    log.info("No cache or cacheManager properties have been set.  Authorization caching is " +
-                            "disabled.");
+                    log.info("No cache or cacheManager properties have been set.  Authorization cache cannot " +
+                            "be obtained.");
                 }
             }
         }
+
+        return this.authorizationCache;
     }
 
+    private Cache<Object, AuthorizationInfo> getAvailableAuthorizationCache() {
+        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
+        if (cache == null && isAuthorizationCachingEnabled()) {
+            cache = getAuthorizationCacheLazy();
+        }
+        return cache;
+    }
 
     /**
      * Returns an account's authorization-specific information for the specified {@code principals},
@@ -287,9 +268,9 @@ public abstract class AuthorizingRealm e
      * loosely coupled and not depend on each other.
      * <h3>Caching</h3>
      * The {@code AuthorizationInfo} values returned from this method are cached for efficient reuse
-     * if caching is enabled.  Caching is enabled automatically when a {@code CacheManager} has been
-     * {@link #setCacheManager injected} and then the realm is {@link #init initialized}.  It can also be enabled by
-     * explicitly calling {@link #initAuthorizationCache() initAuthorizationCache()}.
+     * if caching is enabled.  Caching is enabled automatically when an {@link #setAuthorizationCache authorizationCache}
+     * instance has been explicitly configured, or if a {@link #setCacheManager cacheManager} has been configured, which
+     * will be used to lazily create the {@code authorizationCache} as needed.
      * <p/>
      * If caching is enabled, the authorization cache will be checked first and if found, will return the cached
      * {@code AuthorizationInfo} immediately.  If caching is disabled, or there is a cache miss, the authorization
@@ -322,13 +303,13 @@ public abstract class AuthorizingRealm e
             log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
         }
 
-        Cache cache = getAuthorizationCache();
+        Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
         if (cache != null) {
             if (log.isTraceEnabled()) {
                 log.trace("Attempting to retrieve the AuthorizationInfo from cache.");
             }
             Object key = getAuthorizationCacheKey(principals);
-            info = (AuthorizationInfo) cache.get(key);
+            info = cache.get(key);
             if (log.isTraceEnabled()) {
                 if (info == null) {
                     log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");
@@ -378,7 +359,7 @@ public abstract class AuthorizingRealm e
             return;
         }
 
-        Cache cache = getAuthorizationCache();
+        Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
         //cache instance will be non-null if caching is enabled:
         if (cache != null) {
             Object key = getAuthorizationCacheKey(principals);
@@ -397,7 +378,6 @@ public abstract class AuthorizingRealm e
      */
     protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);
 
-    @SuppressWarnings({"unchecked"})
     private Collection<Permission> getPermissions(AuthorizationInfo info) {
         Set<Permission> permissions = new HashSet<Permission>();
 
@@ -418,7 +398,7 @@ public abstract class AuthorizingRealm e
         }
 
         if (permissions.isEmpty()) {
-            return Collections.EMPTY_SET;
+            return Collections.emptySet();
         } else {
             return Collections.unmodifiableSet(permissions);
         }
@@ -462,7 +442,6 @@ public abstract class AuthorizingRealm e
         return isPermitted(permission, info);
     }
 
-    @SuppressWarnings("deprecation")
     private boolean isPermitted(Permission permission, AuthorizationInfo info) {
         //TODO Remove this once AuthorizingAccount class is deleted
         if (info instanceof AuthorizingAccount) {

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/CachingRealm.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/CachingRealm.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/CachingRealm.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/CachingRealm.java Tue May 11 06:29:58 2010
@@ -26,9 +26,9 @@ import java.util.concurrent.atomic.Atomi
 
 
 /**
- * <p>A very basic abstract extension point for the {@link Realm} interface that provides logging and caching support.
+ * A very basic abstract extension point for the {@link Realm} interface that provides caching support.
  * <p/>
- * <p>All actual Realm method implementations are left to subclasses.
+ * All actual Realm method implementations are left to subclasses.
  *
  * @author Les Hazlewood
  * @since 0.9
@@ -67,10 +67,10 @@ public abstract class CachingRealm imple
      * <p/>
      * <p>This property is <tt>null</tt> by default, indicating that caching is turned off.
      *
-     * @param authzInfoCacheManager the <tt>CacheManager</tt> to use for data caching, or <tt>null</tt> to disable caching.
+     * @param cacheManager the <tt>CacheManager</tt> to use for data caching, or <tt>null</tt> to disable caching.
      */
-    public void setCacheManager(CacheManager authzInfoCacheManager) {
-        this.cacheManager = authzInfoCacheManager;
+    public void setCacheManager(CacheManager cacheManager) {
+        this.cacheManager = cacheManager;
         afterCacheManagerSet();
     }
 

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java Tue May 11 06:29:58 2010
@@ -163,11 +163,15 @@ public abstract class AbstractLdapRealm 
     |               M E T H O D S                |
     ============================================*/
 
-    protected void afterAuthorizationCacheSet() {
-        if (ldapContextFactory == null) {
+    protected void onInit() {
+        ensureContextFactory();
+    }
+
+    private LdapContextFactory ensureContextFactory() {
+        if (this.ldapContextFactory == null) {
 
             if (log.isDebugEnabled()) {
-                log.debug("No LdapContextFactory is specified, so a default instance is being created.");
+                log.debug("No LdapContextFactory specified - creating a default instance.");
             }
 
             DefaultLdapContextFactory defaultFactory = new DefaultLdapContextFactory();
@@ -177,17 +181,18 @@ public abstract class AbstractLdapRealm 
             defaultFactory.setSystemUsername(this.systemUsername);
             defaultFactory.setSystemPassword(this.systemPassword);
 
-            ldapContextFactory = defaultFactory;
+            this.ldapContextFactory = defaultFactory;
         }
+        return this.ldapContextFactory;
     }
 
 
     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
         AuthenticationInfo info;
         try {
-            info = queryForAuthenticationInfo(token, this.ldapContextFactory);
+            info = queryForAuthenticationInfo(token, ensureContextFactory());
         } catch (javax.naming.AuthenticationException e) {
-            throw new AuthenticationException( "LDAP authentication failed.", e );
+            throw new AuthenticationException("LDAP authentication failed.", e);
         } catch (NamingException e) {
             String msg = "LDAP naming error while attempting to authenticate user.";
             throw new AuthenticationException(msg, e);
@@ -200,7 +205,7 @@ public abstract class AbstractLdapRealm 
     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
         AuthorizationInfo info;
         try {
-            info = queryForAuthorizationInfo(principals, this.ldapContextFactory);
+            info = queryForAuthorizationInfo(principals, ensureContextFactory());
         } catch (NamingException e) {
             String msg = "LDAP naming error while attempting to retrieve authorization for user [" + principals + "].";
             throw new AuthorizationException(msg, e);

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java Tue May 11 06:29:58 2010
@@ -77,8 +77,6 @@ public class IniRealm extends TextConfig
 
     @Override
     protected void onInit() {
-        // We override init() instead of onInit() because we _don't_ want any caches to be created
-        // (see the superclass init() code).
         // This is an in-memory realm only - no need for an additional cache when we're already
         // as memory-efficient as we can be.
         String resourcePath = getResourcePath();

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java Tue May 11 06:29:58 2010
@@ -62,7 +62,6 @@ public class DefaultSessionManager exten
         this.sessionDAO = sessionDAO;
     }
 
-    @SuppressWarnings({"UnusedDeclaration"})
     public SessionDAO getSessionDAO() {
         return this.sessionDAO;
     }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java Tue May 11 06:29:58 2010
@@ -61,7 +61,7 @@ public abstract class CachingSessionDAO 
     /**
      * The Cache instance responsible for caching Sessions.
      */
-    private Cache activeSessions;
+    private Cache<Serializable, Session> activeSessions;
 
     /**
      * The name of the session cache, defaults to {@link #ACTIVE_SESSION_CACHE_NAME}.
@@ -82,10 +82,6 @@ public abstract class CachingSessionDAO 
      */
     public void setCacheManager(CacheManager cacheManager) {
         this.cacheManager = cacheManager;
-        if (cacheManager != null) {
-            //force cache reload:
-            this.activeSessions = null;
-        }
     }
 
     /**
@@ -127,7 +123,7 @@ public abstract class CachingSessionDAO 
      * @return the cache instance to use for storing active sessions or {@code null} if the {@code Cache} instance
      *         should be retrieved from the
      */
-    public Cache getActiveSessionsCache() {
+    public Cache<Serializable, Session> getActiveSessionsCache() {
         return this.activeSessions;
     }
 
@@ -139,7 +135,7 @@ public abstract class CachingSessionDAO 
      * @param cache the cache instance to use for storing active sessions or {@code null} if the cache is to be
      *              acquired from the {@link #setCacheManager configured} {@code CacheManager}.
      */
-    public void setActiveSessionsCache(Cache cache) {
+    public void setActiveSessionsCache(Cache<Serializable, Session> cache) {
         this.activeSessions = cache;
     }
 
@@ -152,11 +148,9 @@ public abstract class CachingSessionDAO 
      *
      * @return the active sessions cache instance.
      */
-    protected Cache getActiveSessionsCacheLazy() {
-        Cache activeSessions = getActiveSessionsCache();
-        if (activeSessions == null) {
-            activeSessions = createActiveSessionsCache();
-            setActiveSessionsCache(activeSessions);
+    private Cache<Serializable, Session> getActiveSessionsCacheLazy() {
+        if (this.activeSessions == null) {
+            this.activeSessions = createActiveSessionsCache();
         }
         return activeSessions;
     }
@@ -171,8 +165,8 @@ public abstract class CachingSessionDAO 
      * @return a cache instance used to store active sessions, or {@code null} if the {@code CacheManager} has
      *         not been set.
      */
-    protected Cache createActiveSessionsCache() {
-        Cache cache = null;
+    protected Cache<Serializable, Session> createActiveSessionsCache() {
+        Cache<Serializable, Session> cache = null;
         CacheManager mgr = getCacheManager();
         if (mgr != null) {
             String name = getActiveSessionsCacheName();
@@ -204,7 +198,7 @@ public abstract class CachingSessionDAO 
     protected Session getCachedSession(Serializable sessionId) {
         Session cached = null;
         if (sessionId != null) {
-            Cache cache = getActiveSessionsCacheLazy();
+            Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
             if (cache != null) {
                 cached = getCachedSession(sessionId, cache);
             }
@@ -220,8 +214,8 @@ public abstract class CachingSessionDAO 
      * @param cache     the cache to acquire the session from
      * @return the cached session, or {@code null} if the session wasn't in the cache.
      */
-    protected Session getCachedSession(Serializable sessionId, Cache cache) {
-        return (Session) cache.get(sessionId);
+    protected Session getCachedSession(Serializable sessionId, Cache<Serializable, Session> cache) {
+        return cache.get(sessionId);
     }
 
     /**
@@ -235,7 +229,7 @@ public abstract class CachingSessionDAO 
         if (session == null || sessionId == null) {
             return;
         }
-        Cache cache = getActiveSessionsCacheLazy();
+        Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
         if (cache == null) {
             return;
         }
@@ -250,7 +244,7 @@ public abstract class CachingSessionDAO 
      * @param sessionId the id of the session, expected to be the cache key.
      * @param cache     the cache to store the session
      */
-    protected void cache(Session session, Serializable sessionId, Cache cache) {
+    protected void cache(Session session, Serializable sessionId, Cache<Serializable, Session> cache) {
         cache.put(sessionId, session);
     }
 
@@ -331,7 +325,7 @@ public abstract class CachingSessionDAO 
         if (id == null) {
             return;
         }
-        Cache cache = getActiveSessionsCacheLazy();
+        Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
         if (cache != null) {
             cache.remove(id);
         }
@@ -346,9 +340,8 @@ public abstract class CachingSessionDAO 
      *
      * @return the sessions found in the activeSessions cache.
      */
-    @SuppressWarnings({"unchecked"})
     public Collection<Session> getActiveSessions() {
-        Cache cache = getActiveSessionsCacheLazy();
+        Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();
         if (cache != null) {
             return cache.values();
         } else {

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java Tue May 11 06:29:58 2010
@@ -27,7 +27,6 @@ import org.apache.shiro.session.Session;
 import java.io.Serializable;
 import java.util.concurrent.ConcurrentHashMap;
 
-
 /**
  * SessionDAO implementation that relies on an enterprise caching product as the EIS system of record for all sessions.
  * It is expected that an injected {@link org.apache.shiro.cache.Cache Cache} or
@@ -55,8 +54,8 @@ public class EnterpriseCacheSessionDAO e
     public EnterpriseCacheSessionDAO() {
         setCacheManager(new AbstractCacheManager() {
             @Override
-            protected Cache createCache(String name) throws CacheException {
-                return new MapCache(name, new ConcurrentHashMap());
+            protected Cache<Serializable, Session> createCache(String name) throws CacheException {
+                return new MapCache<Serializable, Session>(name, new ConcurrentHashMap<Serializable, Session>());
             }
         });
     }

Added: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java?rev=943004&view=auto
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java (added)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java Tue May 11 06:29:58 2010
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.config;
+
+import org.apache.shiro.cache.AbstractCacheManager;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.cache.MapCache;
+
+import java.util.HashMap;
+
+/**
+ * Returns HashMap-backed cache instances for testing only.  NEVER use this in production, as it would cause
+ * memory leaks since HashMaps retain strong references.
+ *
+ * @author Les Hazlewood
+ * @since 1.0
+ */
+public class HashMapCacheManager<K, V> extends AbstractCacheManager {
+
+    @Override
+    protected Cache createCache(String name) throws CacheException {
+        return new HashMapCache<K, V>(name);
+    }
+
+    //This class is not strictly necessary - it exists to verify a test case only.
+
+    public class HashMapCache<K, V> extends MapCache<K, V> {
+        public HashMapCache(String name) {
+            super(name, new HashMap<K, V>());
+        }
+    }
+}

Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/IniSecurityManagerFactoryTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/IniSecurityManagerFactoryTest.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/IniSecurityManagerFactoryTest.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/IniSecurityManagerFactoryTest.java Tue May 11 06:29:58 2010
@@ -20,13 +20,20 @@ package org.apache.shiro.config;
 
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.MapCache;
 import org.apache.shiro.crypto.hash.Sha256Hash;
 import org.apache.shiro.mgt.DefaultSecurityManager;
 import org.apache.shiro.mgt.SecurityManager;
 import org.apache.shiro.realm.Realm;
 import org.apache.shiro.realm.text.IniRealm;
 import org.apache.shiro.realm.text.PropertiesRealm;
+import org.apache.shiro.session.Session;
 import org.apache.shiro.session.mgt.AbstractSessionManager;
+import org.apache.shiro.session.mgt.DefaultSessionManager;
+import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
+import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
+import org.apache.shiro.session.mgt.eis.SessionDAO;
 import org.apache.shiro.subject.Subject;
 import org.junit.Test;
 
@@ -151,4 +158,50 @@ public class IniSecurityManagerFactoryTe
         });
         assertTrue(subject.getPrincipal().equals("admin"));
     }
+
+    /**
+     * Test case for issue <a href="https://issues.apache.org/jira/browse/SHIRO-95">SHIRO-95</a>.
+     */
+    @Test
+    public void testCacheManagerConfigOrderOfOperations() {
+
+        Ini ini = new Ini();
+        Ini.Section main = ini.addSection(IniSecurityManagerFactory.MAIN_SECTION_NAME);
+        //create a non-default CacheManager:
+        main.put("cacheManager", "org.apache.shiro.config.HashMapCacheManager");
+
+        //now add a session DAO after the cache manager has been set - this is what tests the user-reported issue
+        main.put("sessionDAO", "org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO");
+        main.put("securityManager.sessionManager.sessionDAO", "$sessionDAO");
+
+        //add the cache manager after the sessionDAO has been set:
+        main.put("securityManager.cacheManager", "$cacheManager");
+
+        //add a test user:
+        ini.setSectionProperty(IniRealm.USERS_SECTION_NAME, "admin", "admin");
+
+        IniSecurityManagerFactory factory = new IniSecurityManagerFactory(ini);
+        SecurityManager sm = factory.getInstance();
+
+        //try to log-in:
+        Subject subject = new Subject.Builder(sm).buildSubject();
+        subject.login(new UsernamePasswordToken("admin", "admin"));
+        Session session = subject.getSession();
+        session.setAttribute("hello", "world");
+        //session should have been started, and a cache is in use.  Assert that the SessionDAO is still using
+        //the cache instances provided by our custom CacheManager and not the Default MemoryConstrainedCacheManager
+
+        SessionDAO sessionDAO = ((DefaultSessionManager) ((DefaultSecurityManager) sm).getSessionManager()).getSessionDAO();
+        assertTrue(sessionDAO instanceof EnterpriseCacheSessionDAO);
+        CachingSessionDAO cachingSessionDAO = (CachingSessionDAO) sessionDAO;
+        Cache activeSessionsCache = cachingSessionDAO.getActiveSessionsCache();
+        assertTrue(activeSessionsCache instanceof MapCache);
+        MapCache mapCache = (MapCache) activeSessionsCache;
+
+        //this is the line that verifies Caches created by our specific CacheManager are not overwritten by the
+        //default cache manager's caches:
+        assertTrue(mapCache instanceof HashMapCacheManager.HashMapCache);
+    }
+
+
 }

Modified: incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCache.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCache.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCache.java (original)
+++ incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCache.java Tue May 11 06:29:58 2010
@@ -18,18 +18,14 @@
  */
 package org.apache.shiro.cache.ehcache;
 
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
 import net.sf.ehcache.Element;
-
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.util.CollectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.shiro.cache.Cache;
-import org.apache.shiro.cache.CacheException;
+import java.util.*;
 
 /**
  * Shiro {@link org.apache.shiro.cache.Cache} implementation that wraps an {@link net.sf.ehcache.Ehcache} instance.
@@ -38,10 +34,11 @@ import org.apache.shiro.cache.CacheExcep
  * @author Les Hazlewood
  * @since 0.2
  */
-@SuppressWarnings("unchecked")
-public class EhCache implements Cache {
+public class EhCache<K, V> implements Cache<K, V> {
 
-    /** Private internal log instance. */
+    /**
+     * Private internal log instance.
+     */
     private static final Logger log = LoggerFactory.getLogger(EhCache.class);
 
     /**
@@ -67,7 +64,7 @@ public class EhCache implements Cache {
      * @param key the key of the element to return.
      * @return The value placed into the cache with an earlier put, or null if not found or expired
      */
-    public Object get(Object key) throws CacheException {
+    public V get(K key) throws CacheException {
         try {
             if (log.isTraceEnabled()) {
                 log.trace("Getting object from cache [" + cache.getName() + "] for key [" + key + "]");
@@ -82,11 +79,11 @@ public class EhCache implements Cache {
                     }
                     return null;
                 } else {
-                    return element.getObjectValue();
+                    //noinspection unchecked
+                    return (V) element.getObjectValue();
                 }
             }
-        }
-        catch (Throwable t) {
+        } catch (Throwable t) {
             throw new CacheException(t);
         }
     }
@@ -97,15 +94,16 @@ public class EhCache implements Cache {
      * @param key   the key.
      * @param value the value.
      */
-    public void put(Object key, Object value) throws CacheException {
+    public V put(K key, V value) throws CacheException {
         if (log.isTraceEnabled()) {
             log.trace("Putting object in cache [" + cache.getName() + "] for key [" + key + "]");
         }
         try {
+            V previous = get(key);
             Element element = new Element(key, value);
             cache.put(element);
-        }
-        catch (Throwable t) {
+            return previous;
+        } catch (Throwable t) {
             throw new CacheException(t);
         }
     }
@@ -117,12 +115,14 @@ public class EhCache implements Cache {
      *
      * @param key the key of the element to remove
      */
-    public void remove(Object key) throws CacheException {
+    public V remove(K key) throws CacheException {
         if (log.isTraceEnabled()) {
             log.trace("Removing object from cache [" + cache.getName() + "] for key [" + key + "]");
         }
         try {
+            V previous = get(key);
             cache.remove(key);
+            return previous;
         } catch (Throwable t) {
             throw new CacheException(t);
         }
@@ -150,30 +150,35 @@ public class EhCache implements Cache {
         }
     }
 
-    public Set keys() {
+    public Set<K> keys() {
         try {
-            List keys = cache.getKeys();
-            if (keys != null && !keys.isEmpty()) {
-                return Collections.unmodifiableSet(new LinkedHashSet(keys));
+            @SuppressWarnings({"unchecked"})
+            List<K> keys = cache.getKeys();
+            if (!CollectionUtils.isEmpty(keys)) {
+                return Collections.unmodifiableSet(new LinkedHashSet<K>(keys));
             } else {
-                return Collections.EMPTY_SET;
+                return Collections.emptySet();
             }
         } catch (Throwable t) {
             throw new CacheException(t);
         }
     }
 
-    public Set values() {
+    public Collection<V> values() {
         try {
-            List keys = cache.getKeys();
-            if (keys != null && !keys.isEmpty()) {
-                Set values = new LinkedHashSet(keys.size());
-                for (Object key : keys) {
-                    values.add(cache.get(key));
+            @SuppressWarnings({"unchecked"})
+            List<K> keys = cache.getKeys();
+            if (!CollectionUtils.isEmpty(keys)) {
+                List<V> values = new ArrayList<V>(keys.size());
+                for (K key : keys) {
+                    V value = get(key);
+                    if (value != null) {
+                        values.add(value);
+                    }
                 }
-                return Collections.unmodifiableSet(values);
+                return Collections.unmodifiableList(values);
             } else {
-                return Collections.EMPTY_SET;
+                return Collections.emptyList();
             }
         } catch (Throwable t) {
             throw new CacheException(t);

Modified: incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java?rev=943004&r1=943003&r2=943004&view=diff
==============================================================================
--- incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java (original)
+++ incubator/shiro/trunk/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java Tue May 11 06:29:58 2010
@@ -39,10 +39,10 @@ import java.io.InputStream;
  * or an <code>ehcache.xml</code> path location can be specified instead and one will be constructed. If neither are
  * specified, Shiro's failsafe <code><a href="./ehcache.xml">ehcache.xml</a></code> file will be used by default.
  * <p/>
- * <p>This implementation requires EhCache 1.2 and above. Make sure EhCache 1.1 or earlier
- * is not in the classpath or it will not work.</p>
+ * This implementation requires EhCache 1.2 and above. Make sure EhCache 1.1 or earlier
+ * is not in the classpath or it will not work.
  * <p/>
- * <p>Please see the <a href="http://ehcache.sf.net" target="_top">Ehcache website</a> for their documentation.</p>
+ * Please see the <a href="http://ehcache.sf.net" target="_top">Ehcache website</a> for their documentation.
  *
  * @author Jeremy Haile
  * @author Les Hazlewood
@@ -117,8 +117,8 @@ public class EhCacheManager implements C
      * EhCache CacheManager instance.  The string can be any resource path supported by the
      * {@link org.apache.shiro.io.ResourceUtils#getInputStreamForPath(String)} call.
      * <p/>
-     * <p>This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
-     * lazily create a CacheManager if one is not already provided.</p>
+     * This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
+     * lazily create a CacheManager if one is not already provided.
      *
      * @return the resource location of the config file used to initialize the wrapped
      *         EhCache CacheManager instance.
@@ -132,8 +132,8 @@ public class EhCacheManager implements C
      * EhCache CacheManager instance.  The string can be any resource path supported by the
      * {@link org.apache.shiro.io.ResourceUtils#getInputStreamForPath(String)} call.
      * <p/>
-     * <p>This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
-     * lazily create a CacheManager if one is not already provided.</p>
+     * This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
+     * lazily create a CacheManager if one is not already provided.
      *
      * @param classpathLocation resource location of the config file used to create the wrapped
      *                          EhCache CacheManager instance.
@@ -163,7 +163,7 @@ public class EhCacheManager implements C
      *
      * @param name the name of the cache to load/create.
      */
-    public final Cache getCache(String name) throws CacheException {
+    public final <K, V> Cache<K, V> getCache(String name) throws CacheException {
 
         if (log.isTraceEnabled()) {
             log.trace("Loading a new EhCache cache named [" + name + "]");
@@ -196,7 +196,7 @@ public class EhCacheManager implements C
                     log.info("Using preconfigured EHCache named [" + cache.getName() + "]");
                 }
             }
-            return new EhCache(cache);
+            return new EhCache<K, V>(cache);
         } catch (net.sf.ehcache.CacheException e) {
             throw new CacheException(e);
         }
@@ -224,17 +224,17 @@ public class EhCacheManager implements C
     /**
      * Initializes this instance.
      * <p/>
-     * <p>If a {@link #setCacheManager CacheManager} has been
+     * If a {@link #setCacheManager CacheManager} has been
      * explicitly set (e.g. via Dependency Injection or programatically) prior to calling this
-     * method, this method does nothing.</p>
+     * method, this method does nothing.
      * <p/>
-     * <p>However, if no <tt>CacheManager</tt> has been set, the default Ehcache singleton will be initialized, where
+     * However, if no <tt>CacheManager</tt> has been set, the default Ehcache singleton will be initialized, where
      * Ehcache will look for an <tt>ehcache.xml</tt> file at the root of the classpath.  If one is not found,
-     * Ehcache will use its own failsafe configuration file.</p>
+     * Ehcache will use its own failsafe configuration file.
      * <p/>
-     * <p>Because Shiro cannot use the failsafe defaults (failsafe expunges cached objects after 2 minutes,
+     * Because Shiro cannot use the failsafe defaults (failsafe expunges cached objects after 2 minutes,
      * something not desireable for Shiro sessions), this class manages an internal default configuration for
-     * this case.</p>
+     * this case.
      *
      * @throws org.apache.shiro.cache.CacheException
      *          if there are any CacheExceptions thrown by EhCache.
@@ -270,7 +270,7 @@ public class EhCacheManager implements C
     /**
      * Shuts-down the wrapped Ehcache CacheManager <b>only if implicitly created</b>.
      * <p/>
-     * <p>If another component injected
+     * If another component injected
      * a non-null CacheManager into this instace before calling {@link #init() init}, this instance expects that same
      * component to also destroy the CacheManager instance, and it will not attempt to do so.
      */