package play.utils.cache;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import play.Logger;
import play.Logger.ALogger;
import play.cache.Cache;
import play.db.ebean.Model.Finder;
import com.avaje.ebean.Expression;
import com.avaje.ebean.Page;
public class CachedFinder<K, T> extends Finder<K, T> {
private static ALogger log = Logger.of(CachedFinder.class);
/** expire in 24 hours */
private static final int EXPIRATION = 24 * 3600;
/** serial id */
private static final long serialVersionUID = 1L;
/** prefix for all keys */
private final String pre;
/** prefix for page keys */
private final String prePage;
/** key for retrieving all entities */
private final String keyAll;
/** cache keys for cached pages */
private final Set<String> pages = new HashSet<String>();
public CachedFinder(Class<K> keyType, Class<T> type) {
super(keyType, type);
this.pre = type.getName();
keyAll = pre + ".all";
prePage = pre + ".page.";
}
public CachedFinder(String serverName, Class<K> keyType, Class<T> type) {
super(serverName, keyType, type);
this.pre = type.getName();
keyAll = pre + ".all";
prePage = pre + ".page.";
}
@Override
public T byId(final K id) {
String key = pre + id;
try {
return Cache.getOrElse(key, new Callable<T>() {
public T call() throws Exception {
return CachedFinder.super.byId(id);
}
}, EXPIRATION);
} catch (Exception e) {
log.error("exception occured while retrieving from cache", e);
return super.byId(id);
}
}
@Override
public T ref(final K id) {
String key = pre + id;
try {
return Cache.getOrElse(key, new Callable<T>() {
public T call() throws Exception {
return CachedFinder.super.ref(id);
}
}, EXPIRATION);
} catch (Exception e) {
log.error("exception occured while retrieving from cache", e);
return super.ref(id);
}
}
@SuppressWarnings("unchecked")
public T clean(final K id) {
String key = pre + id;
T t = null;
try {
t = (T) Cache.get(key);
} catch (Exception e) {
log.debug("exception occured while retrieving from cache", e);
}
//clean self entry
Cache.set(key, null);
if (t != null)
cleanBulkCaches();
return t;
}
public void put(K id, T t) {
String key = pre + id;
Cache.set(key, t);
if (t != null)
cleanBulkCaches();
}
@Override
public List<T> all() {
try {
return Cache.getOrElse(keyAll, new Callable<List<T>>() {
public List<T> call() throws Exception {
return CachedFinder.super.all();
}
}, EXPIRATION);
} catch (Exception e) {
log.error("exception occured while retrieving from cache", e);
return super.all();
}
}
public Page<T> page(final int page, final int pageSize, final String orderBy) {
String key = prePage + page;
try {
Page<T> p = Cache.getOrElse(key, new Callable<Page<T>>() {
public Page<T> call() throws Exception {
return where().orderBy(orderBy).findPagingList(pageSize)
.getPage(page);
}
}, EXPIRATION);
pages.add(key);
return p;
} catch (Exception e) {
log.error("exception occured while retrieving from cache", e);
return where().orderBy(orderBy).findPagingList(pageSize)
.getPage(page);
}
}
public <F> Page<T> page(final int page, final int pageSize, final String orderBy, final String filterField, final F filterValue) {
String key = prePage + page + "." + filterField + "." + filterValue;
try {
Page<T> p = Cache.getOrElse(key, new Callable<Page<T>>() {
public Page<T> call() throws Exception {
return where().eq(filterField, filterValue)
.orderBy(orderBy).findPagingList(pageSize)
.getPage(page);
}
}, EXPIRATION);
pages.add(key);
return p;
} catch (Exception e) {
log.error("exception occured while retrieving from cache", e);
return where().eq(filterField, filterValue).orderBy(orderBy)
.findPagingList(pageSize).getPage(page);
}
}
public Page<T> page(final int page, final int pageSize, final String orderBy, String cacheKey, final Expression expression) {
String key = prePage + page + "." + cacheKey;
try {
Page<T> p = Cache.getOrElse(key, new Callable<Page<T>>() {
public Page<T> call() throws Exception {
return where().add(expression).orderBy(orderBy)
.findPagingList(pageSize).getPage(page);
}
}, EXPIRATION);
pages.add(key);
return p;
} catch (Exception e) {
log.error("exception occured while retrieving from cache", e);
return where().add(expression).orderBy(orderBy)
.findPagingList(pageSize).getPage(page);
}
}
protected void cleanBulkCaches() {
//clean other entries
Cache.set(keyAll, null);
//clean all pages
for (String page : pages) {
Cache.set(page, null);
}
pages.clear();
}
}