Răsfoiți Sursa

SEC-155: BasicaclEntryCache to provide "remove from cache" support.

Ben Alex 19 ani în urmă
părinte
comite
8f6275ab3e

+ 9 - 1
core/src/main/java/org/acegisecurity/acl/basic/BasicAclEntryCache.java

@@ -1,4 +1,4 @@
-/* Copyright 2004 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -58,4 +58,12 @@ public interface BasicAclEntryCache {
      *        from the {@link BasicAclEntry#getAclObjectIdentity()} method
      */
     public void putEntriesInCache(BasicAclEntry[] basicAclEntry);
+
+    /**
+     * Removes all ACL entries related to an {@link AclObjectIdentity} from the
+     * cache.
+     *
+     * @param aclObjectIdentity which should be removed from the cache
+     */
+    public void removeEntriesFromCache(AclObjectIdentity aclObjectIdentity);
 }

+ 16 - 11
core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java

@@ -1,4 +1,4 @@
-/* Copyright 2004 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,20 +15,21 @@
 
 package org.acegisecurity.acl.basic.cache;
 
-import org.acegisecurity.acl.basic.AclObjectIdentity;
-import org.acegisecurity.acl.basic.BasicAclEntry;
-import org.acegisecurity.acl.basic.BasicAclEntryCache;
-
 import net.sf.ehcache.Cache;
 import net.sf.ehcache.CacheException;
 import net.sf.ehcache.Element;
 
+import org.acegisecurity.acl.basic.AclObjectIdentity;
+import org.acegisecurity.acl.basic.BasicAclEntry;
+import org.acegisecurity.acl.basic.BasicAclEntryCache;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.springframework.beans.factory.InitializingBean;
 
 import org.springframework.dao.DataRetrievalFailureException;
+
 import org.springframework.util.Assert;
 
 
@@ -51,8 +52,8 @@ public class EhCacheBasedAclEntryCache implements BasicAclEntryCache,
 
     //~ Methods ================================================================
 
-    public void setCache(Cache cache) {
-        this.cache = cache;
+    public void afterPropertiesSet() throws Exception {
+        Assert.notNull(cache, "cache mandatory");
     }
 
     public Cache getCache() {
@@ -89,10 +90,6 @@ public class EhCacheBasedAclEntryCache implements BasicAclEntryCache,
         return holder.getBasicAclEntries();
     }
 
-    public void afterPropertiesSet() throws Exception {
-        Assert.notNull(cache, "cache mandatory");
-    }
-
     public void putEntriesInCache(BasicAclEntry[] basicAclEntry) {
         BasicAclEntryHolder holder = new BasicAclEntryHolder(basicAclEntry);
         Element element = new Element(basicAclEntry[0].getAclObjectIdentity(),
@@ -104,4 +101,12 @@ public class EhCacheBasedAclEntryCache implements BasicAclEntryCache,
 
         cache.put(element);
     }
+
+    public void removeEntriesFromCache(AclObjectIdentity aclObjectIdentity) {
+        cache.remove(aclObjectIdentity);
+    }
+
+    public void setCache(Cache cache) {
+        this.cache = cache;
+    }
 }

+ 8 - 1
core/src/main/java/org/acegisecurity/acl/basic/cache/NullAclEntryCache.java

@@ -1,4 +1,4 @@
-/* Copyright 2004 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,4 +53,11 @@ public class NullAclEntryCache implements BasicAclEntryCache {
      * @param basicAclEntry ignored
      */
     public void putEntriesInCache(BasicAclEntry[] basicAclEntry) {}
+
+    /**
+     * Meets method signature but doesn't remove from cache.
+     *
+     * @param aclObjectIdentity ignored
+     */
+    public void removeEntriesFromCache(AclObjectIdentity aclObjectIdentity) {}
 }

+ 30 - 0
core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcExtendedDaoImpl.java

@@ -17,7 +17,9 @@ package org.acegisecurity.acl.basic.jdbc;
 
 import org.acegisecurity.acl.basic.AclObjectIdentity;
 import org.acegisecurity.acl.basic.BasicAclEntry;
+import org.acegisecurity.acl.basic.BasicAclEntryCache;
 import org.acegisecurity.acl.basic.BasicAclExtendedDao;
+import org.acegisecurity.acl.basic.cache.NullAclEntryCache;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -32,6 +34,8 @@ import org.springframework.jdbc.core.SqlParameter;
 import org.springframework.jdbc.object.MappingSqlQuery;
 import org.springframework.jdbc.object.SqlUpdate;
 
+import org.springframework.util.Assert;
+
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Types;
@@ -54,6 +58,13 @@ import javax.sql.DataSource;
  * </p>
  * 
  * <p>
+ * If you are using a cache with <code>BasicAclProvider</code>, you should
+ * specify that cache via {@link #setBasicAclEntryCache(BasicAclEntryCache)}.
+ * This will cause cache evictions (removals) to take place whenever a DAO
+ * mutator method is called.
+ * </p>
+ * 
+ * <p>
  * This implementation works with <code>String</code> based recipients and
  * {@link org.acegisecurity.acl.basic.NamedEntityObjectIdentity} only. The
  * latter can be changed by overriding {@link
@@ -82,6 +93,7 @@ public class JdbcExtendedDaoImpl extends JdbcDaoImpl
     private AclPermissionDelete aclPermissionDelete;
     private AclPermissionInsert aclPermissionInsert;
     private AclPermissionUpdate aclPermissionUpdate;
+    private BasicAclEntryCache basicAclEntryCache = new NullAclEntryCache();
     private MappingSqlQuery lookupPermissionIdMapping;
     private String aclObjectIdentityDeleteStatement;
     private String aclObjectIdentityInsertStatement;
@@ -105,6 +117,8 @@ public class JdbcExtendedDaoImpl extends JdbcDaoImpl
 
     public void changeMask(AclObjectIdentity aclObjectIdentity,
         Object recipient, Integer newMask) throws DataAccessException {
+        basicAclEntryCache.removeEntriesFromCache(aclObjectIdentity);
+
         // Retrieve acl_object_identity record details
         AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
 
@@ -164,6 +178,9 @@ public class JdbcExtendedDaoImpl extends JdbcDaoImpl
      */
     private void createAclObjectIdentityIfRequired(BasicAclEntry basicAclEntry)
         throws DataAccessException {
+        basicAclEntryCache.removeEntriesFromCache(basicAclEntry
+            .getAclObjectIdentity());
+
         String aclObjectIdentityString = convertAclObjectIdentityToString(basicAclEntry
                 .getAclObjectIdentity());
 
@@ -189,6 +206,8 @@ public class JdbcExtendedDaoImpl extends JdbcDaoImpl
 
     public void delete(AclObjectIdentity aclObjectIdentity)
         throws DataAccessException {
+        basicAclEntryCache.removeEntriesFromCache(aclObjectIdentity);
+
         // Retrieve acl_object_identity record details
         AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
 
@@ -209,6 +228,8 @@ public class JdbcExtendedDaoImpl extends JdbcDaoImpl
 
     public void delete(AclObjectIdentity aclObjectIdentity, Object recipient)
         throws DataAccessException {
+        basicAclEntryCache.removeEntriesFromCache(aclObjectIdentity);
+
         // Retrieve acl_object_identity record details
         AclDetailsHolder aclDetailsHolder = lookupAclDetailsHolder(aclObjectIdentity);
 
@@ -257,6 +278,10 @@ public class JdbcExtendedDaoImpl extends JdbcDaoImpl
         return aclPermissionUpdateStatement;
     }
 
+    public BasicAclEntryCache getBasicAclEntryCache() {
+        return basicAclEntryCache;
+    }
+
     public MappingSqlQuery getLookupPermissionIdMapping() {
         return lookupPermissionIdMapping;
     }
@@ -371,6 +396,11 @@ public class JdbcExtendedDaoImpl extends JdbcDaoImpl
         this.aclPermissionUpdateStatement = aclPermissionUpdateStatement;
     }
 
+    public void setBasicAclEntryCache(BasicAclEntryCache basicAclEntryCache) {
+        Assert.notNull(basicAclEntryCache, "Cache cannot be set to null");
+        this.basicAclEntryCache = basicAclEntryCache;
+    }
+
     public void setLookupPermissionIdMapping(
         MappingSqlQuery lookupPermissionIdMapping) {
         this.lookupPermissionIdMapping = lookupPermissionIdMapping;

+ 17 - 13
core/src/test/java/org/acegisecurity/acl/basic/BasicAclProviderTests.java

@@ -1,4 +1,4 @@
-/* Copyright 2004, 2005 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,10 +19,12 @@ import junit.framework.TestCase;
 
 import org.acegisecurity.Authentication;
 import org.acegisecurity.PopulatedDatabase;
+
 import org.acegisecurity.acl.AclEntry;
 import org.acegisecurity.acl.basic.cache.BasicAclEntryHolder;
 import org.acegisecurity.acl.basic.cache.NullAclEntryCache;
 import org.acegisecurity.acl.basic.jdbc.JdbcDaoImpl;
+
 import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
 import java.util.HashMap;
@@ -52,14 +54,22 @@ public class BasicAclProviderTests extends TestCase {
 
     //~ Methods ================================================================
 
-    public final void setUp() throws Exception {
-        super.setUp();
-    }
-
     public static void main(String[] args) {
         junit.textui.TestRunner.run(BasicAclProviderTests.class);
     }
 
+    private JdbcDaoImpl makePopulatedJdbcDao() throws Exception {
+        JdbcDaoImpl dao = new JdbcDaoImpl();
+        dao.setDataSource(PopulatedDatabase.getDataSource());
+        dao.afterPropertiesSet();
+
+        return dao;
+    }
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
     public void testCachingUsedProperly() throws Exception {
         BasicAclProvider provider = new BasicAclProvider();
         provider.setBasicAclDao(makePopulatedJdbcDao());
@@ -316,14 +326,6 @@ public class BasicAclProviderTests extends TestCase {
         assertFalse(provider.supports(new Integer(34)));
     }
 
-    private JdbcDaoImpl makePopulatedJdbcDao() throws Exception {
-        JdbcDaoImpl dao = new JdbcDaoImpl();
-        dao.setDataSource(PopulatedDatabase.getDataSource());
-        dao.afterPropertiesSet();
-
-        return dao;
-    }
-
     //~ Inner Classes ==========================================================
 
     private class MockCache implements BasicAclEntryCache {
@@ -371,6 +373,8 @@ public class BasicAclProviderTests extends TestCase {
             BasicAclEntryHolder holder = new BasicAclEntryHolder(basicAclEntry);
             map.put(basicAclEntry[0].getAclObjectIdentity(), holder);
         }
+
+        public void removeEntriesFromCache(AclObjectIdentity aclObjectIdentity) {}
     }
 
     private class MockDao implements BasicAclDao {

+ 18 - 11
core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java

@@ -1,4 +1,4 @@
-/* Copyright 2004 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,14 +17,15 @@ package org.acegisecurity.acl.basic.cache;
 
 import junit.framework.TestCase;
 
+import net.sf.ehcache.Cache;
+
 import org.acegisecurity.MockApplicationContext;
+
 import org.acegisecurity.acl.basic.AclObjectIdentity;
 import org.acegisecurity.acl.basic.BasicAclEntry;
 import org.acegisecurity.acl.basic.NamedEntityObjectIdentity;
 import org.acegisecurity.acl.basic.SimpleAclEntry;
 
-import net.sf.ehcache.Cache;
-
 import org.springframework.context.ApplicationContext;
 
 
@@ -60,14 +61,20 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase {
 
     //~ Methods ================================================================
 
-    public final void setUp() throws Exception {
-        super.setUp();
+    private Cache getCache() {
+        ApplicationContext ctx = MockApplicationContext.getContext();
+
+        return (Cache) ctx.getBean("eHCacheBackend");
     }
 
     public static void main(String[] args) {
         junit.textui.TestRunner.run(EhCacheBasedAclEntryCacheTests.class);
     }
 
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
     public void testCacheOperation() throws Exception {
         EhCacheBasedAclEntryCache cache = new EhCacheBasedAclEntryCache();
         cache.setCache(getCache());
@@ -88,6 +95,12 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase {
                 new NamedEntityObjectIdentity("OBJECT", "200"))[0]);
         assertNull(cache.getEntriesFromCache(
                 new NamedEntityObjectIdentity("OBJECT", "NOT_IN_CACHE")));
+
+        // Check after eviction we cannot get them from cache
+        cache.removeEntriesFromCache(new NamedEntityObjectIdentity("OBJECT",
+                "100"));
+        assertNull(cache.getEntriesFromCache(
+                new NamedEntityObjectIdentity("OBJECT", "100")));
     }
 
     public void testStartupDetectsMissingCache() throws Exception {
@@ -104,10 +117,4 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase {
         cache.setCache(myCache);
         assertEquals(myCache, cache.getCache());
     }
-
-    private Cache getCache() {
-        ApplicationContext ctx = MockApplicationContext.getContext();
-
-        return (Cache) ctx.getBean("eHCacheBackend");
-    }
 }

+ 7 - 5
core/src/test/java/org/acegisecurity/acl/basic/cache/NullAclEntryCacheTests.java

@@ -1,4 +1,4 @@
-/* Copyright 2004 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,18 +41,20 @@ public class NullAclEntryCacheTests extends TestCase {
 
     //~ Methods ================================================================
 
-    public final void setUp() throws Exception {
-        super.setUp();
-    }
-
     public static void main(String[] args) {
         junit.textui.TestRunner.run(NullAclEntryCacheTests.class);
     }
 
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
     public void testCacheOperation() throws Exception {
         NullAclEntryCache cache = new NullAclEntryCache();
         cache.putEntriesInCache(new BasicAclEntry[] {new SimpleAclEntry()});
         cache.getEntriesFromCache(new NamedEntityObjectIdentity("not_used",
                 "not_used"));
+        cache.removeEntriesFromCache(new NamedEntityObjectIdentity("not_used",
+                "not_used"));
     }
 }