package cn.dreampie.route.cache;
import cn.dreampie.cache.SimpleCache;
import cn.dreampie.common.Constant;
import cn.dreampie.common.http.HttpMethod;
import cn.dreampie.common.http.HttpRequest;
import cn.dreampie.common.http.HttpResponse;
import cn.dreampie.common.http.result.HttpStatus;
import cn.dreampie.log.Logger;
import cn.dreampie.route.annotation.API;
import cn.dreampie.route.annotation.GET;
import cn.dreampie.route.core.RouteInvocation;
import cn.dreampie.route.core.RouteMatch;
import cn.dreampie.route.interceptor.Interceptor;
import java.util.Date;
import java.util.UUID;
/**
* Created by Dreampie on 16/1/8.
*/
public class CacheInterceptor implements Interceptor {
private final static Logger logger = Logger.getLogger(CacheInterceptor.class);
public static final String HTTP_DEF_KEY = "_http";
private int expired = -1;//-1 表示事件驱动缓存更新 缓存不会过期
public CacheInterceptor() {
}
public CacheInterceptor(int expired) {
this.expired = expired;
}
public void intercept(RouteInvocation ri) {
if (Constant.cacheEnabled) {
API apiAnno = (API) ri.getResourceClass().getAnnotation(API.class);
String apiValue = apiAnno.value();
RouteMatch routeMatch = ri.getRouteMatch();
HttpRequest request = routeMatch.getRequest();
HttpResponse response = routeMatch.getResponse();
String method = request.getHttpMethod();
String group = HTTP_DEF_KEY + Constant.CONNECTOR + apiValue;
String uri = request.getRestUri();
String version = SimpleCache.instance().get(group, apiValue);
if (method.equals(HttpMethod.GET)) {
GET getAnno = ri.getMethod().getAnnotation(GET.class);
//缓存请求判断
if (getAnno.cached()) {
String previousToken = request.getHeader("If-None-Match");
// compare previous token with current one
if ((version != null) && (previousToken != null && previousToken.equals('"' + version + '"'))) {
HttpStatus status = HttpStatus.NOT_MODIFIED;
response.setStatus(status);
// re-use original last modified timestamp
response.setHeader("Last-Modified", request.getHeader("If-Modified-Since"));
logger.info("Not modify '" + uri + "'");
return; // no further processing required
}
//设置ETag
setETag(apiValue, response, group, version);
Object result = SimpleCache.instance().get(group, uri);
if (result == null) {
result = ri.invoke();
SimpleCache.instance().add(group, uri, result, expired);
} else {
//not invoke render cache result
ri.render(result);
}
return;
}
} else {
//重置ETag
setETag(apiValue, response, group, null);
SimpleCache.instance().flush(group);//清楚 get 缓存
}
}
//不缓存请求
ri.invoke();
}
private void setETag(String apiValue, HttpResponse response, String group, String version) {
// set header for the next time the client calls
if (version == null) {
version = UUID.randomUUID().toString();
SimpleCache.instance().add(group, apiValue, version, expired);
}
// first time through - set last modified time to now
response.setHeader("Last-Modified", new Date().toString());
response.setHeader("ETag", '"' + version + '"');
}
}