package ddth.dasp.hetty.mvc.view; import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.builder.HashCodeBuilder; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import ddth.dasp.hetty.message.IRequest; import ddth.dasp.hetty.qnt.ITopicPublisher; public abstract class CacheViewResolver implements IViewResolver { private boolean enableCache = true; private boolean cacheNull = true; private Cache<String, IView> cache; private long cacheCapacity = 1000; public boolean isEnableCache() { return enableCache; } public void setEnableCache(boolean enableCache) { this.enableCache = enableCache; } public boolean isCacheNull() { return cacheNull; } public void setCacheNull(boolean cacheNull) { this.cacheNull = cacheNull; } public long getCacheCapacity() { return cacheCapacity; } public void setCacheCapacity(long cacheCapacity) { this.cacheCapacity = cacheCapacity; } public void init() { if (enableCache) { int concurrencyLevel = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); CacheBuilder<Object, Object> cacheBuider = CacheBuilder.newBuilder(); cacheBuider.concurrencyLevel(concurrencyLevel); long expireAfterAccess = 3600; long expireAfterWrite = 3600; cacheBuider.maximumSize(cacheCapacity); if (expireAfterAccess > 0) { cacheBuider.expireAfterAccess(expireAfterAccess, TimeUnit.SECONDS); } else if (expireAfterWrite > 0) { cacheBuider.expireAfterWrite(expireAfterWrite, TimeUnit.SECONDS); } else { cacheBuider.expireAfterAccess(3600, TimeUnit.SECONDS); } cache = cacheBuider.build(); } } public void destroy() { if (cache != null) { cache.cleanUp(); } cache = null; } protected String calcCacheKey(String name, Map<String, String> replacements) { return String.valueOf(new HashCodeBuilder(19, 81).append(name).append(replacements) .toHashCode()); } @Override public IView resolveView(String name, Map<String, String> replacements) { if (name.startsWith(REDIRECT_VIEW_PREFIX) || name.startsWith(FORWARD_VIEW_PREFIX)) { String[] tokens = name.split(":", 2); return new RedirectView(tokens[1]); } IView result = null; if (cache != null) { String cacheKey = calcCacheKey(name, replacements); result = cache.getIfPresent(cacheKey); if (result == null) { result = createView(name, replacements); if (result != null) { cache.put(cacheKey, result); } else if (cacheNull) { cache.put(cacheKey, new NullView()); } } } else { result = createView(name, replacements); } return result instanceof NullView ? null : result; } protected abstract IView createView(String name, Map<String, String> replacements); protected static class NullView implements IView { @Override public void render(IRequest request, Object model, ITopicPublisher topicPublisher, String topicName) throws Exception { // empty } } }