diff --git a/core/src/main/java/org/acegisecurity/acl/basic/BasicAclEntryCache.java b/core/src/main/java/org/acegisecurity/acl/basic/BasicAclEntryCache.java index e6c6d1cd3c..1302d45996 100644 --- a/core/src/main/java/org/acegisecurity/acl/basic/BasicAclEntryCache.java +++ b/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); } diff --git a/core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java b/core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java index 8e8bcf75df..dbc2996dc6 100644 --- a/core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java +++ b/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; + } } diff --git a/core/src/main/java/org/acegisecurity/acl/basic/cache/NullAclEntryCache.java b/core/src/main/java/org/acegisecurity/acl/basic/cache/NullAclEntryCache.java index c95f90bac0..50f8b09356 100644 --- a/core/src/main/java/org/acegisecurity/acl/basic/cache/NullAclEntryCache.java +++ b/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) {} } diff --git a/core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcExtendedDaoImpl.java b/core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcExtendedDaoImpl.java index cedb3cffcb..c4af3bade6 100644 --- a/core/src/main/java/org/acegisecurity/acl/basic/jdbc/JdbcExtendedDaoImpl.java +++ b/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; *

* *

+ * If you are using a cache with BasicAclProvider, 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. + *

+ * + *

* This implementation works with String 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; diff --git a/core/src/test/java/org/acegisecurity/acl/basic/BasicAclProviderTests.java b/core/src/test/java/org/acegisecurity/acl/basic/BasicAclProviderTests.java index 1395492501..024e17e540 100644 --- a/core/src/test/java/org/acegisecurity/acl/basic/BasicAclProviderTests.java +++ b/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 { diff --git a/core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java b/core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java index f87e78cbdd..a2bb707621 100644 --- a/core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java +++ b/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"); - } } diff --git a/core/src/test/java/org/acegisecurity/acl/basic/cache/NullAclEntryCacheTests.java b/core/src/test/java/org/acegisecurity/acl/basic/cache/NullAclEntryCacheTests.java index 507f4ff4b4..41fc145f00 100644 --- a/core/src/test/java/org/acegisecurity/acl/basic/cache/NullAclEntryCacheTests.java +++ b/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")); } }