package in.srain.cube.request;
import android.text.TextUtils;
import in.srain.cube.cache.CacheManager;
import in.srain.cube.cache.CacheResultType;
import in.srain.cube.concurrent.SimpleTask;
import in.srain.cube.util.CLog;
import in.srain.cube.util.Debug;
import java.net.URI;
import java.net.URISyntaxException;
public class CacheAbleRequest<T> extends RequestBase<T> implements ICacheAbleRequest<T> {
public static enum ResultType {
USE_CACHE_NOT_EXPIRED,
USE_CACHE_ANYWAY,
USE_CACHE_ON_TIMEOUT,
USE_DATA_FROM_SERVER,
USE_CACHE_ON_FAIL,
}
protected static final boolean DEBUG = Debug.DEBUG_CACHE;
protected static final String LOG_TAG = "cube_cache_request";
private CacheAbleRequestHandler<T> mHandler;
private T mCacheData;
private boolean mOutOfDate;
private String mCacheKey = null;
private int mTimeout = 0;
private boolean mHasTimeout = false;
private boolean mUseCacheAnyway = false;
private boolean mHasNotified = false;
protected boolean mForceQueryFromServer = false;
private String mInitDataPath;
private boolean mDisableCache = false;
private long mCacheTime;
public CacheAbleRequest() {
}
public CacheAbleRequest(final CacheAbleRequestHandler<T> handler) {
setCacheAbleRequestHandler(handler);
}
public void setCacheAbleRequestHandler(CacheAbleRequestHandler<T> handler) {
mHandler = handler;
}
public void forceQueryFromServer(boolean force) {
mForceQueryFromServer = force;
}
// ===========================================================
// Override parent
// ===========================================================
@Override
public void doSendRequest() {
RequestCacheManager.getInstance().requestCache(this);
}
/**
* prepare request
*/
@Override
protected void prepareRequest() {
}
// ===========================================================
// Override Interface
// ===========================================================
@Override
public void setTimeout(int timeOut) {
mTimeout = timeOut;
}
@Override
public void useCacheAnyway(boolean use) {
mUseCacheAnyway = use;
}
@Override
public void onRequestSuccess(T data) {
if (DEBUG) {
CLog.d(LOG_TAG, "%s, onRequestSuccess", getCacheKey());
}
if (hasBeenCanceled()) {
return;
}
mCacheData = data;
if (null != mHandler) {
mHandler.onRequestFinish(data);
if (!mHasTimeout && !mUseCacheAnyway) {
notifyRequestFinish(ResultType.USE_DATA_FROM_SERVER, false);
} else {
if (DEBUG) {
CLog.d(LOG_TAG, "%s, will not notifyRequestFinish", getCacheKey());
}
}
}
}
@Override
public void onRequestFail(FailData failData) {
if (DEBUG) {
CLog.d(LOG_TAG, "%s, onRequestFail", getCacheKey());
}
if (hasBeenCanceled()) {
return;
}
if (null != mHandler) {
mHandler.onRequestFail(failData);
if (mCacheData != null && !cacheIsDisabled() && !mUseCacheAnyway) {
notifyRequestFinish(ResultType.USE_CACHE_ON_FAIL, true);
} else {
mHandler.onRequestFail(null);
}
}
}
@Override
public void createDataForCache(CacheManager cacheManager) {
if (DEBUG) {
CLog.d(LOG_TAG, "%s, createDataForCache", getCacheKey());
}
if (hasBeenCanceled()) {
return;
}
doQueryFromServer();
beginTimeout();
}
protected void doQueryFromServer() {
SimpleRequestManager.sendRequest(this);
}
protected boolean cacheRequestResult() {
return mForceQueryFromServer || !cacheIsDisabled();
}
@Override
public boolean cacheIsDisabled() {
if (mForceQueryFromServer) {
return true;
}
return mDisableCache;
}
// ===========================================================
// Implements Interface {@link ICacheAble}
// ===========================================================
@Override
public void onCacheData(CacheResultType cacheResultType, T data, boolean outOfDate) {
if (DEBUG) {
CLog.d(LOG_TAG, "%s, onQueryFinish, out of date: %s", getCacheKey(), outOfDate);
}
if (hasBeenCanceled()) {
return;
}
mCacheData = data;
mOutOfDate = outOfDate;
if (null != mHandler) {
mHandler.onCacheData(data, outOfDate);
if (mUseCacheAnyway) {
notifyRequestFinish(ResultType.USE_CACHE_ANYWAY, mOutOfDate);
} else {
if (!outOfDate) {
notifyRequestFinish(ResultType.USE_CACHE_NOT_EXPIRED, false);
}
}
}
}
@Override
public long getCacheTime() {
return mCacheTime;
}
@Override
public String getCacheKey() {
if (mCacheKey == null) {
String cacheKey = null;
String url = getRequestData().getRequestUrl();
try {
URI uri = null;
uri = new URI(url);
cacheKey = uri.getPath();
if (cacheKey.startsWith("/")) {
cacheKey = cacheKey.substring(1);
}
cacheKey = cacheKey.replace("/", "-");
} catch (URISyntaxException e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(cacheKey)) {
throw new RuntimeException("Cache key is null");
}
mCacheKey = cacheKey;
}
return mCacheKey;
}
@Override
public String getAssertInitDataPath() {
return mInitDataPath;
}
@Override
public T onDataFromServer(String data) {
if (DEBUG) {
CLog.d(LOG_TAG, "%s, onDataFromServer", getCacheKey());
}
// cache the data
if (!TextUtils.isEmpty(data) && cacheRequestResult()) {
RequestCacheManager.getInstance().setCacheData(this.getCacheKey(), data);
}
return super.onDataFromServer(data);
}
@Override
public T processOriginDataFromServer(JsonData rawData) {
return mHandler.processOriginData(rawData);
}
@Override
public T processRawDataFromCache(JsonData rawData) {
return mHandler.processOriginData(rawData);
}
/**
* will only notify once
*
* @param type
* @param outOfDate
*/
private void notifyRequestFinish(ResultType type, boolean outOfDate) {
if (DEBUG) {
CLog.d(LOG_TAG, "%s, notifyRequestFinish: %s, %s", getCacheKey(), type, outOfDate);
}
if (mHasNotified) {
return;
}
mHasNotified = true;
mHandler.onCacheAbleRequestFinish(mCacheData, type, outOfDate);
}
private void timeout() {
mHasTimeout = true;
if (mCacheData != null && mHandler != null) {
notifyRequestFinish(ResultType.USE_CACHE_ON_TIMEOUT, true);
}
}
private void beginTimeout() {
if (mTimeout > 0 && mCacheData != null) {
SimpleTask.postDelay(new Runnable() {
@Override
public void run() {
timeout();
}
}, mTimeout);
}
}
public CacheAbleRequest setCacheKey(String cacheKey) {
mCacheKey = cacheKey;
return this;
}
public CacheAbleRequest setDisableCache(boolean disable) {
mDisableCache = disable;
return this;
}
public CacheAbleRequest setInitDataPath(String path) {
mInitDataPath = path;
return this;
}
public CacheAbleRequest setCacheTime(long cacheTime) {
mCacheTime = cacheTime;
return this;
}
}