Skip to content
This repository has been archived by the owner on Jan 5, 2022. It is now read-only.

Commit

Permalink
Adding cache invalidation at all the right places and support for all…
Browse files Browse the repository at this point in the history
… Principal types makes all tests run except for one.

This guy still fails: PermissionsResourceIT.getNonExistantEntityReturns404:213 expected:<404> but was:<401>
  • Loading branch information
snoopdave committed Sep 29, 2015
1 parent 02fb362 commit b9a7ab1
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 105 deletions.
Expand Up @@ -26,9 +26,11 @@
import com.google.common.hash.Funnel; import com.google.common.hash.Funnel;
import com.google.common.hash.PrimitiveSink; import com.google.common.hash.PrimitiveSink;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.netflix.astyanax.ColumnListMutation;
import com.netflix.astyanax.Keyspace; import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.MutationBatch; import com.netflix.astyanax.MutationBatch;
import com.netflix.astyanax.Serializer; import com.netflix.astyanax.Serializer;
import com.netflix.astyanax.connectionpool.OperationResult;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.connectionpool.exceptions.NotFoundException; import com.netflix.astyanax.connectionpool.exceptions.NotFoundException;
import com.netflix.astyanax.model.Column; import com.netflix.astyanax.model.Column;
Expand Down Expand Up @@ -136,8 +138,13 @@ public V readValue(CacheScope scope, K key, TypeReference typeRef ) {
//V value = MAPPER.readValue(result.getByteArrayValue(), new TypeReference<V>() {}); //V value = MAPPER.readValue(result.getByteArrayValue(), new TypeReference<V>() {});
V value = MAPPER.readValue(result.getByteArrayValue(), typeRef); V value = MAPPER.readValue(result.getByteArrayValue(), typeRef);


logger.debug("Read cache item\n key/value types {}/{}\n key:value: {}:{}", logger.debug("Read cache item from scope {}\n key/value types {}/{}\n key:value: {}:{}",
new Object[]{key.getClass().getSimpleName(), value.getClass().getSimpleName(), key, value}); new Object[]{
scope.getApplication().getUuid(),
key.getClass().getSimpleName(),
value.getClass().getSimpleName(),
key,
value});


return value; return value;


Expand Down Expand Up @@ -192,8 +199,13 @@ public V writeValue(CacheScope scope, K key, V value, Integer ttl) {


executeBatch(batch); executeBatch(batch);


logger.debug("Wrote cache item\n key/value types {}/{}\n key:value: {}:{}", logger.debug("Wrote cache item to scope {}\n key/value types {}/{}\n key:value: {}:{}",
new Object[]{key.getClass().getSimpleName(), value.getClass().getSimpleName(), key, value}); new Object[] {
scope.getApplication().getUuid(),
key.getClass().getSimpleName(),
value.getClass().getSimpleName(),
key,
value});


return value; return value;
} }
Expand Down Expand Up @@ -237,7 +249,10 @@ public void invalidate(CacheScope scope) {
final MutationBatch batch = keyspace.prepareMutationBatch(); final MutationBatch batch = keyspace.prepareMutationBatch();


batch.withRow(SCOPED_CACHE, keyRowKey).delete(); batch.withRow(SCOPED_CACHE, keyRowKey).delete();
executeBatch(batch);
final OperationResult<Void> result = executeBatch(batch);

logger.debug("Invalidated scope {}", scope.getApplication().getUuid());
} }




Expand All @@ -254,9 +269,10 @@ public Void call() throws Exception {
} }




private void executeBatch(MutationBatch batch) { private OperationResult<Void> executeBatch(MutationBatch batch) {
try { try {
batch.execute(); return batch.execute();

} catch (ConnectionException e) { } catch (ConnectionException e) {
throw new RuntimeException("Unable to connect to cassandra", e); throw new RuntimeException("Unable to connect to cassandra", e);
} }
Expand Down
Expand Up @@ -22,6 +22,8 @@
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import org.apache.usergrid.management.ApplicationInfo; import org.apache.usergrid.management.ApplicationInfo;
import org.apache.usergrid.management.OrganizationInfo; import org.apache.usergrid.management.OrganizationInfo;
import org.apache.usergrid.persistence.cache.CacheScope;
import org.apache.usergrid.persistence.cache.ScopedCache;
import org.apache.usergrid.persistence.exceptions.EntityNotFoundException; import org.apache.usergrid.persistence.exceptions.EntityNotFoundException;
import org.apache.usergrid.rest.AbstractContextResource; import org.apache.usergrid.rest.AbstractContextResource;
import org.apache.usergrid.rest.ApiResponse; import org.apache.usergrid.rest.ApiResponse;
Expand Down
Expand Up @@ -17,32 +17,34 @@
package org.apache.usergrid.rest.security.shiro; package org.apache.usergrid.rest.security.shiro;


import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException; import org.apache.shiro.cache.CacheException;
import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.usergrid.corepersistence.util.CpNamingUtils;
import org.apache.usergrid.persistence.cache.CacheFactory; import org.apache.usergrid.persistence.cache.CacheFactory;
import org.apache.usergrid.persistence.cache.CacheScope; import org.apache.usergrid.persistence.cache.CacheScope;
import org.apache.usergrid.persistence.cache.ScopedCache; import org.apache.usergrid.persistence.cache.ScopedCache;
import org.apache.usergrid.persistence.index.utils.UUIDUtils;
import org.apache.usergrid.persistence.model.entity.SimpleId; import org.apache.usergrid.persistence.model.entity.SimpleId;
import org.apache.usergrid.persistence.model.util.UUIDGenerator;
import org.apache.usergrid.security.shiro.UsergridAuthenticationInfo; import org.apache.usergrid.security.shiro.UsergridAuthenticationInfo;
import org.apache.usergrid.security.shiro.UsergridAuthorizationInfo; import org.apache.usergrid.security.shiro.UsergridAuthorizationInfo;
import org.apache.usergrid.security.shiro.principals.AdminUserPrincipal; import org.apache.usergrid.security.shiro.principals.ApplicationPrincipal;
import org.apache.usergrid.security.shiro.principals.OrganizationPrincipal;
import org.apache.usergrid.security.shiro.principals.UserPrincipal; import org.apache.usergrid.security.shiro.principals.UserPrincipal;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import java.util.*; import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;




/** /**
* Plugin Usergrid cache for Shiro. * Plugin Usergrid cache for Shiro.
*/ */
public class ShiroCache<K, V> implements Cache<K,V> { public class ShiroCache<K, V> implements Cache<K,V> {


private static final Logger logger = LoggerFactory.getLogger( ShiroCacheManager.class ); private static final Logger logger = LoggerFactory.getLogger( ShiroCache.class );


CacheFactory<String, V> cacheFactory; CacheFactory<String, V> cacheFactory;


Expand All @@ -60,16 +62,18 @@ public V get(K key) throws CacheException {
if ( scopedCache != null ) { if ( scopedCache != null ) {
V value = scopedCache.get(getKeyString(key), typeRef); V value = scopedCache.get(getKeyString(key), typeRef);


if ( value instanceof UsergridAuthorizationInfo ) { if ( logger.isDebugEnabled() ) {
UsergridAuthorizationInfo info = (UsergridAuthorizationInfo)value; if (value instanceof UsergridAuthorizationInfo) {
logger.debug("Got from AUTHZ cache {} for app {}", getKeyString(key), info.toString()); UsergridAuthorizationInfo info = (UsergridAuthorizationInfo) value;
logger.debug("Got from AUTHZ cache {} for app {}", getKeyString(key), info.toString());


} else if ( value instanceof UsergridAuthenticationInfo ) { } else if (value instanceof UsergridAuthenticationInfo) {
UsergridAuthenticationInfo info = (UsergridAuthenticationInfo)value; UsergridAuthenticationInfo info = (UsergridAuthenticationInfo) value;
logger.debug("Got from AUTHC cache {} for app {}", getKeyString(key), info.toString()); logger.debug("Got from AUTHC cache {} for app {}", getKeyString(key), info.toString());


} else if (value == null) { } else if (value == null) {
logger.debug("Got NULL from cache app {} for key {}", getKeyString(key), key.toString() ); logger.debug("Got NULL from cache app {} for key {}", getKeyString(key), key.toString());
}
} }


return value; return value;
Expand All @@ -83,13 +87,15 @@ public V put(K key, V value) throws CacheException {
if ( scopedCache != null ) { if ( scopedCache != null ) {
V ret = scopedCache.put(getKeyString(key), value, 5000); V ret = scopedCache.put(getKeyString(key), value, 5000);


if ( value instanceof UsergridAuthorizationInfo ) { if ( logger.isDebugEnabled() ) {
UsergridAuthorizationInfo info = (UsergridAuthorizationInfo)value; if (value instanceof UsergridAuthorizationInfo) {
logger.debug("Put to AUTHZ cache {} for app {}", getKeyString(key), info.toString()); UsergridAuthorizationInfo info = (UsergridAuthorizationInfo) value;
logger.debug("Put to AUTHZ cache {} for app {}", getKeyString(key), info.toString());


} else if ( value instanceof UsergridAuthenticationInfo ) { } else if (value instanceof UsergridAuthenticationInfo) {
UsergridAuthenticationInfo info = (UsergridAuthenticationInfo)value; UsergridAuthenticationInfo info = (UsergridAuthenticationInfo) value;
logger.debug("Put to AUTHC cache {} for app {}", getKeyString(key), info.toString()); logger.debug("Put to AUTHC cache {} for app {}", getKeyString(key), info.toString());
}
} }


return ret; return ret;
Expand Down Expand Up @@ -129,53 +135,68 @@ public Collection<V> values() {
/** get cache for application scope */ /** get cache for application scope */
private ScopedCache<String, V> getCacheScope( K key ) { private ScopedCache<String, V> getCacheScope( K key ) {


if ( key instanceof SimplePrincipalCollection) { UUID applicationId;


if ( key instanceof SimplePrincipalCollection) {
SimplePrincipalCollection spc = (SimplePrincipalCollection)key; SimplePrincipalCollection spc = (SimplePrincipalCollection)key;


if ( spc.getPrimaryPrincipal() instanceof AdminUserPrincipal ) { if ( spc.getPrimaryPrincipal() instanceof UserPrincipal ) {
UserPrincipal p = (UserPrincipal) spc.getPrimaryPrincipal();
applicationId = p.getApplicationId();

} else if ( spc.getPrimaryPrincipal() instanceof ApplicationPrincipal ) {
ApplicationPrincipal p = (ApplicationPrincipal)spc.getPrimaryPrincipal();
applicationId = p.getApplicationId();


AdminUserPrincipal p = (AdminUserPrincipal) spc.getPrimaryPrincipal(); } else if ( spc.getPrimaryPrincipal() instanceof OrganizationPrincipal ) {
CacheScope scope = new CacheScope(new SimpleId(p.getApplicationId(), "application")); applicationId = CpNamingUtils.MANAGEMENT_APPLICATION_ID;
ScopedCache<String, V> scopedCache = cacheFactory.getScopedCache(scope);
return scopedCache;


} else { } else {
throw new RuntimeException("Cannot determine application ID for cache scope"); logger.error("Unknown principal type: " + spc.getPrimaryPrincipal().getClass().getSimpleName());
throw new RuntimeException("Unknown principal type: "
+ spc.getPrimaryPrincipal().getClass().getSimpleName());
} }


} else if ( key instanceof AdminUserPrincipal ) { } else if ( key instanceof UserPrincipal ) {
UserPrincipal p = (UserPrincipal)key;
applicationId = p.getApplicationId();


AdminUserPrincipal p = (AdminUserPrincipal)key; } else if ( key instanceof ApplicationPrincipal ) {
CacheScope scope = new CacheScope(new SimpleId(p.getApplicationId(), "application")); ApplicationPrincipal p = (ApplicationPrincipal)key;
ScopedCache<String, V> scopedCache = cacheFactory.getScopedCache(scope); applicationId = p.getApplicationId();
return scopedCache;
} else if ( key instanceof OrganizationPrincipal ) {
applicationId = CpNamingUtils.MANAGEMENT_APPLICATION_ID;


} else { } else {
throw new RuntimeException("Cannot determine application ID for cache scope"); logger.error("Unknown key type: " + key.getClass().getSimpleName());
throw new RuntimeException("Unknown key type: " + key.getClass().getSimpleName());
} }

CacheScope scope = new CacheScope(new SimpleId(applicationId, "application"));
ScopedCache<String, V> scopedCache = cacheFactory.getScopedCache(scope);
return scopedCache;
} }




/** key is the user UUID in string form */ /** key is the user UUID in string form + class name of key */
private String getKeyString( K key ) { private String getKeyString( K key ) {


if ( key instanceof SimplePrincipalCollection) { if ( key instanceof SimplePrincipalCollection) {
SimplePrincipalCollection spc = (SimplePrincipalCollection)key; SimplePrincipalCollection spc = (SimplePrincipalCollection)key;


if ( spc.getPrimaryPrincipal() instanceof UserPrincipal) { if ( spc.getPrimaryPrincipal() instanceof UserPrincipal) {
AdminUserPrincipal p = (AdminUserPrincipal) spc.getPrimaryPrincipal(); UserPrincipal p = (UserPrincipal) spc.getPrimaryPrincipal();
return p.getUser().getUuid().toString(); return p.getUser().getUuid().toString();
} }
} }


return key.toString(); return key.toString() + "_" + key.getClass().getSimpleName();
} }


public void invalidate( UUID applicationId ) { public void invalidate( UUID applicationId ) {
CacheScope scope = new CacheScope( new SimpleId(applicationId, "application") ); CacheScope scope = new CacheScope( new SimpleId(applicationId, "application") );
ScopedCache cache = cacheFactory.getScopedCache(scope); ScopedCache cache = cacheFactory.getScopedCache(scope);
cache.invalidate(); cache.invalidate();

} }
} }
Expand Up @@ -17,7 +17,6 @@
package org.apache.usergrid.rest.applications; package org.apache.usergrid.rest.applications;


import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.sun.jersey.api.client.UniformInterfaceException;
import junit.framework.Assert; import junit.framework.Assert;
import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.RandomStringUtils;
import org.apache.shiro.codec.Base64; import org.apache.shiro.codec.Base64;
Expand Down
Expand Up @@ -17,33 +17,26 @@
package org.apache.usergrid.rest.applications.collection.users; package org.apache.usergrid.rest.applications.collection.users;




import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.usergrid.rest.test.resource.AbstractRestIT; import org.apache.usergrid.rest.test.resource.AbstractRestIT;
import org.apache.usergrid.rest.test.resource.endpoints.CollectionEndpoint; import org.apache.usergrid.rest.test.resource.endpoints.CollectionEndpoint;
import org.apache.usergrid.rest.test.resource.model.ApiResponse; import org.apache.usergrid.rest.test.resource.model.ApiResponse;
import org.apache.usergrid.rest.test.resource.model.Collection; import org.apache.usergrid.rest.test.resource.model.Collection;
import org.apache.usergrid.rest.test.resource.model.Entity; import org.apache.usergrid.rest.test.resource.model.Entity;
import org.apache.usergrid.rest.test.resource.model.QueryParameters; import org.apache.usergrid.rest.test.resource.model.QueryParameters;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.sun.jersey.api.client.UniformInterfaceException; import javax.ws.rs.NotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Map;


import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;




/** /**
* // TODO: Document this * TODO: Document this
*
* @author ApigeeCorporation
* @since 4.0
*/ */
public class ConnectionResourceTest extends AbstractRestIT { public class ConnectionResourceTest extends AbstractRestIT {
private static Logger log = LoggerFactory.getLogger( ConnectionResourceTest.class ); private static Logger log = LoggerFactory.getLogger( ConnectionResourceTest.class );
Expand Down Expand Up @@ -78,11 +71,11 @@ public void connectionsQueryTest() throws IOException {


try { try {


this.app().collection( "users" ).entity( scott ).collection( "likes" ).collection( "peeps" ).entity( peep ) this.app().collection( "users" ).entity( scott )
.get(); .collection("likes").collection( "peeps" ).entity( peep ).get();
fail( "This should throw an exception" ); fail( "This should throw an exception" );
} }
catch ( UniformInterfaceException uie ) { catch ( NotFoundException uie ) {
// Should return a 404 Not Found // Should return a 404 Not Found
assertEquals( 404, uie.getResponse().getStatus() ); assertEquals( 404, uie.getResponse().getStatus() );
} }
Expand All @@ -103,8 +96,8 @@ public void connectionsLoopbackTest() throws IOException {


refreshIndex(); refreshIndex();
//create the connection: thing1 likes thing2 //create the connection: thing1 likes thing2
this.app().collection( "things" ).entity( thing1 ).connection( "likes" ).collection( "things" ).entity( thing2 ) this.app().collection( "things" ).entity( thing1 )
.post(); .connection("likes").collection( "things" ).entity( thing2 ).post();
refreshIndex(); refreshIndex();


//test we have the "likes" in our connection meta data response //test we have the "likes" in our connection meta data response
Expand Down Expand Up @@ -160,8 +153,8 @@ public void connectionsDeleteSecondEntityInConnectionTest() throws IOException {


refreshIndex(); refreshIndex();
//create the connection: thing1 likes thing2 //create the connection: thing1 likes thing2
this.app().collection( "things" ).entity( thing1 ).connection( "likes" ).collection( "things" ).entity( thing2 ) this.app().collection( "things" ).entity( thing1 )
.post(); .connection("likes").collection( "things" ).entity( thing2 ).post();
//delete thing2 //delete thing2
this.app().collection( "things" ).entity( thing2 ).delete(); this.app().collection( "things" ).entity( thing2 ).delete();


Expand All @@ -172,7 +165,7 @@ public void connectionsDeleteSecondEntityInConnectionTest() throws IOException {
thing2 = this.app().collection( "things" ).entity( thing2 ).get(); thing2 = this.app().collection( "things" ).entity( thing2 ).get();
fail( "This should throw an exception" ); fail( "This should throw an exception" );
} }
catch ( UniformInterfaceException uie ) { catch ( NotFoundException uie ) {
// Should return a 404 Not Found // Should return a 404 Not Found
assertEquals( 404, uie.getResponse().getStatus() ); assertEquals( 404, uie.getResponse().getStatus() );
} }
Expand All @@ -196,8 +189,8 @@ public void connectionsDeleteFirstEntityInConnectionTest() throws IOException {


refreshIndex(); refreshIndex();
//create the connection: thing1 likes thing2 //create the connection: thing1 likes thing2
this.app().collection( "things" ).entity( thing1 ).connection( "likes" ).collection( "things" ).entity( thing2 ) this.app().collection( "things" ).entity( thing1 )
.post(); .connection("likes").collection( "things" ).entity( thing2 ).post();
//delete thing1 //delete thing1
this.app().collection( "things" ).entity( thing1 ).delete(); this.app().collection( "things" ).entity( thing1 ).delete();


Expand All @@ -208,7 +201,7 @@ public void connectionsDeleteFirstEntityInConnectionTest() throws IOException {
thing1 = this.app().collection( "things" ).entity( thing1 ).get(); thing1 = this.app().collection( "things" ).entity( thing1 ).get();
fail( "This should throw an exception" ); fail( "This should throw an exception" );
} }
catch ( UniformInterfaceException uie ) { catch ( NotFoundException uie ) {
// Should return a 404 Not Found // Should return a 404 Not Found
assertEquals( 404, uie.getResponse().getStatus() ); assertEquals( 404, uie.getResponse().getStatus() );
} }
Expand Down

0 comments on commit b9a7ab1

Please sign in to comment.