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

This commit is contained in:
Ben Alex 2006-01-27 04:42:39 +00:00
parent 449e395181
commit 8f6275ab3e
7 changed files with 105 additions and 42 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * from the {@link BasicAclEntry#getAclObjectIdentity()} method
*/ */
public void putEntriesInCache(BasicAclEntry[] basicAclEntry); 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);
} }

View File

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

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * @param basicAclEntry ignored
*/ */
public void putEntriesInCache(BasicAclEntry[] basicAclEntry) {} public void putEntriesInCache(BasicAclEntry[] basicAclEntry) {}
/**
* Meets method signature but doesn't remove from cache.
*
* @param aclObjectIdentity ignored
*/
public void removeEntriesFromCache(AclObjectIdentity aclObjectIdentity) {}
} }

View File

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

View File

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

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 junit.framework.TestCase;
import net.sf.ehcache.Cache;
import org.acegisecurity.MockApplicationContext; import org.acegisecurity.MockApplicationContext;
import org.acegisecurity.acl.basic.AclObjectIdentity; import org.acegisecurity.acl.basic.AclObjectIdentity;
import org.acegisecurity.acl.basic.BasicAclEntry; import org.acegisecurity.acl.basic.BasicAclEntry;
import org.acegisecurity.acl.basic.NamedEntityObjectIdentity; import org.acegisecurity.acl.basic.NamedEntityObjectIdentity;
import org.acegisecurity.acl.basic.SimpleAclEntry; import org.acegisecurity.acl.basic.SimpleAclEntry;
import net.sf.ehcache.Cache;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -60,14 +61,20 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase {
//~ Methods ================================================================ //~ Methods ================================================================
public final void setUp() throws Exception { private Cache getCache() {
super.setUp(); ApplicationContext ctx = MockApplicationContext.getContext();
return (Cache) ctx.getBean("eHCacheBackend");
} }
public static void main(String[] args) { public static void main(String[] args) {
junit.textui.TestRunner.run(EhCacheBasedAclEntryCacheTests.class); junit.textui.TestRunner.run(EhCacheBasedAclEntryCacheTests.class);
} }
public final void setUp() throws Exception {
super.setUp();
}
public void testCacheOperation() throws Exception { public void testCacheOperation() throws Exception {
EhCacheBasedAclEntryCache cache = new EhCacheBasedAclEntryCache(); EhCacheBasedAclEntryCache cache = new EhCacheBasedAclEntryCache();
cache.setCache(getCache()); cache.setCache(getCache());
@ -88,6 +95,12 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase {
new NamedEntityObjectIdentity("OBJECT", "200"))[0]); new NamedEntityObjectIdentity("OBJECT", "200"))[0]);
assertNull(cache.getEntriesFromCache( assertNull(cache.getEntriesFromCache(
new NamedEntityObjectIdentity("OBJECT", "NOT_IN_CACHE"))); 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 { public void testStartupDetectsMissingCache() throws Exception {
@ -104,10 +117,4 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase {
cache.setCache(myCache); cache.setCache(myCache);
assertEquals(myCache, cache.getCache()); assertEquals(myCache, cache.getCache());
} }
private Cache getCache() {
ApplicationContext ctx = MockApplicationContext.getContext();
return (Cache) ctx.getBean("eHCacheBackend");
}
} }

View File

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