package com.google.sitebricks.binding;
import com.google.common.collect.MapMaker;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import net.jcip.annotations.ThreadSafe;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
/**
* Used to store binding (or forwarding) information between successive requests.
*
* @author Dhanji R. Prasanna (dhanji@gmail.com)
*/
@ThreadSafe @Singleton
class CookieBasedFlashCache implements FlashCache, Serializable {
private final ConcurrentMap<String, Object> cache = new MapMaker()
.concurrencyLevel(64)
.makeMap();
/**
* Name of the cookie we use to create flash-scoping. I.e. consecutive
* request detection (without sessions).
*/
private static final String FLASH_COOKIE = "X-SB-Flash";
private final Provider<HttpServletRequest> request;
private final Provider<HttpServletResponse> response;
@Inject
public CookieBasedFlashCache(Provider<HttpServletRequest> request,
Provider<HttpServletResponse> response) {
this.request = request;
this.response = response;
}
@SuppressWarnings("unchecked")
public <T> T get(String key) {
String cookieId = findCookie();
if (cookieId == null) {
return null;
}
// This is how the cookie is constructed in {@linkplain #put}
key = cookieId + key;
return (T) cache.get(key);
}
@SuppressWarnings("unchecked")
public <T> T remove(String key) {
String cookieId = findCookie();
if (cookieId == null) {
return null;
}
// This is how the cookie is constructed in {@linkplain #put}
key = cookieId + key;
return (T) cache.remove(key);
}
public <T> void put(String key, T t) {
String cookieId = (String) request.get().getAttribute(FLASH_COOKIE);
if (null == cookieId) {
// seed a cookie for the next time this user comes back
cookieId = UUID.randomUUID().toString();
response.get().addCookie(new Cookie(FLASH_COOKIE, cookieId));
// memo for this request... (we only need to set the cookie once per request)
request.get().setAttribute(FLASH_COOKIE, cookieId);
}
// Compose a key from the cookied id + the store key
// We use the cookied id first coz the first 5 chars of
// String are used for generating a hash.
key = cookieId + key;
cache.put(key, t);
}
private String findCookie() {
String cookieId = null;
for (Cookie cookie : request.get().getCookies()) {
if (FLASH_COOKIE.equals(cookie.getName())) {
cookieId = cookie.getValue();
}
}
return cookieId;
}
}