1 package com.atlassian.user.impl.cache;
2
3 import com.atlassian.cache.CacheFactory;
4 import com.atlassian.user.Entity;
5 import com.atlassian.user.EntityException;
6 import com.atlassian.user.Group;
7 import com.atlassian.user.GroupManager;
8 import com.atlassian.user.User;
9 import com.atlassian.user.repository.RepositoryIdentifier;
10 import com.atlassian.user.search.page.DefaultPager;
11 import com.atlassian.user.search.page.Pager;
12 import com.atlassian.user.search.page.PagerUtils;
13 import org.apache.log4j.Category;
14
15 import java.util.LinkedList;
16 import java.util.List;
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public class CachingGroupManager implements GroupManager
33 {
34 private static final Category log = Category.getInstance(CachingGroupManager.class);
35
36 protected final GroupManager underlyingGroupManager;
37 protected final CacheFactory cacheFactory;
38
39 protected GroupCache groupCache = null;
40 protected MembershipCache membershipCache = null;
41 protected GroupsForUserCache groupsForUserCache = null;
42 protected EntityRepositoryCache entityRepositoryCache = null;
43
44 public CachingGroupManager(GroupManager underlyingGroupManager, CacheFactory cacheFactory)
45 {
46 this.underlyingGroupManager = underlyingGroupManager;
47 this.cacheFactory = cacheFactory;
48 initialiseCaches();
49 }
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public Pager<Group> getGroups(User user) throws EntityException
67 {
68 if (user == null)
69 throw new IllegalArgumentException("User cannot be null.");
70 if (log.isInfoEnabled())
71 log.info("Retrieving groups for user [" + user.getName() + "]");
72
73 List<String> groupNames = groupsForUserCache.get(user);
74
75 if (groupNames != null)
76 {
77 if (log.isDebugEnabled())
78 log.debug("Cache hit. Returning pager with " + groupNames.size() + " items.");
79
80 List<Group> groups = new LinkedList<Group>();
81
82 for (Object groupName1 : groupNames)
83 {
84 groups.add(getGroup((String) groupName1));
85 }
86 return new DefaultPager<Group>(groups);
87 }
88
89 if (log.isDebugEnabled())
90 log.debug("Cache miss. Retrieving groups from underlying group manager.");
91
92 List<Group> groups = new LinkedList<Group>();
93 groupNames = new LinkedList<String>();
94
95 for (Group group : underlyingGroupManager.getGroups(user))
96 {
97 groups.add(group);
98 groupCache.put(group.getName(), group);
99 groupNames.add(group.getName());
100 }
101
102 if (log.isDebugEnabled())
103 log.debug("Retrieved " + groupNames.size() + " groups for user [" + user + "], putting in cache.");
104
105 groupsForUserCache.put(user, groupNames);
106
107 return new DefaultPager<Group>(groups);
108 }
109
110 public List<Group> getWritableGroups()
111 {
112 return underlyingGroupManager.getWritableGroups();
113 }
114
115 public Group getGroup(String groupName) throws EntityException
116 {
117 Group cachedGroup = groupCache.get(groupName);
118 if (cachedGroup != null)
119 {
120 return GroupCache.NULL_GROUP.equals(cachedGroup) ? null : cachedGroup;
121 }
122 else
123 {
124 Group group = underlyingGroupManager.getGroup(groupName);
125 groupCache.put(groupName, group);
126 return group;
127 }
128 }
129
130 public Group createGroup(String groupName) throws EntityException
131 {
132 Group createdGroup = underlyingGroupManager.createGroup(groupName);
133
134 if (createdGroup != null)
135 groupCache.put(createdGroup.getName(), createdGroup);
136
137 return createdGroup;
138 }
139
140 public void removeGroup(Group group) throws EntityException
141 {
142 List<String> memberNames = PagerUtils.toList(getMemberNames(group));
143 underlyingGroupManager.removeGroup(group);
144 groupCache.remove(group.getName());
145 groupsForUserCache.remove(memberNames);
146 membershipCache.remove(memberNames, group);
147 entityRepositoryCache.remove(group);
148 }
149
150 public void addMembership(Group group, User user) throws EntityException
151 {
152 underlyingGroupManager.addMembership(group, user);
153 membershipCache.put(user, group, true);
154 groupsForUserCache.remove(user);
155 }
156
157 public boolean hasMembership(Group group, User user) throws EntityException
158 {
159 if(group==null)
160 return false;
161
162 Boolean membershipCheckElement = membershipCache.get(user, group);
163
164 if (membershipCheckElement != null)
165 {
166 return membershipCheckElement;
167 }
168 else
169 {
170 boolean isMember = underlyingGroupManager.hasMembership(group, user);
171 membershipCache.put(user, group, isMember);
172 return isMember;
173 }
174 }
175
176 public void removeMembership(Group group, User user) throws EntityException
177 {
178 underlyingGroupManager.removeMembership(group, user);
179 membershipCache.remove(user, group);
180 groupsForUserCache.remove(user);
181 }
182
183 public RepositoryIdentifier getRepository(Entity entity) throws EntityException
184 {
185 RepositoryIdentifier cachedRepository = entityRepositoryCache.get(entity);
186 if (cachedRepository != null)
187 return cachedRepository;
188
189 RepositoryIdentifier repository = underlyingGroupManager.getRepository(entity);
190 entityRepositoryCache.put(entity, repository);
191 return repository;
192 }
193
194 public Pager<Group> getGroups() throws EntityException
195 {
196 return underlyingGroupManager.getGroups();
197 }
198
199 public Pager<String> getMemberNames(Group group) throws EntityException
200 {
201 return underlyingGroupManager.getMemberNames(group);
202 }
203
204 public Pager<String> getLocalMemberNames(Group group) throws EntityException
205 {
206 return underlyingGroupManager.getLocalMemberNames(group);
207 }
208
209 public Pager<String> getExternalMemberNames(Group group) throws EntityException
210 {
211 return underlyingGroupManager.getExternalMemberNames(group);
212 }
213
214 public boolean supportsExternalMembership() throws EntityException
215 {
216 return underlyingGroupManager.supportsExternalMembership();
217 }
218
219 public boolean isReadOnly(Group group) throws EntityException
220 {
221 return underlyingGroupManager.isReadOnly(group);
222 }
223
224 public RepositoryIdentifier getIdentifier()
225 {
226 return underlyingGroupManager.getIdentifier();
227 }
228
229 public boolean isCreative()
230 {
231 return underlyingGroupManager.isCreative();
232 }
233
234
235
236
237 private void initialiseCaches()
238 {
239 entityRepositoryCache = new EntityRepositoryCache(cacheFactory, getCacheKey("repositories"));
240 groupCache = new GroupCache(cacheFactory, getCacheKey("groups"));
241 membershipCache = new MembershipCache(cacheFactory, getCacheKey("groups_hasMembership"));
242 groupsForUserCache = new GroupsForUserCache(cacheFactory, getCacheKey("groups_getGroupsForUser"));
243 }
244
245
246
247
248 private String getCacheKey(String cacheName)
249 {
250 String className = underlyingGroupManager.getClass().getName();
251 String repositoryKey = underlyingGroupManager.getIdentifier().getKey();
252 return className + "." + repositoryKey + "." + cacheName;
253 }
254 }