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