001/*
002 *  Copyright 2016 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.user;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024import java.util.stream.Collectors;
025
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030
031import org.ametys.core.user.directory.NotUniqueUserException;
032import org.ametys.core.user.directory.UserDirectory;
033import org.ametys.core.user.population.PopulationContextHelper;
034import org.ametys.core.user.population.UserPopulation;
035import org.ametys.core.user.population.UserPopulationDAO;
036import org.ametys.runtime.plugin.component.AbstractLogEnabled;
037
038/**
039 * Component for getting user list and verify the presence of a particular user on a context or for user directory(ies).
040 */
041public class UserManager extends AbstractLogEnabled implements Component, Serviceable
042{
043    /** Avalon Role */
044    public static final String ROLE = UserManager.class.getName(); 
045            
046    /** The DAO for User Population */
047    protected UserPopulationDAO _userPopulationDAO;
048    /** The helper for the associations population/context */
049    protected PopulationContextHelper _populationContextHelper;
050    
051    @Override
052    public void service(ServiceManager manager) throws ServiceException
053    {
054        _userPopulationDAO = (UserPopulationDAO) manager.lookup(UserPopulationDAO.ROLE);
055        _populationContextHelper = (PopulationContextHelper) manager.lookup(PopulationContextHelper.ROLE);
056    }
057    
058    /**
059     * Get the list of users on some given contexts
060     * @param contexts The contexts
061     * @param checkRight True to check that current user belongs to one of populations on theses contexts or he's an administrator user
062     * @return the collection of users
063     */
064    public Collection<User> getUsersByContext(Set<String> contexts, boolean checkRight)
065    {
066        List<UserPopulation> userPopulations = _populationContextHelper.getUserPopulationsOnContexts(contexts, false, checkRight).stream()
067            .map(upId -> _userPopulationDAO.getUserPopulation(upId))
068            .collect(Collectors.toList());
069        
070        return getUsersByPopulations(userPopulations);
071    }
072    
073    /**
074     * Get the users for given users' populations
075     * @param userPopulationIds the id of population of users
076     * @return the collection of users
077     */
078    public Collection<User> getUsersByPopulationIds(List<String> userPopulationIds)
079    {
080        List<User> users = new ArrayList<>();
081        for (String id : userPopulationIds)
082        {
083            UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(id);
084            if (userPopulation != null)
085            {
086                for (User user : getUsers(userPopulation))
087                {
088                    if (!users.contains(user))
089                    {
090                        users.add(user);
091                    }
092                }
093            }
094        }
095        return users;
096    }
097    
098    /**
099     * Get the users for given users' populations
100     * @param userPopulations the population of users
101     * @return the collection of users
102     */
103    public Collection<User> getUsersByPopulations(List<UserPopulation> userPopulations)
104    {
105        List<User> users = new ArrayList<>();
106        for (UserPopulation userPopulation : userPopulations)
107        {
108            for (User user : getUsers(userPopulation))
109            {
110                if (!users.contains(user))
111                {
112                    users.add(user);
113                }
114            }
115        }
116        return users;
117    }
118    
119    /**
120     * Gets all the users of a {@link UserPopulation}
121     * @param userPopulationId The ID of user population
122     * @return list of users as Collection of {@link User}s, empty if a problem occurs.
123     */
124    public Collection<User> getUsers(String userPopulationId)
125    {
126        UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(userPopulationId);
127        if (userPopulation != null)
128        {
129            return getUsers(userPopulation);
130        }
131        else
132        {
133            return Collections.EMPTY_LIST;
134        }
135    }
136    
137    /**
138     * Gets all the users of a {@link UserPopulation}
139     * @param userPopulation The user population
140     * @return list of users as Collection of {@link User}s, empty if a problem occurs.
141     */
142    public Collection<User> getUsers(UserPopulation userPopulation)
143    {
144        List<User> users = new ArrayList<>();
145        
146        for (UserDirectory ud : userPopulation.getUserDirectories())
147        {
148            for (User user : ud.getUsers())
149            {
150                if (!users.contains(user))
151                {
152                    users.add(user);
153                }
154            }
155        }
156        
157        return users;
158    }
159    
160    /**
161     * Get a list of users given the parameters
162     * @param contexts The contexts
163     * @param count The limit of users to retrieve
164     * @param offset The number of result to ignore before starting to collect users. 
165     * @param parameters A map of additional parameters, see implementation.
166     * @param checkRight True to check that current user belongs to one of populations on theses contexts or he's an administrator user
167     * @return The list of retrieved {@link User}
168     */
169    public List<User> getUsersByContext(Set<String> contexts, int count, int offset, Map<String, Object> parameters, boolean checkRight)
170    {
171        List<UserPopulation> userPopulations = _populationContextHelper.getUserPopulationsOnContexts(contexts, false, checkRight).stream()
172                .map(upId -> _userPopulationDAO.getUserPopulation(upId))
173                .collect(Collectors.toList());
174        
175        return getUsers(userPopulations, count, offset, parameters);
176    }
177    
178    /**
179     * Get a list of users given the parameters
180     * @param userPopulations the population of users
181     * @param count The limit of users to retrieve
182     * @param offset The number of result to ignore before starting to collect users. 
183     * @param parameters A map of additional parameters, see implementation.
184     * @return The list of retrieved {@link User}
185     */
186    public List<User> getUsers(List<UserPopulation> userPopulations, int count, int offset, Map<String, Object> parameters)
187    {
188        List<User> users = new ArrayList<>();
189        for (UserPopulation userPopulation : userPopulations)
190        {
191            for (User user : getUsers(userPopulation, count + offset, 0, parameters))
192            {
193                if (!users.contains(user))
194                {
195                    users.add(user);
196                }
197            }
198        }
199        
200        int boundedCount = count >= 0 ? count : Integer.MAX_VALUE;
201        int boundedOffset = offset >= 0 ? offset : 0;
202        int toIndex;
203        if (boundedOffset + boundedCount >= 0)
204        {
205            toIndex = Math.min(boundedOffset + boundedCount, users.size());
206        }
207        else
208        {
209            // particular case where count was initially negative (to say "no limit") and we set it to Integer.MAX_VALUE
210            // so if the offset is strictly positive, the sum overflows
211            toIndex = users.size();
212        }
213        return users.subList(boundedOffset, toIndex);
214    }
215    
216    /**
217     * Gets all the users of a {@link UserPopulation}
218     * @param userPopulationId The ID of user population
219     * @param count The limit of users to retrieve
220     * @param offset The number of result to ignore before starting to collect users. 
221     * @param parameters A map of additional parameters, see implementation.
222     * @return list of users as Collection of {@link User}s, empty if a problem occurs.
223     */
224    public Collection<User> getUsers(String userPopulationId, int count, int offset, Map<String, Object> parameters)
225    {
226        UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(userPopulationId);
227        if (userPopulation != null)
228        {
229            return getUsers(userPopulation, count, offset, parameters);
230        }
231        else
232        {
233            return Collections.EMPTY_LIST;
234        }
235    }
236    
237    /**
238     * Gets all the users of a given {@link UserPopulation} and {@link UserDirectory}
239     * @param userPopulationId The ID of user population
240     * @param userDirectoryId The id of the user directory
241     * @param count The limit of users to retrieve
242     * @param offset The number of result to ignore before starting to collect users. 
243     * @param parameters A map of additional parameters, see implementation.
244     * @return list of users as Collection of {@link User}s, empty if a problem occurs.
245     */
246    public Collection<User> getUsersByDirectory(String userPopulationId, String userDirectoryId, int count, int offset, Map<String, Object> parameters)
247    {
248        UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(userPopulationId);
249        
250        if (userPopulation == null)
251        {
252            return Collections.EMPTY_LIST;
253        }
254        
255        UserDirectory ud = userPopulation.getUserDirectory(userDirectoryId);
256        if (ud == null)
257        {
258            throw new IllegalArgumentException("In the population '" + userPopulationId + "' the directory '" + userDirectoryId + "' was referenced but does not exists");
259        }
260        return ud.getUsers(count, offset, parameters);
261    }
262    
263    /**
264     * Gets all the users of a {@link UserPopulation}
265     * @param userPopulation The users population
266     * @param count The limit of users to retrieve
267     * @param offset The number of result to ignore before starting to collect users. 
268     * @param parameters A map of additional parameters, see implementation.
269     * @return list of users as Collection of {@link User}s, empty if a problem occurs.
270     */
271    public Collection<User> getUsers(UserPopulation userPopulation, int count, int offset, Map<String, Object> parameters)
272    {
273        List<User> users = new ArrayList<>();
274        
275        for (UserDirectory ud : userPopulation.getUserDirectories())
276        {
277            for (User user : ud.getUsers(-1, 0, parameters))
278            {
279                if (!users.contains(user))
280                {
281                    users.add(user);
282                }
283            }
284        }
285        
286        int boundedCount = count >= 0 ? count : Integer.MAX_VALUE;
287        int boundedOffset = offset >= 0 ? offset : 0;
288        int toIndex;
289        if (boundedOffset + boundedCount >= 0)
290        {
291            toIndex = Math.min(boundedOffset + boundedCount, users.size());
292        }
293        else
294        {
295            // particular case where count was initially negative (to say "no limit") and we set it to Integer.MAX_VALUE
296            // so if the offset is strictly positive, the sum overflows
297            toIndex = users.size();
298        }
299        return users.subList(boundedOffset, toIndex);
300    }
301    
302    /**
303     * Gets all the users of a {@link UserPopulation}
304     * @param userPopulation The users population
305     * @param userDirectoryId The id of the user directory
306     * @param count The limit of users to retrieve
307     * @param offset The number of result to ignore before starting to collect users. 
308     * @param parameters A map of additional parameters, see implementation.
309     * @return list of users as Collection of {@link User}s, empty if a problem occurs.
310     */
311    public Collection<User> getUsersByDirectory(UserPopulation userPopulation, String userDirectoryId, int count, int offset, Map<String, Object> parameters)
312    {
313        UserDirectory ud = userPopulation.getUserDirectory(userDirectoryId);
314        return ud.getUsers(count, offset, parameters);
315    }
316    
317    /**
318     * Get a user by his login on some given contexts
319     * @param contexts The contexts
320     * @param login Login of the user to get. Cannot be null.
321     * @param checkRight True to check that current user is authorized to retrieve this user (true if he belongs to one of populations on theses contexts or he's an administrator user)
322     * @return User's information as a {@link User} instance or null if the user login does not exist.
323     */
324    public User getUserByContext(Set<String> contexts, String login, boolean checkRight)
325    {
326        Set<String> upIds = _populationContextHelper.getUserPopulationsOnContexts(contexts, false, checkRight);
327        for (String upId : upIds)
328        {
329            UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(upId);
330            User user = getUser(userPopulation, login);
331            if (user != null)
332            {
333                return user;
334            }
335        }
336        return null;
337    }
338    
339    /**
340     * Get the user from its user identity
341     * @param userIdentity The user identity
342     * @return The User or null if the user login does not exist.
343     */
344    public User getUser (UserIdentity userIdentity)
345    {
346        return getUser(userIdentity.getPopulationId(), userIdentity.getLogin());
347    }
348    
349    /**
350     * Get a particular user of the given users population by his login.
351     * @param userPopulationId The ID of user population
352     * @param login Login of the user to get. Cannot be null.
353     * @return User's information as a {@link User} instance or null if the user login does not exist.
354     */
355    public User getUser(String userPopulationId, String login)
356    {
357        UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(userPopulationId);
358        if (userPopulation != null)
359        {
360            return getUser(userPopulation, login);
361        }
362        else
363        {
364            return null;
365        }
366    }
367    
368    /**
369     * Get a particular user of the given users population by his email.
370     * @param userPopulationId The ID of user population
371     * @param email Email of the user to get. Cannot be null.
372     * @return User's information as a {@link User} instance or null if the user login does not exist.
373     * @throws NotUniqueUserException if many users match the given email
374     */
375    public User getUserByEmail(String userPopulationId, String email) throws NotUniqueUserException
376    {
377        UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(userPopulationId);
378        if (userPopulation != null)
379        {
380            return getUserByEmail(userPopulation, email);
381        }
382        else
383        {
384            return null;
385        }
386    }
387    
388    /**
389     * Get a particular user of the given user population and given user directory by his login.
390     * @param userPopulationId The ID of user population
391     * @param userDirectoryId The id of the user directory
392     * @param login Login of the user to get. Cannot be null.
393     * @return User's information as a {@link User} instance or null if the user login does not exist.
394     */
395    public User getUserByDirectory(String userPopulationId, String userDirectoryId, String login)
396    {
397        UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(userPopulationId);
398        if (userPopulation != null)
399        {
400            return getUserByDirectory(userPopulation, userDirectoryId, login);
401        }
402        else
403        {
404            return null;
405        }
406    }
407    
408    /**
409     * Get a particular user of the given user population by his login.
410     * @param userPopulation The user population
411     * @param login Login of the user to get. Cannot be null.
412     * @return User's information as a {@link User} instance or null if the user login does not exist.
413     */
414    public User getUser(UserPopulation userPopulation, String login)
415    {
416        for (UserDirectory ud : userPopulation.getUserDirectories())
417        {
418            User user = ud.getUser(login);
419            if (user != null)
420            {
421                return user;
422            }
423        }
424        return null;
425    }
426    
427    /**
428     * Get a particular user of the given user population by his email.
429     * @param userPopulation The user population
430     * @param email Email of the user to get. Cannot be null.
431     * @return User's information as a {@link User} instance or null if the user login does not exist.
432     * @throws NotUniqueUserException if many users match the given email
433     */
434    public User getUserByEmail(UserPopulation userPopulation, String email) throws NotUniqueUserException
435    {
436        for (UserDirectory ud : userPopulation.getUserDirectories())
437        {
438            User user = ud.getUserByEmail(email);
439            if (user != null)
440            {
441                return user;
442            }
443        }
444        return null;
445    }
446    
447    /**
448     * Get a particular user of the given user population and given user directory by his login.
449     * @param userPopulation The user population
450     * @param userDirectoryId The id of the user directory
451     * @param login Login of the user to get. Cannot be null.
452     * @return User's information as a {@link User} instance or null if the user login does not exist.
453     */
454    public User getUserByDirectory(UserPopulation userPopulation, String userDirectoryId, String login)
455    {
456        UserDirectory ud = userPopulation.getUserDirectory(userDirectoryId);
457        
458        User user = ud.getUser(login);
459        if (user != null)
460        {
461            return user;
462        }
463            
464        return null;
465    }
466    
467    /**
468     * Get the user directory the given user belongs to
469     * @param userPopulationId The id of the user population
470     * @param login Login of the user to get. Cannot be null.
471     * @return The user directory the user belongs to.
472     */
473    public UserDirectory getUserDirectory(String userPopulationId, String login)
474    {
475        UserPopulation userPopulation = _userPopulationDAO.getUserPopulation(userPopulationId);
476        if (userPopulation == null)
477        {
478            return null;
479        }
480        
481        for (UserDirectory ud : userPopulation.getUserDirectories())
482        {
483            User user = ud.getUser(login);
484            if (user != null)
485            {
486                return ud;
487            }
488        }
489        return null;
490    }
491}