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.right; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025import java.util.stream.Collectors; 026 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.commons.lang3.StringUtils; 030import org.apache.ibatis.session.SqlSession; 031 032import org.ametys.core.ObservationConstants; 033import org.ametys.core.datasource.AbstractMyBatisDAO; 034import org.ametys.core.observation.Event; 035import org.ametys.core.observation.ObservationManager; 036import org.ametys.core.user.CurrentUserProvider; 037 038/** 039 * Manages registration of profiles 040 */ 041public class RightProfilesDAO extends AbstractMyBatisDAO 042{ 043 /** The component role. */ 044 public static final String ROLE = RightProfilesDAO.class.getName(); 045 046 private Map<String, Profile> _profilesCache; 047 private Map<String, List<String>> _profileRightsCache; 048 049 private ServiceManager _smanager; 050 051 private ObservationManager _observationManager; 052 053 private CurrentUserProvider _currentUserProvider; 054 055 @Override 056 public void service(ServiceManager smanager) throws ServiceException 057 { 058 _smanager = smanager; 059 super.service(smanager); 060 } 061 062 /** 063 * Clear the profiles cache 064 */ 065 public synchronized void clearCache() 066 { 067 _profilesCache = null; 068 _profileRightsCache = null; 069 } 070 071 private synchronized Map<String, Profile> _getProfiles() 072 { 073 if (_profilesCache == null) 074 { 075 try (SqlSession session = getSession()) 076 { 077 List<Profile> profiles = session.selectList("Profiles.getProfiles"); 078 _profilesCache = profiles.stream().collect(Collectors.toMap(Profile::getId, p -> p)); 079 } 080 } 081 082 return _profilesCache; 083 } 084 085 private synchronized Map<String, List<String>> _getProfileRightsCache() 086 { 087 if (_profileRightsCache == null) 088 { 089 try (SqlSession session = getSession()) 090 { 091 List<Map<String, String>> rightAssociations = session.selectList("Profiles.getProfileRights"); 092 093 _profileRightsCache = rightAssociations.stream() 094 .collect(Collectors.groupingBy( 095 rightAssociation -> rightAssociation.get("profileId"), 096 Collectors.mapping( 097 rightAssociation -> rightAssociation.get("rightId"), 098 Collectors.toList()))); 099 } 100 } 101 102 return _profileRightsCache; 103 } 104 105 /** 106 * Get all existing profiles 107 * @return The list for profiles 108 */ 109 public List<Profile> getProfiles() 110 { 111 Collection<Profile> profiles = _getProfiles().values(); 112 return new ArrayList<>(profiles); 113 } 114 115 /** 116 * Get the profiles on a given context 117 * @param context The context. Can be null. If null, the profiles with no context are returned. 118 * @return The list for profiles for this context 119 */ 120 public List<Profile> getProfiles(String context) 121 { 122 return _getProfiles().values().stream() 123 .filter(p -> StringUtils.equals(p.getContext(), context)) 124 .collect(Collectors.toList()); 125 } 126 127 /** 128 * Get the profile with given identifier 129 * @param id The id of profile to retrieve 130 * @return The profile 131 */ 132 public Profile getProfile(String id) 133 { 134 return _getProfiles().get(id); 135 } 136 137 /** 138 * Get all profiles containing the right with given id 139 * @param rightId The id of right 140 * @return The id of profiles with this right 141 */ 142 public Set<String> getProfilesWithRight (String rightId) 143 { 144 return _getProfileRightsCache().entrySet().stream() 145 .filter(e -> e.getValue().contains(rightId)) 146 .map(e -> e.getKey()) 147 .collect(Collectors.toSet()); 148 } 149 150 /** 151 * Creates a new profile with null context. The identifier of the profile will be automatically generated from label. 152 * @param label The label of profile 153 * @return The create profile 154 */ 155 public Profile addProfile (String label) 156 { 157 return addProfile(label, null); 158 } 159 160 /** 161 * Creates a new profile. The identifier of the profile will be automatically generated from label. 162 * @param label The label of profile 163 * @param context The context. Can be null 164 * @return The create profile 165 */ 166 public Profile addProfile (String label, String context) 167 { 168 String id = _generateUniqueId(label); 169 Profile profile = new Profile(id, label, context); 170 addProfile(profile); 171 return profile; 172 } 173 174 private String _generateUniqueId(String label) 175 { 176 // Id generated from name lowercased, trimmed, and spaces and underscores replaced by dashes 177 String value = label.toLowerCase().trim().replaceAll("[\\W_]", "-").replaceAll("-+", "-").replaceAll("^-", ""); 178 int i = 2; 179 String suffixedValue = value; 180 while (getProfile(suffixedValue) != null) 181 { 182 suffixedValue = value + i; 183 i++; 184 } 185 186 return suffixedValue; 187 } 188 189 /** 190 * Creates a new profile 191 * @param id The unique identifier of profile 192 * @param label The label of profile 193 * @param context The context. Can be null 194 * @return The create profile 195 */ 196 public Profile addProfile (String id, String label, String context) 197 { 198 Profile profile = new Profile(id, label, context); 199 addProfile(profile); 200 return profile; 201 } 202 203 /** 204 * Add a new profile 205 * @param profile The profile to add 206 * @param silent Set to true to not notify observer of this update 207 */ 208 public void addProfile (Profile profile, boolean silent) 209 { 210 try (SqlSession session = getSession(true)) 211 { 212 session.insert("Profiles.addProfile", profile); 213 clearCache(); 214 if (!silent) 215 { 216 _notifyEvent(profile, ObservationConstants.EVENT_PROFILE_ADDED); 217 } 218 } 219 } 220 221 /** 222 * Add a new profile 223 * @param profile The profile to add 224 */ 225 public void addProfile (Profile profile) 226 { 227 addProfile(profile, false); 228 } 229 230 /** 231 * Rename a profile 232 * @param profile The profile to rename 233 * @param newLabel The updated label 234 */ 235 public void renameProfile (Profile profile, String newLabel) 236 { 237 renameProfile(profile, newLabel, false); 238 } 239 240 /** 241 * Rename a profile 242 * @param profile The profile to rename 243 * @param newLabel The updated label 244 * @param silent Set to true to not notify observer of this update 245 */ 246 public void renameProfile (Profile profile, String newLabel, boolean silent) 247 { 248 try (SqlSession session = getSession(true)) 249 { 250 Map<String, Object> params = new HashMap<>(); 251 params.put("id", profile.getId()); 252 params.put("label", newLabel); 253 session.update("Profiles.renameProfile", params); 254 255 clearCache(); 256 257 if (!silent) 258 { 259 _notifyEvent(profile, ObservationConstants.EVENT_PROFILE_UPDATED); 260 } 261 } 262 } 263 264 265 /** 266 * Get the rights of a profile 267 * @param profileId The profile id 268 * @return The rights 269 */ 270 public List<String> getRights (String profileId) 271 { 272 if (!StringUtils.isEmpty(profileId)) 273 { 274 List<String> list = _getProfileRightsCache().get(profileId); 275 if (list != null) 276 { 277 return list; 278 } 279 } 280 return Collections.EMPTY_LIST; 281 } 282 283 /** 284 * Get the rights of a profile 285 * @param profile The profile 286 * @return The rights 287 */ 288 public List<String> getRights (Profile profile) 289 { 290 if (profile == null) 291 { 292 return Collections.EMPTY_LIST; 293 } 294 else 295 { 296 return getRights(profile.getId()); 297 } 298 } 299 300 /** 301 * Add a right to a profile 302 * @param profile The profile 303 * @param rightId The id of right to add 304 */ 305 public void addRight (Profile profile, String rightId) 306 { 307 try (SqlSession session = getSession(true)) 308 { 309 _addRight (session, profile, rightId); 310 } 311 312 clearCache(); 313 } 314 315 /** 316 * Add a right to a profile 317 * @param profile The profile 318 * @param rightIds The id of rights to add 319 */ 320 public void addRights (Profile profile, List<String> rightIds) 321 { 322 try (SqlSession session = getSession()) 323 { 324 for (String rightId : rightIds) 325 { 326 _addRight (session, profile, rightId); 327 } 328 329 session.commit(); 330 } 331 332 clearCache(); 333 } 334 335 /** 336 * Update the rights of a profile 337 * @param profile The profile 338 * @param rights The rights of the profile 339 */ 340 public void updateRights (Profile profile, List<String> rights) 341 { 342 updateRights(profile, rights, false); 343 } 344 345 /** 346 * Update the rights of a profile 347 * @param profile The profile 348 * @param rights The rights of the profile 349 * @param silent Set to true to not notify observer of this update 350 */ 351 public void updateRights (Profile profile, List<String> rights, boolean silent) 352 { 353 try (SqlSession session = getSession()) 354 { 355 session.delete("Profiles.deleteProfileRights", profile.getId()); 356 357 if (rights != null) 358 { 359 for (String rightId : rights) 360 { 361 _addRight (session, profile, rightId); 362 } 363 } 364 365 session.commit(); 366 367 clearCache(); 368 369 if (!silent) 370 { 371 _notifyEvent(profile, ObservationConstants.EVENT_PROFILE_UPDATED); 372 } 373 } 374 } 375 376 private void _addRight (SqlSession session, Profile profile, String rightId) 377 { 378 Map<String, Object> params = new HashMap<>(); 379 params.put("profileId", profile.getId()); 380 params.put("rightId", rightId); 381 382 session.insert("Profiles.addRight", params); 383 } 384 385 /** 386 * Add a right to a profile 387 * @param profile The profile 388 */ 389 public void removeRights (Profile profile) 390 { 391 removeRights(profile, false); 392 } 393 394 /** 395 * Add a right to a profile 396 * @param profile The profile 397 * @param silent Set to true to not notify observer of this update 398 */ 399 public void removeRights (Profile profile, boolean silent) 400 { 401 try (SqlSession session = getSession(true)) 402 { 403 session.delete("Profiles.deleteProfileRights", profile.getId()); 404 405 clearCache(); 406 407 if (!silent) 408 { 409 _notifyEvent(profile, ObservationConstants.EVENT_PROFILE_UPDATED); 410 } 411 } 412 } 413 414 /** 415 * Delete a profile 416 * @param profile The profile to delete 417 */ 418 public void deleteProfile (Profile profile) 419 { 420 deleteProfile(profile, false); 421 } 422 423 /** 424 * Delete a profile 425 * @param profile The profile to delete 426 * @param silent Set to true to not notify observer of this update 427 */ 428 public void deleteProfile (Profile profile, boolean silent) 429 { 430 try (SqlSession session = getSession()) 431 { 432 session.delete("Profiles.deleteProfile", profile.getId()); 433 session.delete("Profiles.deleteProfileRights", profile.getId()); 434 435 session.commit(); 436 437 clearCache(); 438 439 if (!silent) 440 { 441 _notifyEvent(profile, ObservationConstants.EVENT_PROFILE_DELETED); 442 } 443 } 444 } 445 446 private void _notifyEvent (Profile profile, String eventId) 447 { 448 try 449 { 450 if (_observationManager == null) 451 { 452 _observationManager = (ObservationManager) _smanager.lookup(ObservationManager.ROLE); 453 } 454 if (_currentUserProvider == null) 455 { 456 _currentUserProvider = (CurrentUserProvider) _smanager.lookup(CurrentUserProvider.ROLE); 457 } 458 459 Map<String, Object> eventParams = new HashMap<>(); 460 eventParams.put(ObservationConstants.ARGS_PROFILE, profile); 461 _observationManager.notify(new Event(eventId, _currentUserProvider.getUser(), eventParams)); 462 } 463 catch (ServiceException e) 464 { 465 getLogger().error("Fail to notify observers for event '" + eventId + "'", e); 466 } 467 } 468}