001/* 002 * Copyright 2017 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.plugins.core.impl.right; 017 018import java.util.Collections; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028import org.apache.commons.collections.CollectionUtils; 029 030import org.ametys.core.group.GroupIdentity; 031import org.ametys.core.right.AccessController; 032import org.ametys.core.right.ProfileAssignmentStorageExtensionPoint; 033import org.ametys.core.right.RightManager; 034import org.ametys.core.right.RightProfilesDAO; 035import org.ametys.core.user.UserIdentity; 036import org.ametys.runtime.plugin.component.AbstractLogEnabled; 037 038/** 039 * This class delegates all it can to the profile assignment storage extension point 040 */ 041public abstract class AbstractProfileStorageBasedAccessController extends AbstractLogEnabled implements AccessController, Component, Serviceable 042{ 043 /** 044 * The knd of cache to get/set 045 */ 046 protected enum CacheKind 047 { 048 /** for anonymous user */ 049 ANONYMOUS, 050 /** for any connected user */ 051 ANY_CONNECTED_USER, 052 /** for users */ 053 USERS, 054 /** for user */ 055 USER, 056 /** for groups */ 057 GROUPS 058 } 059 060 /** The instance of ObjectUserIdentity for anonymous */ 061 protected static final UserIdentity __ANONYMOUS_USER_IDENTITY = null; 062 /** The instance of ObjectUserIdentity for any connected user */ 063 protected static final UserIdentity __ANY_CONTECTED_USER_IDENTITY = new UserIdentity(null, null); 064 065 /** The extension point for the profile assignment storages */ 066 protected ProfileAssignmentStorageExtensionPoint _profileAssignmentStorageEP; 067 /** The right profile DAO */ 068 protected RightProfilesDAO _rightProfileDAO; 069 /** The right manager */ 070 protected RightManager _rightManager; 071 072 /** 073 * This first cache is for right result on non-null contexts when calling hasXXX methods 074 * On the contratry of the other cache, this one is split between profiles, as we check for the first true result (no negativity) 075 * 076 * { 077 * UserIdentity : 078 * { 079 * Set<ProfileId> : 080 * { 081 * Context : boolean 082 * } 083 * } 084 * } 085 */ 086 private final String _cache1 = this.getClass().getName() + "$Cache-1"; 087 088 /** 089 * This second cache is for right result on non-null contexts when calling getXXXByGroup methods 090 * 091 * { 092 * Set<ProfileId> : 093 * { 094 * Context : { 095 * CacheKind.ANONYMOUS: AccessResult 096 * CacheKind.ANY_CONNECTED_USER: AccessResult 097 * CacheKind.USERS: Map<UserIdentity, AccessResult>, 098 * CacheKind.USER: Map<UserIdentity, AccessResult>, 099 * CacheKind.GROUPS: Map<GroupIdentity, AccessResult> 100 * } 101 * } 102 * } 103 */ 104 private final String _cache2 = this.getClass().getName() + "$Cache-2"; 105 106 107 @Override 108 public void service(ServiceManager manager) throws ServiceException 109 { 110 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 111 _rightProfileDAO = (RightProfilesDAO) manager.lookup(RightProfilesDAO.ROLE); 112 _profileAssignmentStorageEP = (ProfileAssignmentStorageExtensionPoint) manager.lookup(ProfileAssignmentStorageExtensionPoint.ROLE); 113 } 114 115 public Map<String, AccessResult> getPermissionByRight(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 116 { 117 Map<String, AccessResult> rights = new HashMap<>(); 118 119 Map<String, AccessResult> permissionsByProfile = _profileAssignmentStorageEP.getPermissionsByProfile(user, userGroups, _convertContext(object)); 120 121 // Convert profile <-> accessresult to right <-> accessresult 122 for (String profileId : permissionsByProfile.keySet()) 123 { 124 List<String> rights2 = _rightProfileDAO.getRights(profileId); 125 for (String rightId : rights2) 126 { 127 rights.put(rightId, AccessResult.merge(permissionsByProfile.get(profileId), rights.get(rightId))); 128 } 129 } 130 131 return rights; 132 } 133 134 public AccessResult getPermission(UserIdentity user, Set<GroupIdentity> userGroups, String rightId, Object object) 135 { 136 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 137 if (profilesIds == null || profilesIds.isEmpty()) 138 { 139 // No need for cache... 140 return AccessResult.UNKNOWN; 141 } 142 else 143 { 144 Object convertedObject = _convertContext(object); 145 return _getPermission(user, userGroups, profilesIds, object, convertedObject); 146 } 147 } 148 public AccessResult getReadAccessPermission(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 149 { 150 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 151 // Some converted context may change so cache must be done with the convertedObject 152 Object convertedObject = _convertContext(object); 153 return _getPermission(user, userGroups, profilesIds, object, convertedObject); 154 } 155 /** 156 * Works for getPermission or getReadAccessPermission 157 * @param user The use 158 * @param userGroups The groups 159 * @param profilesIds The profiles 160 * @param object The original context 161 * @param convertedObject The converted context 162 * @return the computed result 163 */ 164 protected AccessResult _getPermission(UserIdentity user, Set<GroupIdentity> userGroups, Set<String> profilesIds, Object object, Object convertedObject) 165 { 166 @SuppressWarnings("unchecked") 167 Map<UserIdentity, AccessResult> cacheResult = (Map<UserIdentity, AccessResult>) _hasRightResultInSecondCache(convertedObject, profilesIds, CacheKind.USER); 168 if (cacheResult != null && cacheResult.containsKey(user)) 169 { 170 return cacheResult.get(user); 171 } 172 173 Map<String, AccessResult> permissions = _profileAssignmentStorageEP.getPermissions(user, userGroups, profilesIds, convertedObject); 174 AccessResult result = AccessResult.merge(permissions.values()); 175 cacheResult = cacheResult == null ? new HashMap<>() : cacheResult; 176 cacheResult.put(user, result); 177 _putInSecondCache(profilesIds, convertedObject, cacheResult, CacheKind.USER); 178 return result; 179 } 180 181 public AccessResult getPermissionForAnonymous(String rightId, Object object) 182 { 183 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 184 if (profilesIds == null || profilesIds.isEmpty()) 185 { 186 // No need for cache... 187 return AccessResult.UNKNOWN; 188 } 189 else 190 { 191 // Some converted context may change so cache must be done with the convertedObject 192 Object convertedObject = _convertContext(object); 193 return _getPermissionForAnonymous(profilesIds, object, convertedObject); 194 } 195 } 196 public AccessResult getReadAccessPermissionForAnonymous(Object object) 197 { 198 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 199 // Some converted context may change so cache must be done with the convertedObject 200 Object convertedObject = _convertContext(object); 201 return _getPermissionForAnonymous(profilesIds, object, convertedObject); 202 } 203 /** 204 * Works for getPermissionForAnonymous and getReadAccessPermissionForAnonymous 205 * @param profilesIds The profiles ids 206 * @param object The context 207 * @param convertedObject The converted context 208 * @return The access result 209 */ 210 protected AccessResult _getPermissionForAnonymous(Set<String> profilesIds, Object object, Object convertedObject) 211 { 212 // Try to retrieve in second cache 213 AccessResult cacheResult = (AccessResult) _hasRightResultInSecondCache(convertedObject, profilesIds, CacheKind.ANONYMOUS); 214 if (cacheResult != null) 215 { 216 return cacheResult; 217 } 218 219 AccessResult result = _profileAssignmentStorageEP.getPermissionForAnonymous(profilesIds, convertedObject); 220 _putInSecondCache(profilesIds, convertedObject, result, CacheKind.ANONYMOUS); 221 return result; 222 } 223 224 public AccessResult getPermissionForAnyConnectedUser(String rightId, Object object) 225 { 226 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 227 if (profilesIds == null || profilesIds.isEmpty()) 228 { 229 // No need for cache... 230 return AccessResult.UNKNOWN; 231 } 232 else 233 { 234 // Some converted context may change so cache must be done with the convertedObject 235 Object convertedObject = _convertContext(object); 236 return _getPermissionForAnyConnectedUser(profilesIds, object, convertedObject); 237 } 238 } 239 public AccessResult getReadAccessPermissionForAnyConnectedUser(Object object) 240 { 241 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 242 // Some converted context may change so cache must be done with the convertedObject 243 Object convertedObject = _convertContext(object); 244 return _getPermissionForAnyConnectedUser(profilesIds, object, convertedObject); 245 } 246 /** 247 * Works for getPermissionForAnyConnectedUser and getReadAccessPermissionForAnyConnectedUser 248 * @param profilesIds The profiles ids 249 * @param object The context 250 * @param convertedObject The converted context 251 * @return the access result 252 */ 253 protected AccessResult _getPermissionForAnyConnectedUser(Set<String> profilesIds, Object object, Object convertedObject) 254 { 255 // Try to retrieve in second cache 256 AccessResult cacheResult = (AccessResult) _hasRightResultInSecondCache(convertedObject, profilesIds, CacheKind.ANY_CONNECTED_USER); 257 if (cacheResult != null) 258 { 259 return cacheResult; 260 } 261 262 AccessResult result = _profileAssignmentStorageEP.getPermissionForAnyConnectedUser(profilesIds, convertedObject); 263 _putInSecondCache(profilesIds, convertedObject, result, CacheKind.ANY_CONNECTED_USER); 264 return result; 265 } 266 267 public Map<UserIdentity, AccessResult> getPermissionByUser(String rightId, Object object) 268 { 269 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 270 if (profilesIds == null || profilesIds.isEmpty()) 271 { 272 // No need for cache... 273 return Collections.EMPTY_MAP; 274 } 275 else 276 { 277 // Some converted context may change so cache must be done with the convertedObject 278 Object convertedObject = _convertContext(object); 279 return _getPermissionByUser(profilesIds, object, convertedObject); 280 } 281 } 282 public Map<UserIdentity, AccessResult> getReadAccessPermissionByUser(Object object) 283 { 284 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 285 // Some converted context may change so cache must be done with the convertedObject 286 Object convertedObject = _convertContext(object); 287 return _getPermissionByUser(profilesIds, object, convertedObject); 288 } 289 /** 290 * Works for getPermissionByUser and getReadAccessPermissionByUser 291 * @param profilesIds The profiles ids 292 * @param object The context 293 * @param convertedObject The converted context 294 * @return The users and their access results 295 */ 296 protected Map<UserIdentity, AccessResult> _getPermissionByUser(Set<String> profilesIds, Object object, Object convertedObject) 297 { 298 // Try to retrieve in second cache 299 @SuppressWarnings("unchecked") 300 Map<UserIdentity, AccessResult> cacheResult = (Map<UserIdentity, AccessResult>) _hasRightResultInSecondCache(convertedObject, profilesIds, CacheKind.USERS); 301 if (cacheResult != null) 302 { 303 return cacheResult; 304 } 305 306 Map<UserIdentity, AccessResult> result = _profileAssignmentStorageEP.getPermissionsByUser(profilesIds, convertedObject); 307 _putInSecondCache(profilesIds, convertedObject, result, CacheKind.USERS); 308 return result; 309 } 310 311 public Map<GroupIdentity, AccessResult> getPermissionByGroup(String rightId, Object object) 312 { 313 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 314 if (profilesIds == null || profilesIds.isEmpty()) 315 { 316 // No need for cache... 317 return Collections.EMPTY_MAP; 318 } 319 else 320 { 321 // Some converted context may change so cache must be done with the convertedObject 322 Object convertedObject = _convertContext(object); 323 return _getPermissionByGroup(profilesIds, object, convertedObject); 324 } 325 } 326 public Map<GroupIdentity, AccessResult> getReadAccessPermissionByGroup(Object object) 327 { 328 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 329 // Some converted context may change so cache must be done with the convertedObject 330 Object convertedObject = _convertContext(object); 331 return _getPermissionByGroup(profilesIds, object, convertedObject); 332 } 333 /** 334 * Works for getPermissionByGroup and getReadAccessPermissionByGroup 335 * @param profilesIds The profiles ids 336 * @param object The context 337 * @param convertedObject The converted context 338 * @return The users and their access results 339 */ 340 protected Map<GroupIdentity, AccessResult> _getPermissionByGroup(Set<String> profilesIds, Object object, Object convertedObject) 341 { 342 // Try to retrieve in second cache 343 @SuppressWarnings("unchecked") 344 Map<GroupIdentity, AccessResult> cacheResult = (Map<GroupIdentity, AccessResult>) _hasRightResultInSecondCache(convertedObject, profilesIds, CacheKind.GROUPS); 345 if (cacheResult != null) 346 { 347 return cacheResult; 348 } 349 350 Map<GroupIdentity, AccessResult> result = _profileAssignmentStorageEP.getPermissionsByGroup(profilesIds, convertedObject); 351 _putInSecondCache(profilesIds, convertedObject, result, CacheKind.GROUPS); 352 return result; 353 } 354 355 /** 356 * For methods getXXXXPermissionYYY allow to have a modification of the context before transfering it to the profile assignment storage extension point 357 * The default implemenation keep the context as it is 358 * @param initialContext The right context that is supported 359 * @return the context modified 360 */ 361 protected Object _convertContext(Object initialContext) 362 { 363 return initialContext; 364 } 365 366 public boolean hasAnonymousAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 367 { 368 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 369 return _hasAnonymousAnyPermissionOnWorkspace(workspacesContexts, profilesIds); 370 } 371 public boolean hasAnonymousAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 372 { 373 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 374 return _hasAnonymousAnyPermissionOnWorkspace(workspacesContexts, profilesIds); 375 } 376 private boolean _hasAnonymousAnyPermissionOnWorkspace(Set<Object> workspacesContexts, Set<String> profilesIds) 377 { 378 // Try to retrieve in first cache (the one which manages non-null contexts) 379 Boolean cacheResult = _hasRightResultInFirstCache(__ANONYMOUS_USER_IDENTITY, profilesIds, workspacesContexts); 380 if (cacheResult != null) 381 { 382 return cacheResult; 383 } 384 385 // Otherwise continue 386 Set<? extends Object> rootContexts = _convertWorkspaceToRootRightContexts(workspacesContexts); 387 boolean rightResult = CollectionUtils.isNotEmpty(rootContexts) ? _profileAssignmentStorageEP.hasAnonymousAnyPermission(rootContexts, profilesIds) : false; 388 _putInFirstCache(__ANONYMOUS_USER_IDENTITY, profilesIds, workspacesContexts, rightResult); 389 return rightResult; 390 } 391 392 public boolean hasAnyConnectedUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 393 { 394 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 395 return _hasAnyConnectedUserAnyPermissionOnWorkspace(workspacesContexts, profilesIds); 396 } 397 public boolean hasAnyConnectedUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 398 { 399 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 400 return _hasAnyConnectedUserAnyPermissionOnWorkspace(workspacesContexts, profilesIds); 401 } 402 private boolean _hasAnyConnectedUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, Set<String> profilesIds) 403 { 404 // Try to retrieve in first cache (the one which manages non-null contexts) 405 Boolean cacheResult = _hasRightResultInFirstCache(__ANY_CONTECTED_USER_IDENTITY, profilesIds, workspacesContexts); 406 if (cacheResult != null) 407 { 408 return cacheResult; 409 } 410 411 // Otherwise continue 412 Set<? extends Object> rootContexts = _convertWorkspaceToRootRightContexts(workspacesContexts); 413 boolean rightResult = CollectionUtils.isNotEmpty(rootContexts) ? _profileAssignmentStorageEP.hasAnyConnectedUserAnyPermission(rootContexts, profilesIds) : false; 414 _putInFirstCache(__ANY_CONTECTED_USER_IDENTITY, profilesIds, workspacesContexts, rightResult); 415 return rightResult; 416 } 417 418 public boolean hasUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups) 419 { 420 Set<String> profilesIds = Collections.singleton(RightManager.READER_PROFILE_ID); 421 return _hasUserAnyPermissionOnWorkspace(workspacesContexts, user, userGroups, profilesIds); 422 } 423 public boolean hasUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups, String rightId) 424 { 425 Set<String> profilesIds = _rightProfileDAO.getProfilesWithRight(rightId); 426 return _hasUserAnyPermissionOnWorkspace(workspacesContexts, user, userGroups, profilesIds); 427 } 428 private boolean _hasUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups, Set<String> profilesIds) 429 { 430 // Try to retrieve in first cache (the one which manages non-null contexts) 431 Boolean cacheResult = _hasRightResultInFirstCache(user, profilesIds, workspacesContexts); 432 if (cacheResult != null) 433 { 434 return cacheResult; 435 } 436 437 // Otherwise continue 438 Set<? extends Object> rootContexts = _convertWorkspaceToRootRightContexts(workspacesContexts); 439 boolean rightResult = CollectionUtils.isNotEmpty(rootContexts) ? _profileAssignmentStorageEP.hasUserAnyPermission(rootContexts, user, userGroups, profilesIds) : false; 440 _putInFirstCache(user, profilesIds, workspacesContexts, rightResult); 441 return rightResult; 442 } 443 444 /** 445 * Get the current workspaces contexts and turn it into root contexts in order to allow methods hasXXXAnyPermissionOnWorkspace to work 446 * @param workspacesContexts The workspace contexts. Such as '/${WorkspaceName}', '/admin' 447 * @return A null or empty set if the current AccessController does not apply to any workspace context, or the root object where ProfileAssignmentStorageExtension should start looking at to find any permission 448 */ 449 protected abstract Set<? extends Object> _convertWorkspaceToRootRightContexts(Set<Object> workspacesContexts); 450 451 452 453 454 455 456 /** 457 * Seek in cache 458 * @param userIdentity The user identity or AbstractProfileStorageBasedAccessController.__ANONYMOUS_USER_IDENTITY or AbstractProfileStorageBasedAccessController.__ANY_CONTECTED_USER_IDENTITY 459 * @param profilesIds The profiles identifiers 460 * @param object The context 461 * @return true or false if in cache. null otherwise 462 */ 463 protected Boolean _hasRightResultInFirstCache(UserIdentity userIdentity, Set<String> profilesIds, Object object) 464 { 465 // On the contrary of the other cache, this one is split between profiles, as we check for the first true result (no negativity) 466 467 if (profilesIds == null || profilesIds.isEmpty()) 468 { 469 // No need for cache... 470 return false; 471 } 472 473 Map<UserIdentity, Map<Set<String>, Map<Object, Boolean>>> mapCache = _rightManager.getCache(_cache1, false); 474 if (mapCache != null) 475 { 476 if (mapCache.containsKey(userIdentity)) 477 { 478 int negativeProfiles = 0; 479 480 Map<Set<String>, Map<Object, Boolean>> mapProfile = mapCache.get(userIdentity); 481 if (mapProfile.containsKey(profilesIds)) 482 { 483 Map<Object, Boolean> mapContext = mapProfile.get(profilesIds); 484 if (mapContext.containsKey(object)) 485 { 486 if (mapContext.get(object)) 487 { 488 getLogger().debug("Find entry in cache for [{}, {}, {}] => true", userIdentity, profilesIds, object); 489 return true; 490 } 491 else 492 { 493 negativeProfiles++; 494 } 495 } 496 } 497 498 if (negativeProfiles == profilesIds.size()) 499 { 500 // All required profiles were negative in cache 501 return false; 502 } 503 } 504 } 505 506 getLogger().debug("Did not find entry in cache for [{}, {}, {}]", userIdentity, profilesIds, object); 507 return null; 508 } 509 510 /** 511 * Add to cache 512 * @param userIdentity The user identity or AbstractProfileStorageBasedAccessController.__ANONYMOUS_USER_IDENTITY or AbstractProfileStorageBasedAccessController.__ANY_CONTECTED_USER_IDENTITY 513 * @param profilesIds The profiles identifiers 514 * @param object The context 515 * @param rightResult The cache value. true if hasXXX or false otherwise. 516 */ 517 protected void _putInFirstCache(UserIdentity userIdentity, Set<String> profilesIds, Object object, boolean rightResult) 518 { 519 // On the contratry of the other cache, this one is split between profiles, as we check for the first true result (no negativity) 520 521 Map<UserIdentity, Map<Set<String>, Map<Object, Boolean>>> mapCache = _rightManager.getCache(_cache1, true); 522 if (mapCache != null) 523 { 524 if (!mapCache.containsKey(userIdentity)) 525 { 526 mapCache.put(userIdentity, new HashMap<>()); 527 } 528 529 Map<Set<String>, Map<Object, Boolean>> mapProfile = mapCache.get(userIdentity); 530 531 if (!mapProfile.containsKey(profilesIds)) 532 { 533 mapProfile.put(profilesIds, new HashMap<>()); 534 } 535 536 Map<Object, Boolean> mapContext = mapProfile.get(profilesIds); 537 mapContext.put(object, rightResult); 538 539 } 540 } 541 542 /** 543 * Seek in cache 544 * @param object The context 545 * @param profilesIds The set of profile ids to consider 546 * @return The cached result per group. null otherwise 547 * @param key The kind of cache to use 548 */ 549 protected Object _hasRightResultInSecondCache(Object object, Set<String> profilesIds, CacheKind key) 550 { 551 Map<Set<String>, Map<Object, Map<CacheKind, Object>>> mapCache = _rightManager.getCache(_cache2, false); 552 if (mapCache != null) 553 { 554 if (mapCache.containsKey(profilesIds)) 555 { 556 Map<Object, Map<CacheKind, Object>> mapAll = mapCache.get(profilesIds); 557 if (mapAll.containsKey(object)) 558 { 559 Map<CacheKind, Object> mapResult = mapAll.get(object); 560 Object cacheResult = mapResult.get(key); 561 if (cacheResult != null) 562 { 563 getLogger().debug("Find entry in cache for [{}, {}, {}] => {}", profilesIds, object, key, cacheResult); 564 return cacheResult; 565 } 566 } 567 } 568 } 569 570 getLogger().debug("Did not find entry in cache for [{}, {}, {}]", profilesIds, object, key); 571 return null; 572 } 573 574 /** 575 * Add to cache 576 * @param profilesIds The profiles ids to consider 577 * @param object The context 578 * @param result The result 579 * @param key The kind of cache to use 580 */ 581 protected void _putInSecondCache(Set<String> profilesIds, Object object, Object result, CacheKind key) 582 { 583 Map<Set<String>, Map<Object, Map<CacheKind, Object>>> mapCache = _rightManager.getCache(_cache2, true); 584 if (mapCache != null) 585 { 586 if (!mapCache.containsKey(profilesIds)) 587 { 588 mapCache.put(profilesIds, new HashMap<>()); 589 } 590 Map<Object, Map<CacheKind, Object>> mapAll = mapCache.get(profilesIds); 591 592 if (!mapAll.containsKey(object)) 593 { 594 mapAll.put(object, new HashMap<>()); 595 } 596 Map<CacheKind, Object> mapResult = mapAll.get(object); 597 598 mapResult.put(key, result); 599 } 600 } 601}