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