package org.multibit.mbm.auth; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import org.multibit.mbm.model.ClientUser; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * <p>Cache to provide the following to {@link org.multibit.mbm.model.ClientUser} authenticators:</p> * <ul> * <li>In-memory thread-safe cache for client user instances</li> * <li>Provision of fast lookup for request authentication</li> * </ul> * * @since 0.0.1 *   */ public enum InMemorySessionTokenCache { // Provide a global singleton for the application INSTANCE; // A lot of threads will hit this cache private volatile Cache<UUID, ClientUser> sessionTokenCache; InMemorySessionTokenCache() { reset(15,TimeUnit.MINUTES); } /** * Resets the cache and allows the expiry time to be set (perhaps for testing) * * @param duration The duration before a user must manually authenticate through a web form due to inactivity * @param unit The {@link TimeUnit} that duration is expressed in */ public InMemorySessionTokenCache reset(int duration, TimeUnit unit) { // Build the cache if (sessionTokenCache != null) { sessionTokenCache.invalidateAll(); } // If there is no activity against a key then we want // it to be expired from the cache, but each fresh write // will reset the expiry timer sessionTokenCache = CacheBuilder .newBuilder() .expireAfterWrite(duration, unit) .maximumSize(1000) .build(); return INSTANCE; } /** * @param sessionToken The session token to locate the user * * @return The matching ClientUser or absent */ public Optional<ClientUser> getBySessionToken(Optional<UUID> sessionToken) { // Fail fast if (!sessionToken.isPresent()) { return Optional.absent(); } // Check the cache Optional<ClientUser> clientUser = Optional.fromNullable(sessionTokenCache.getIfPresent(sessionToken.get())); // TODO What is a better way of implementing this? if (clientUser.isPresent()) { // Ensure we refresh the cache on a check to maintain the session timeout sessionTokenCache.put(clientUser.get().getSessionToken(), clientUser.get()); } return clientUser; } /** * @param sessionToken The session token to use to locate the user * @param clientUser The client user to cache */ public void put(UUID sessionToken, ClientUser clientUser) { Preconditions.checkNotNull(clientUser); sessionTokenCache.put(sessionToken, clientUser); } }