1   package com.atlassian.user.impl.delegation;
2   
3   import com.atlassian.user.Entity;
4   import com.atlassian.user.EntityException;
5   import com.atlassian.user.User;
6   import com.atlassian.user.UserManager;
7   import com.atlassian.user.impl.DuplicateEntityException;
8   import com.atlassian.user.impl.delegation.repository.DelegatingRepository;
9   import com.atlassian.user.repository.RepositoryIdentifier;
10  import com.atlassian.user.search.page.Pager;
11  import com.atlassian.user.search.page.PagerFactory;
12  import com.atlassian.user.security.password.Credential;
13  import com.atlassian.user.util.Assert;
14  
15  import java.util.ArrayList;
16  import java.util.Collections;
17  import java.util.Iterator;
18  import java.util.List;
19  
20  /*
21   * User manager with a list of other user managers to delegate to.
22   * The user managers are tried in the iteration order of the list.
23   */
24  public class DelegatingUserManager implements UserManager
25  {
26      private final List<UserManager> userManagers;
27  
28      public DelegatingUserManager(List<UserManager> userManagers)
29      {
30          this.userManagers = userManagers;
31      }
32  
33      public Pager<User> getUsers() throws EntityException
34      {
35          ArrayList<Pager<User>> pagers = new ArrayList<Pager<User>>();
36  
37          for (UserManager userManager : userManagers)
38          {
39              pagers.add(userManager.getUsers());
40          }
41  
42          return PagerFactory.getPager(pagers);
43      }
44  
45      public Pager<String> getUserNames() throws EntityException
46      {
47          ArrayList<Pager<String>> pagers = new ArrayList<Pager<String>>();
48  
49          for (UserManager userManager : userManagers)
50          {
51              pagers.add(userManager.getUserNames());
52          }
53  
54          return PagerFactory.getPager(pagers);
55      }
56  
57      /**
58       * @return - an {@link com.atlassian.user.User} if one could be found, otherwise null.
59       * @throws com.atlassian.user.EntityException
60       *          - representing the exception which prohibited looking for or
61       *          retrieving the user.
62       */
63      public User getUser(String username) throws EntityException
64      {
65          User foundUser = null;
66  
67          for (UserManager userManager : userManagers)
68          {
69              foundUser = userManager.getUser(username);
70  
71              if (foundUser != null)
72                  break;
73          }
74  
75          return foundUser;
76      }
77  
78      /**
79       * @return the created user
80       * @throws com.atlassian.user.EntityException If user cannot be created in any user managers.
81       */
82      public User createUser(String username) throws EntityException
83      {
84          User preexistingUser;
85          try
86          {
87              preexistingUser = getUser(username);
88          }
89          catch (EntityException e)
90          {
91              throw new EntityException("Couldn't check whether user already exists", e);
92          }
93  
94          if (preexistingUser != null)
95          {
96              UserManager manager = getMatchingUserManager(preexistingUser);
97              if (manager == null)
98              {
99                  // This could just mean the user has just been deleted since the first call to getUser,
100                 // but it may be a bug in in the getMatchingUserManager logic
101                 throw new DuplicateEntityException("User [" + username + "] reported to exist by unknown manager");
102             }
103             RepositoryIdentifier repository = manager.getRepository(preexistingUser);
104             if (repository == null)
105             {
106                 // This most likely indicates a bug in the manager.  E.g. its cache contains the user but its repo doesn't.
107                 // Or again it could have been removed since the call to getMatchingUserManager
108                 throw new DuplicateEntityException("User [" + username + "] reported to exist in unknown repository by manager: " + manager);
109             }
110             else
111             {
112                 throw new DuplicateEntityException("User [" + username + "] already exists in: " + repository.getName());
113             }
114         }
115 
116 
117         User createdUser = null;
118 
119         for (UserManager userManager : userManagers)
120         {
121 
122             if (userManager.isCreative())
123                 createdUser = userManager.createUser(username);
124 
125             if (createdUser != null)
126                 break;
127         }
128 
129         if (createdUser == null)
130             throw new EntityException("Could not create user: " + username + ". " +
131                 "Ensure you have a read-write repository configured.");
132 
133         return createdUser;
134     }
135 
136 
137     public User createUser(User userTemplate, Credential credential) throws EntityException, UnsupportedOperationException
138     {
139         String username = userTemplate.getName();
140         User preexistingUser;
141         try
142         {
143             preexistingUser = getUser(username);
144         }
145         catch (EntityException e)
146         {
147             throw new EntityException("Couldn't check whether user already exists", e);
148         }
149 
150         if (preexistingUser != null)
151         {
152             UserManager manager = getMatchingUserManager(preexistingUser);
153             if (manager == null)
154             {
155                 // This could just mean the user has just been deleted since the first call to getUser,
156                 // but it may be a bug in in the getMatchingUserManager logic
157                 throw new DuplicateEntityException("User [" + username + "] reported to exist by unknown manager");
158             }
159             RepositoryIdentifier repository = manager.getRepository(preexistingUser);
160             if (repository == null)
161             {
162                 // This most likely indicates a bug in the manager.  E.g. its cache contains the user but its repo doesn't.
163                 // Or again it could have been removed since the call to getMatchingUserManager
164                 throw new DuplicateEntityException("User [" + username + "] reported to exist in unknown repository by manager: " + manager);
165             }
166             else
167             {
168                 throw new DuplicateEntityException("User [" + username + "] already exists in: " + repository.getName());
169             }
170         }
171 
172 
173         User createdUser = null;
174 
175         for (UserManager userManager : userManagers)
176         {
177 
178             if (userManager.isCreative())
179                 createdUser = userManager.createUser(userTemplate, credential);
180 
181             if (createdUser != null)
182                 break;
183         }
184 
185         if (createdUser == null)
186             throw new EntityException("Could not create user: " + username + ". " +
187                 "Ensure you have a read-write repository configured.");
188 
189         return createdUser;
190     }
191 
192     /**
193      * Encrypts the plain password, sets it on the user, and saves the user.
194      */
195     public void alterPassword(User user, String plainTextPass) throws EntityException
196     {
197         UserManager userManager = getMatchingUserManager(user);
198 
199         if (userManager != null)
200             userManager.alterPassword(user, plainTextPass);
201         else
202             throw new EntityException("Cannot find a userManager responsible for user [" + user.getName() + "]");
203     }
204 
205     public void saveUser(User user) throws EntityException
206     {
207         UserManager userManager = getMatchingUserManager(user);
208 
209         if (userManager != null)
210             userManager.saveUser(user);
211         else
212             throw new EntityException("Cannot find a userManager responsible for user [" + user.getName() + "]");
213     }
214 
215     public void removeUser(User user) throws EntityException
216     {
217         UserManager userManager = getMatchingUserManager(user);
218 
219         if (userManager != null)
220             userManager.removeUser(user);
221         else
222             throw new IllegalArgumentException("Cannot find a userManager responsible for user [" + user.getName() + "]");
223     }
224 
225     /**
226      * @return true indicates that information on the user object cannot be altered in the storage system
227      *         (see {@link com.atlassian.user.repository.RepositoryIdentifier}),
228      *         false indicates that the storage system will save changes or that this {@link com.atlassian.user.UserManager} does not
229      *         know about the {@link com.atlassian.user.User}.
230      * @throws com.atlassian.user.EntityException
231      *
232      */
233     public boolean isReadOnly(User user) throws EntityException
234     {
235         UserManager userManager = getMatchingUserManager(user);
236 
237         if (userManager != null)
238             return userManager.isReadOnly(user);
239         else
240             throw new EntityException("Cannot find a userManager responsible for user [" + user.getName() + "]");
241     }
242 
243     /**
244      * @return the {@link com.atlassian.user.repository.RepositoryIdentifier} which is managed by this instance.
245      */
246     public RepositoryIdentifier getIdentifier()
247     {
248         Iterator iter = userManagers.iterator();
249         ArrayList<RepositoryIdentifier> repositories = new ArrayList<RepositoryIdentifier>();
250 
251         while (iter.hasNext())
252         {
253             UserManager userManager = (UserManager) iter.next();
254             repositories.add(userManager.getIdentifier());
255         }
256 
257         return new DelegatingRepository(repositories);
258     }
259 
260     /**
261      * @return the {@link com.atlassian.user.repository.RepositoryIdentifier} in which the entity is stored, otherwise null.
262      * @throws com.atlassian.user.EntityException
263      *
264      */
265     public RepositoryIdentifier getRepository(Entity entity) throws EntityException
266     {
267 
268         for (UserManager userManager : userManagers)
269         {
270             RepositoryIdentifier repo = userManager.getRepository(entity);
271 
272             if (repo != null)
273                 return repo;
274         }
275 
276         return null;
277     }
278 
279     /**
280      * Used to detemine whether an entity can be created (eg, can call {@link com.atlassian.user.UserManager#createUser(String)} or
281      * {@link com.atlassian.user.GroupManager#createGroup(String)}
282      *
283      * @return true to indicate that {@link com.atlassian.user.Entity} objects can be created by this manager, or false to indicate
284      *         not.
285      */
286     public boolean isCreative()
287     {
288         for (UserManager userManager : userManagers)
289         {
290             if (userManager.isCreative())
291                 return true;
292         }
293 
294         return false;
295     }
296 
297     /**
298      * Helper method to locate the first userManager responsible for the given user, in the delegation.
299      */
300     protected UserManager getMatchingUserManager(User user) throws EntityException
301     {
302         Assert.notNull(user, "User must not be null");
303 
304         for (UserManager userManager : userManagers)
305         {
306             User foundUser = userManager.getUser(user.getName());
307 
308             if (foundUser != null)
309                 return userManager;
310         }
311 
312         return null;
313     }
314 
315     /**
316      * @return an unmodifiable list of {@link UserManager}s which this manager delegates to,
317      * in the order of delegation.
318      */
319     public List getUserManagers()
320     {
321         return Collections.unmodifiableList(userManagers);
322     }
323 }