Skip to content
Snippets Groups Projects
Commit 1e44bdb6 authored by Patrick Dowler's avatar Patrick Dowler
Browse files

added support for incomplete cache of groups to improve isMember and getGroup when possible

parent 3e46884c
No related branches found
No related tags found
No related merge requests found
...@@ -774,7 +774,7 @@ public class GMSClient implements TransferListener ...@@ -774,7 +774,7 @@ public class GMSClient implements TransferListener
throw new IllegalArgumentException("userID and role are required."); throw new IllegalArgumentException("userID and role are required.");
} }
List<Group> cachedGroups = getCachedGroups(userID, role); List<Group> cachedGroups = getCachedGroups(userID, role, true);
if (cachedGroups != null) if (cachedGroups != null)
{ {
return cachedGroups; return cachedGroups;
...@@ -881,18 +881,10 @@ public class GMSClient implements TransferListener ...@@ -881,18 +881,10 @@ public class GMSClient implements TransferListener
throw new IllegalArgumentException("userID and role are required."); throw new IllegalArgumentException("userID and role are required.");
} }
List<Group> cachedGroups = getCachedGroups(userID, role); Group cachedGroup = getCachedGroup(userID, groupName, role);
if (cachedGroups != null) if (cachedGroup != null)
{
int index = cachedGroups.indexOf(new Group(groupName));
if (index != -1)
{
return cachedGroups.get(index);
}
else
{ {
return null; return cachedGroup;
}
} }
String idType = AuthenticationUtil.getPrincipalType(userID); String idType = AuthenticationUtil.getPrincipalType(userID);
...@@ -951,9 +943,9 @@ public class GMSClient implements TransferListener ...@@ -951,9 +943,9 @@ public class GMSClient implements TransferListener
} }
if (groups.size() == 1) if (groups.size() == 1)
{ {
// don't cache these results as it is not a complete Group ret = groups.get(0);
// list of memberships--it only applies to one group. addCachedGroup(userID, ret, role);
return groups.get(0); return ret;
} }
throw new IllegalStateException( throw new IllegalStateException(
"Duplicate membership for " + id + " in group " + groupName); "Duplicate membership for " + id + " in group " + groupName);
...@@ -1049,15 +1041,13 @@ public class GMSClient implements TransferListener ...@@ -1049,15 +1041,13 @@ public class GMSClient implements TransferListener
{ {
AccessControlContext acContext = AccessController.getContext(); AccessControlContext acContext = AccessController.getContext();
Subject subject = Subject.getSubject(acContext); Subject subject = Subject.getSubject(acContext);
if (subject != null) if (subject != null)
{ {
log.debug("Clearing cache"); subject.getPrivateCredentials().remove(new GroupMemberships());
subject.getPrivateCredentials().clear();
} }
} }
protected List<Group> getCachedGroups(Principal userID, Role role) protected GroupMemberships getGroupCache(Principal userID)
{ {
AccessControlContext acContext = AccessController.getContext(); AccessControlContext acContext = AccessController.getContext();
Subject subject = Subject.getSubject(acContext); Subject subject = Subject.getSubject(acContext);
...@@ -1065,43 +1055,81 @@ public class GMSClient implements TransferListener ...@@ -1065,43 +1055,81 @@ public class GMSClient implements TransferListener
// only consult cache if the userID is of the calling subject // only consult cache if the userID is of the calling subject
if (userIsSubject(userID, subject)) if (userIsSubject(userID, subject))
{ {
Set groupCredentialSet = subject.getPrivateCredentials(GroupMemberships.class); Set<GroupMemberships> gset = subject.getPrivateCredentials(GroupMemberships.class);
if ((groupCredentialSet != null) && if (gset == null || gset.isEmpty())
(groupCredentialSet.size() == 1))
{ {
Iterator i = groupCredentialSet.iterator(); GroupMemberships mems = new GroupMemberships();
GroupMemberships groupMemberships = ((GroupMemberships) i.next()); subject.getPrivateCredentials().add(mems);
return groupMemberships.memberships.get(role); return mems;
} }
GroupMemberships mems = gset.iterator().next();
return mems;
} }
return null; return null; // no cache
} }
protected void setCachedGroups(Principal userID, List<Group> groups, Role role) protected Group getCachedGroup(Principal userID, String groupID, Role role)
{ {
AccessControlContext acContext = AccessController.getContext(); List<Group> groups = getCachedGroups(userID, role, false);
Subject subject = Subject.getSubject(acContext); if (groups == null)
return null; // no cache
for (Group g : groups)
{
if (g.getID().equals(groupID))
return g;
}
return null;
}
protected List<Group> getCachedGroups(Principal userID, Role role, boolean complete)
{
GroupMemberships mems = getGroupCache(userID);
if (mems == null)
return null; // no cache
// only save to cache if the userID is of the calling subject Boolean cacheState = mems.complete.get(role);
if (userIsSubject(userID, subject)) if (!complete || Boolean.TRUE.equals(cacheState))
return mems.memberships.get(role);
// caller wanted complete and we don't have that
return null;
}
protected void addCachedGroup(Principal userID, Group group, Role role)
{ {
log.debug("Caching groups for " + userID + ", role " + role); GroupMemberships mems = getGroupCache(userID);
if (mems == null)
return; // no cache
final GroupMemberships groupCredentials; List<Group> groups = mems.memberships.get(role);
Set groupCredentialSet = subject.getPrivateCredentials(GroupMemberships.class); if (groups == null)
if ((groupCredentialSet != null) &&
(groupCredentialSet.size() == 1))
{ {
Iterator i = groupCredentialSet.iterator(); groups = new ArrayList<Group>();
groupCredentials = ((GroupMemberships) i.next()); mems.complete.put(role, Boolean.FALSE);
mems.memberships.put(role, groups);
} }
else if (!groups.contains(group))
{ groups.add(group);
groupCredentials = new GroupMemberships();
subject.getPrivateCredentials().add(groupCredentials);
} }
groupCredentials.memberships.put(role, groups); protected void setCachedGroups(Principal userID, List<Group> groups, Role role)
{
GroupMemberships mems = getGroupCache(userID);
if (mems == null)
return; // no cache
log.debug("Caching groups for " + userID + ", role " + role);
List<Group> cur = mems.memberships.get(role);
if (cur == null)
{
cur = new ArrayList<Group>();
mems.complete.put(role, Boolean.FALSE);
mems.memberships.put(role, cur);
}
for (Group group : groups)
{
if (!cur.contains(group))
cur.add(group);
mems.complete.put(role, Boolean.TRUE);
} }
} }
...@@ -1114,7 +1142,7 @@ public class GMSClient implements TransferListener ...@@ -1114,7 +1142,7 @@ public class GMSClient implements TransferListener
for (Principal subjectPrincipal : subject.getPrincipals()) for (Principal subjectPrincipal : subject.getPrincipals())
{ {
if (subjectPrincipal.equals(userID)) if (AuthenticationUtil.equals(subjectPrincipal, userID))
{ {
return true; return true;
} }
...@@ -1123,17 +1151,31 @@ public class GMSClient implements TransferListener ...@@ -1123,17 +1151,31 @@ public class GMSClient implements TransferListener
} }
/** /**
* Class used to hold list of groups in which * Class used to hold list of groups in which a user is known to be a member.
* a user is a member.
*/ */
protected class GroupMemberships protected class GroupMemberships implements Comparable
{ {
Map<Role, List<Group>> memberships = new HashMap<Role, List<Group>>(); Map<Role, List<Group>> memberships = new HashMap<Role, List<Group>>();
Map<Role, Boolean> complete = new HashMap<Role, Boolean>();
protected GroupMemberships() protected GroupMemberships()
{ {
} }
// only allow one in a set - makes clearCache simple too
public boolean equals(Object rhs)
{
if (rhs != null && rhs instanceof GroupMemberships)
return true;
return false;
}
public int compareTo(Object t)
{
if (this.equals(t))
return 0;
return -1; // wonder if this is sketchy
}
} }
} }
...@@ -154,27 +154,38 @@ public class GMSClientTest ...@@ -154,27 +154,38 @@ public class GMSClientTest
public Object run() throws Exception public Object run() throws Exception
{ {
List<Group> initial = client.getCachedGroups(test1UserID, Role.MEMBER); List<Group> initial = client.getCachedGroups(test1UserID, Role.MEMBER, true);
Assert.assertNull("Cache should be null", initial); Assert.assertNull("Cache should be null", initial);
// add single group as isMember might do
Group group0 = new Group("0");
client.addCachedGroup(test1UserID, group0, Role.MEMBER);
List<Group> actual = client.getCachedGroups(test1UserID, Role.MEMBER, true);
Assert.assertNull("Cache should be null", actual);
Group g = client.getCachedGroup(test1UserID, "0", Role.MEMBER);
Assert.assertNotNull("cached group from incomplete cache", g);
// add all groups like getMemberships might do
List<Group> expected = new ArrayList<Group>(); List<Group> expected = new ArrayList<Group>();
Group group1 = new Group("1"); Group group1 = new Group("1");
Group group2 = new Group("2"); Group group2 = new Group("2");
expected.add(group0);
expected.add(group1); expected.add(group1);
expected.add(group2); expected.add(group2);
client.setCachedGroups(test1UserID, expected, Role.MEMBER); client.setCachedGroups(test1UserID, expected, Role.MEMBER);
List<Group> actual = client.getCachedGroups(test1UserID, Role.MEMBER); actual = client.getCachedGroups(test1UserID, Role.MEMBER, true);
Assert.assertEquals("Wrong cached groups", expected, actual); Assert.assertEquals("Wrong cached groups", expected, actual);
// check against another role // check against another role
actual = client.getCachedGroups(test1UserID, Role.OWNER); actual = client.getCachedGroups(test1UserID, Role.OWNER, true);
Assert.assertNull("Cache should be null", actual); Assert.assertNull("Cache should be null", actual);
// check against another userid // check against another userid
final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser"); final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser");
actual = client.getCachedGroups(anotherUserID, Role.MEMBER); actual = client.getCachedGroups(anotherUserID, Role.MEMBER, true);
Assert.assertNull("Cache should be null", actual); Assert.assertNull("Cache should be null", actual);
return null; return null;
...@@ -192,7 +203,7 @@ public class GMSClientTest ...@@ -192,7 +203,7 @@ public class GMSClientTest
public Object run() throws Exception public Object run() throws Exception
{ {
List<Group> initial = client.getCachedGroups(test2UserID, Role.MEMBER); List<Group> initial = client.getCachedGroups(test2UserID, Role.MEMBER, true);
Assert.assertNull("Cache should be null", initial); Assert.assertNull("Cache should be null", initial);
List<Group> expected = new ArrayList<Group>(); List<Group> expected = new ArrayList<Group>();
...@@ -203,16 +214,16 @@ public class GMSClientTest ...@@ -203,16 +214,16 @@ public class GMSClientTest
client.setCachedGroups(test2UserID, expected, Role.MEMBER); client.setCachedGroups(test2UserID, expected, Role.MEMBER);
List<Group> actual = client.getCachedGroups(test2UserID, Role.MEMBER); List<Group> actual = client.getCachedGroups(test2UserID, Role.MEMBER, true);
Assert.assertEquals("Wrong cached groups", expected, actual); Assert.assertEquals("Wrong cached groups", expected, actual);
// check against another role // check against another role
actual = client.getCachedGroups(test2UserID, Role.OWNER); actual = client.getCachedGroups(test2UserID, Role.OWNER, true);
Assert.assertNull("Cache should be null", actual); Assert.assertNull("Cache should be null", actual);
// check against another userid // check against another userid
final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser"); final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser");
actual = client.getCachedGroups(anotherUserID, Role.MEMBER); actual = client.getCachedGroups(anotherUserID, Role.MEMBER, true);
Assert.assertNull("Cache should be null", actual); Assert.assertNull("Cache should be null", actual);
return null; return null;
...@@ -221,7 +232,7 @@ public class GMSClientTest ...@@ -221,7 +232,7 @@ public class GMSClientTest
// do the same without a subject // do the same without a subject
List<Group> initial = client.getCachedGroups(test1UserID, Role.MEMBER); List<Group> initial = client.getCachedGroups(test1UserID, Role.MEMBER, true);
Assert.assertNull("Cache should be null", initial); Assert.assertNull("Cache should be null", initial);
List<Group> newgroups = new ArrayList<Group>(); List<Group> newgroups = new ArrayList<Group>();
...@@ -232,7 +243,7 @@ public class GMSClientTest ...@@ -232,7 +243,7 @@ public class GMSClientTest
client.setCachedGroups(test1UserID, newgroups, Role.MEMBER); client.setCachedGroups(test1UserID, newgroups, Role.MEMBER);
List<Group> actual = client.getCachedGroups(test1UserID, Role.MEMBER); List<Group> actual = client.getCachedGroups(test1UserID, Role.MEMBER, true);
Assert.assertNull("Cache should still be null", actual); Assert.assertNull("Cache should still be null", actual);
} }
catch (Throwable t) catch (Throwable t)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment