1   package com.atlassian.user.impl.delegation;
2   
3   import com.atlassian.user.*;
4   import com.atlassian.user.impl.delegation.repository.DelegatingRepository;
5   import com.atlassian.user.repository.RepositoryIdentifier;
6   import com.atlassian.user.search.page.DefaultPager;
7   import com.atlassian.user.search.page.Pager;
8   import com.atlassian.user.search.page.PagerFactory;
9   import com.atlassian.user.util.Assert;
10  import org.apache.log4j.Logger;
11  
12  import java.util.*;
13  
14  /*
15   * Group manager with a list of other group managers to delegate to.
16   * The group managers are tried in the iteration order of the list.
17   */
18  public class DelegatingGroupManager implements GroupManager
19  {
20      private static final Logger log = Logger.getLogger(DelegatingGroupManager.class);
21  
22      private final List<GroupManager> groupManagers = new ArrayList<GroupManager>();
23  
24      public DelegatingGroupManager(List<GroupManager> groupManagers)
25      {
26          this.groupManagers.addAll(groupManagers);
27      }
28  
29      /**
30       * @return an unmodifiable list of {@link GroupManager}s which this manager delegates to,
31       * in the order of delegation.
32       */
33      public List<GroupManager> getGroupManagers()
34      {
35          return Collections.unmodifiableList(groupManagers);
36      }
37  
38      /**
39       * Returns the first group manager in iteration order which returns a non-null value from
40       * {@link GroupManager#getGroup(String)}, or the last group manager in the iteration
41       * order if no group manager meets this criteria.
42       *
43       * @throws EntityException if any of the delegating managers throws an exception
44       * in {@link GroupManager#getGroup(String)}.
45       * @throws NullPointerException if the group is null
46       * @param groupName the name of the group to match against
47       */
48      private GroupManager getMatchingGroupManager(String groupName) throws EntityException
49      {
50          GroupManager lastFoundGroupManager = null;
51  
52          for (GroupManager groupManager : groupManagers)
53          {
54              lastFoundGroupManager = groupManager;
55  
56              if (groupManager.getGroup(groupName) != null)
57                  return groupManager;
58          }
59  
60          // returns the last groupManager if none matched
61          return lastFoundGroupManager;
62      }
63  
64      public Pager<Group> getGroups() throws EntityException
65      {
66          List<Pager<Group>> groups = new ArrayList<Pager<Group>>();
67  
68          for (GroupManager groupManager : groupManagers)
69          {
70              try
71              {
72                  groups.add(groupManager.getGroups());
73              }
74              catch (EntityException e)
75              {
76                  log.error("Failed to retrieve groups from group manager in delegation: " +
77                          groupManager.getClass().toString() + ". Continuing with remaining managers.", e);
78              }
79          }
80  
81          return PagerFactory.getPager(groups);
82      }
83  
84      public Pager<Group> getGroups(User user) throws EntityException
85      {
86          Assert.notNull(user, "User must not be null");
87  		List<Pager<Group>> pagers = new LinkedList<Pager<Group>>();
88  
89          for (GroupManager groupManager : groupManagers)
90          {
91              try
92              {
93                  Pager<Group> groupPager = groupManager.getGroups(user);
94                  pagers.add(groupPager);
95              }
96              catch (EntityException e)
97              {
98                  log.error("Failed to retrieve groups for user [" + user + "] from group manager: " +
99                          groupManager.getClass().toString() + ". Continuing with remaining managers.", e);
100             }
101         }
102 
103 		return PagerFactory.getPager(pagers);
104     }
105 
106     public List<Group> getWritableGroups()
107     {
108         List<Group> groups = new ArrayList<Group>();
109 
110         for (GroupManager groupManager : groupManagers)
111         {
112             groups.addAll(groupManager.getWritableGroups());
113         }
114 
115         return groups;
116     }
117 
118     public Pager<String> getMemberNames(Group group) throws EntityException
119     {
120         GroupManager groupManager = getMatchingGroupManager(group.getName());
121 
122         if (groupManager == null)
123             return DefaultPager.emptyPager();
124 
125         return groupManager.getMemberNames(group);
126     }
127 
128     public Pager<String> getLocalMemberNames(Group group) throws EntityException
129     {
130         GroupManager groupManager = getMatchingGroupManager(group.getName());
131 
132         if (groupManager == null)
133             return DefaultPager.emptyPager();
134 
135         return groupManager.getLocalMemberNames(group);
136     }
137 
138     public Pager<String> getExternalMemberNames(Group group) throws EntityException
139     {
140         GroupManager groupManager = getMatchingGroupManager(group.getName());
141 
142         if (groupManager == null)
143             return DefaultPager.emptyPager();
144 
145         return groupManager.getExternalMemberNames(group);
146     }
147 
148     public Group getGroup(String groupName) throws EntityException
149     {
150         Iterator iter = groupManagers.iterator();
151         Group foundGroup;
152 
153         while (iter.hasNext())
154         {
155             GroupManager groupManager = (GroupManager) iter.next();
156 
157             foundGroup = groupManager.getGroup(groupName);
158 
159 			if (foundGroup != null)
160                 return foundGroup;
161         }
162 
163         return null;
164     }
165 
166     public Group createGroup(String groupName) throws EntityException
167     {
168         Iterator iter = groupManagers.iterator();
169         Group createdGroup = null;
170 
171         while (iter.hasNext())
172         {
173             GroupManager groupManager = (GroupManager) iter.next();
174 
175             if (groupManager.isCreative())
176                 createdGroup = groupManager.createGroup(groupName);
177 
178             if (createdGroup != null)
179                 return createdGroup;
180         }
181 
182         return null;
183     }
184 
185     /**
186      * Removes the specified group, if it is present.
187      *
188      * @throws EntityException
189      *          - representing the exception which prohibited removal
190      */
191     public void removeGroup(Group group) throws EntityException
192     {
193         for (GroupManager groupManager : groupManagers)
194         {
195             if (groupManager.getGroup(group.getName()) == null)
196                 continue;
197 
198             if (groupManager.isReadOnly(group))
199                 continue;
200 
201             groupManager.removeGroup(group);
202             break;
203         }
204     }
205 
206     public void addMembership(Group group, User user) throws EntityException
207     {
208         if (group == null)
209             throw new IllegalArgumentException("Can't add membership for null group");
210         GroupManager groupManager = getMatchingGroupManager(group.getName());
211         groupManager.addMembership(group, user);
212     }
213 
214     /**
215      * Check whether this manager has a record of membership between the
216      * argued user and group.
217      *
218      * @throws com.atlassian.user.impl.RepositoryException
219      *
220      */
221     public boolean hasMembership(Group group, User user) throws EntityException
222     {
223         if (group == null)
224             return false;
225         GroupManager groupManager = getMatchingGroupManager(group.getName());
226         return groupManager.hasMembership(group, user);
227     }
228 
229     public void removeMembership(Group group, User user) throws EntityException
230     {
231         if (group == null)
232             throw new IllegalArgumentException("Can't remove membership for null group");
233         GroupManager groupManager = getMatchingGroupManager(group.getName());
234         groupManager.removeMembership(group, user);
235     }
236 
237     /**
238      * @return true if users from other systems can be granted membership in the underlying {@link com.atlassian.user.repository.RepositoryIdentifier},
239      *         otherwise false.
240      * @throws EntityException
241      *
242      */
243     public boolean supportsExternalMembership() throws EntityException
244     {
245         for (GroupManager groupManager : groupManagers)
246         {
247             if (groupManager.supportsExternalMembership())
248                 return true;
249         }
250 
251         return false;
252     }
253 
254     public boolean isReadOnly(Group group) throws EntityException
255     {
256         for (GroupManager groupManager : groupManagers)
257         {
258             if (groupManager.getGroup(group.getName()) != null)
259                 return groupManager.isReadOnly(group);
260         }
261 
262         return false;
263     }
264 
265     /**
266      * @return the {@link com.atlassian.user.repository.RepositoryIdentifier} which is managed by this instance.
267      */
268     public RepositoryIdentifier getIdentifier()
269     {
270         ArrayList<RepositoryIdentifier> repositories = new ArrayList<RepositoryIdentifier>();
271 
272         for (GroupManager groupManager : groupManagers)
273         {
274             repositories.add(groupManager.getIdentifier());
275         }
276 
277         return new DelegatingRepository(repositories);
278     }
279 
280     /**
281      * Don't use for now. This is very expensive for large LDAP instances. todo: get user/group entities to store which repository they came from
282      *
283      * @return the {@link RepositoryIdentifier} in which the entity is stored, otherwise null.
284      * @throws EntityException
285      *
286      */
287     public RepositoryIdentifier getRepository(Entity entity) throws EntityException
288     {
289         if (!(entity instanceof Group))
290             return null;
291 
292         GroupManager groupManager = getMatchingGroupManager(entity.getName());
293 
294         return groupManager.getIdentifier();
295     }
296 
297     /**
298      * Used to detemine whether an entity can be created (eg, can call {@link UserManager#createUser(String)} or
299      * {@link GroupManager#createGroup(String)}
300      *
301      * @return true to indicate that {@link Entity} objects can be created by this manager, or false to indicate
302      *         not.
303      */
304     public boolean isCreative()
305     {
306         for (GroupManager groupManager : groupManagers)
307         {
308             if (groupManager.isCreative())
309                 return true;
310         }
311         return false;
312     }
313 }