/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.smartitengineering.user.service.impl.cache; import com.google.inject.Inject; import com.google.inject.name.Named; import com.smartitengineering.dao.common.cache.CacheServiceProvider; import com.smartitengineering.dao.common.cache.Lock; import com.smartitengineering.dao.common.cache.Mutex; import com.smartitengineering.dao.common.cache.impl.CacheAPIFactory; import com.smartitengineering.user.domain.Role; import com.smartitengineering.user.filter.RoleFilter; import com.smartitengineering.user.service.RoleService; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author imyousuf */ public class RoleServiceCacheImpl implements RoleService { @Inject @Named("primaryService") private RoleService primaryService; @Inject private CacheServiceProvider<Long, Role> cacheProvider; @Inject private CacheServiceProvider<String, Long> nameCacheProvider; private transient final Logger logger = LoggerFactory.getLogger(getClass()); private final Mutex<Long> mutex = CacheAPIFactory.<Long>getMutex(); @Override public void create(Role role) { //Simply delegate primaryService.create(role); } @Override public void update(Role role) { //First update then delete if update successful! try { primaryService.update(role); expireFromCache(role); } catch (RuntimeException exception) { logger.info("Could not update thus invalidate cache!", exception); throw exception; } } @Override public void delete(Role role) { try { primaryService.delete(role); expireFromCache(role); } catch (RuntimeException exception) { logger.info("Could not update thus invalidate cache!", exception); throw exception; } } @Override public Set<Role> getRolesByIds(Long... ids) { return getRolesByIds(Arrays.asList(ids)); } @Override public Set<Role> getRolesByIds(List<Long> ids) { if (ids == null || ids.isEmpty()) { return Collections.emptySet(); } Map<Long, Role> results = new HashMap<Long, Role>(ids.size()); List<Long> missedIds = new ArrayList<Long>(ids); results.putAll(cacheProvider.retrieveFromCache(missedIds)); for (Long id : results.keySet()) { missedIds.remove(id); } Map<Long, Lock<Long>> locks = new HashMap<Long, Lock<Long>>(missedIds.size()); for (Long missedId : missedIds) { boolean attained = false; while (!attained) { try { locks.put(missedId, mutex.acquire(missedId)); attained = true; } catch (Exception ex) { logger.warn("Could not acquire lock for role!"); } } } results.putAll(cacheProvider.retrieveFromCache(missedIds)); for (Long id : results.keySet()) { if (missedIds.remove(id)) { mutex.release(locks.get(id)); } } Set<Role> fromSource = primaryService.getRolesByIds(missedIds); for (Role role : fromSource) { putToCache(role); results.put(role.getId(), role); } for (Long id : missedIds) { mutex.release(locks.get(id)); } LinkedHashSet<Role> resultSet = new LinkedHashSet<Role>(results.size()); for (Long id : ids) { Role role = results.get(id); if (role != null) { resultSet.add(role); } } return resultSet; } @Override public Role getRoleByName(String roleName) { Long id = nameCacheProvider.retrieveFromCache(getNameCacheKey(roleName)); if (id != null) { Set<Role> set = getRolesByIds(id); if (set != null && !set.isEmpty()) { return set.iterator().next(); } } return primaryService.getRoleByName(roleName); } @Override public Collection<Role> getAllRoles() { return primaryService.getAllRoles(); } @Override public Collection<Role> search(RoleFilter filter) { return primaryService.search(filter); } @Override public void validateRole(Role role) { primaryService.validateRole(role); } private String getNameCacheKey(Role role) { final String name = role.getName(); return getNameCacheKey(name); } protected String getNameCacheKey(final String name) { return new StringBuilder("role:").append(name).toString(); } private void putToCache(Role role) { cacheProvider.putToCache(role.getId(), role); nameCacheProvider.putToCache(getNameCacheKey(role), role.getId()); } private void expireFromCache(Role role) { if (cacheProvider.containsKey(role.getId())) { Set<Role> set = getRolesByIds(role.getId()); if (set != null && !set.isEmpty()) { nameCacheProvider.expireFromCache(getNameCacheKey(set.iterator().next())); } cacheProvider.expireFromCache(role.getId()); } } }