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