package com.m.support.bizlogic;
import java.io.File;
import android.text.TextUtils;
import com.alibaba.fastjson.JSON;
import com.m.common.params.Params;
import com.m.common.settings.Setting;
import com.m.common.settings.SettingUtil;
import com.m.common.settings.SettingUtility;
import com.m.common.utils.Consts;
import com.m.common.utils.KeyGenerator;
import com.m.common.utils.Logger;
import com.m.support.cache.ICacheUtility;
import com.m.support.cache.ICacheUtility.Cache;
import com.m.support.cache.MemoryCacheUtility;
import com.m.support.iclass.IResult;
import com.m.support.network.HttpConfig;
import com.m.support.network.HttpUtility;
import com.m.support.network.http.DefHttpUtility;
import com.m.support.task.TaskException;
import com.m.support.task.WorkTask;
public abstract class ABaseBizlogic implements HttpUtility {
public static final String TAG = "ABaseBizlogic";
public enum CacheMode {
/**
* 有缓存且有效,返回缓存<br/>
* 有缓存但无效,拉取服务数据,如果拉取失败,仍然返回无效缓存<br/>
* 没有缓存,拉取服务数据
*/
auto,
/**
* 在{@link #auto}的基础上,不管存不存在缓存,都拉取服务数据更新缓存
*/
servicePriority,
/**
* 每次拉取数据,都优先拉取缓存
*/
cachePriority,
/**
* 只拉取服务数据
*/
disable
}
private HttpUtility mHttpUtility;
private ICacheUtility memoryCacheUtility;
private CacheMode mCacheMode;
public ABaseBizlogic() {
mHttpUtility = configHttpUtility();
mCacheMode = SettingUtility.getBooleanSetting("debug") ? CacheMode.auto : CacheMode.disable;
}
public ABaseBizlogic(CacheMode cacheMode) {
this();
this.mCacheMode = cacheMode;
}
protected Setting getSetting(String type) {
return SettingUtility.getSetting(type);
}
@Override
public <T> T doGet(HttpConfig config, Setting actionSetting, Params params, Class<T> responseCls) throws TaskException {
throw new RuntimeException(
"not support this method ---> doGet(HttpConfig config, Setting actionSetting, Params params, Class<T> responseCls), please call ---> doGet(Setting actionSetting, Params params, Class<T> responseCls)");
}
public <T> T doGet(final Setting actionSetting, final Params params, Class<T> responseCls) throws TaskException {
HttpConfig mConfig = cloneHttpConfig(configHttpConfig(), actionSetting);
String action = actionSetting.getValue();
Logger.v(TAG, String.format("do get() method, url = %s, action = %s, desc = %s", mConfig.baseUrl, action, actionSetting.getDescription()));
Logger.v(TAG, String.format("params ---> %s", toJson(params)));
Logger.v(TAG, String.format("HttpConfig ---> %s", toJson(mConfig)));
ICacheUtility cacheUtility = null;
// 配置的缓存模式
String cacheUtilityStr = SettingUtil.getSettingValue(actionSetting, Consts.Setting.CACHE_UTILITY);
if (!TextUtils.isEmpty(cacheUtilityStr)) {
try {
cacheUtility = (ICacheUtility) Class.forName(cacheUtilityStr).newInstance();
} catch (Exception e) {
Logger.w(TAG, "CacheUtility has not setting or error setting");
}
}
// 内存缓存
if (actionSetting.getExtras().containsKey(Consts.Setting.MEMORY_CACHE_UTILITY)) {
String memoryCacheUtilityStr = actionSetting.getExtras().get(Consts.Setting.MEMORY_CACHE_UTILITY).getValue();
if (!TextUtils.isEmpty(memoryCacheUtilityStr)) {
try {
memoryCacheUtility = (ICacheUtility) Class.forName(memoryCacheUtilityStr).newInstance();
} catch (Exception e) {
Logger.w(TAG, "MemoryCacheUtility has not setting or error setting");
}
}
}
Cache<T> cache = null;
// 缓存是否在action中配置打开
boolean cacheEnable = actionSetting.getExtras().containsKey(Consts.Setting.CACHE_ENABLE) ? Boolean.parseBoolean(actionSetting.getExtras()
.get(Consts.Setting.CACHE_ENABLE).getValue()) : false;
// 如果是DEBUG模式,则不管配不配置,都打开缓存
if (SettingUtility.getPermanentSettingAsBool(Consts.Setting.DEBUG, false))
cacheEnable = true;
if (cacheEnable && (mCacheMode == CacheMode.cachePriority || mCacheMode != CacheMode.disable)) {
// 拉取内存
// SettingUtility.getIntSetting(Consts.Setting.MEMORY_CACHE_VALIDITY) > 0
if (memoryCacheUtility != null) {
cache = memoryCacheUtility.findCacheData(actionSetting, params, responseCls);
if (cache != null) {
String state = cache.expired() ? "invalid" : "valid";
Logger.d(TAG, String.format("The state of the %s cache time is %s, action = %s", MemoryCacheUtility.class.getSimpleName(), state,
actionSetting.getValue()));
}
}
// 拉取缓存数据
if ((cache == null || cache.expired()) && cacheUtility != null) {
cache = cacheUtility.findCacheData(actionSetting, params, responseCls);
if (cache != null) {
String state = cache.expired() ? "invalid" : "valid";
Logger.d(TAG, String.format("The state of the %s cache time is %s, action = %s", cacheUtility.getClass().getSimpleName(), state,
actionSetting.getValue()));
}
if (memoryCacheUtility != null && cache != null && !cache.expired()) {
// 文件缓存 拉到数据后 刷新内存
putToCache(actionSetting, params, cache.getT(), memoryCacheUtility);
Logger.v(TAG, String.format("Refresh the memory cache, action = %s", actionSetting.getValue()));
}
}
}
T result = null;
// 缓存不存在、缓存无效、服务数据优先等情况下,拉取服务数据
if ((cache == null || cache.expired()) || mCacheMode == CacheMode.servicePriority) {
Exception serviceEx = null;
try {
result = getHttpUtility(actionSetting).doGet(mConfig, actionSetting, params, responseCls);
if (result != null) {
// 刷新内存缓存
if (memoryCacheUtility != null)
putToCache(actionSetting, params, result, memoryCacheUtility);
// 刷新持久缓存
if (cacheUtility != null) {
// 如果数据来自缓存,则不刷新
if (result instanceof IResult && ((IResult) result).isCache()) {
Logger.w(ABaseBizlogic.TAG, "数据来自缓存,不刷新");
}
else {
putToCache(actionSetting, params, result, cacheUtility);
}
}
Logger.d(TAG, String.format("load data from webservice, action = %s --->%s", actionSetting.getValue(), Logger.toJson(result)));
}
} catch (Exception e) {
serviceEx = e;
}
// 拉取网络失败,如果存在缓存,仍然返回缓存
if (result == null && (cache != null && mCacheMode != CacheMode.disable)) {
result = cache.getT();
// 刷新内存缓存
if (memoryCacheUtility != null && result != null)
putToCache(actionSetting, params, result, memoryCacheUtility);
} else {
// 如果是拉取服务数据异常,抛出异常
if (serviceEx != null) {
TaskException taskException = null;
if (serviceEx.getCause() instanceof TaskException) {
taskException = (TaskException) serviceEx.getCause();
}
else if (serviceEx instanceof TaskException) {
taskException = (TaskException) serviceEx;
}
if (taskException != null)
throw taskException;
throw new TaskException(TextUtils.isEmpty(serviceEx.getMessage()) ? "服务器错误" : serviceEx.getMessage());
}
}
} else {
// 缓存存在,且有效
if (cache != null && !cache.expired())
result = cache.getT();
}
// 返回 克隆对象 任意编辑不对这边的 数据产生影响
// return ObjectUtil.cloneObject(result);
return result;
}
@Override
public <T> T doPost(HttpConfig config, Setting action, Params params, Class<T> responseCls, Object requestObj) throws TaskException {
HttpConfig mConfig = cloneHttpConfig(config, action);
try {
Logger.d(TAG, String.format("doPost(config --->%s, \naction--->%s, \nparams --->%s, \nrequestObj --->%s)", toJson(mConfig),
toJson(action), toJson(params), toJson(requestObj == null ? "requestObj is null" : requestObj)));
} catch (Exception e) {
}
String key = KeyGenerator.generateMD5(action.getValue(), params);
Logger.d(TAG, String.format("cacheKey = %s", key));
T result = getHttpUtility(action).doPost(mConfig, action, params, responseCls, requestObj);
if (result != null)
Logger.d(TAG, String.format("%s Successfully loaded --->%s", action.getDescription(), toJson(result)));
else
Logger.d(TAG, String.format("%s load failed", action.getDescription()));
return result;
}
@Override
public <T> T uploadFile(HttpConfig config, Setting action, Params params, File file, Params headers, Class<T> responseClass) throws TaskException {
HttpConfig mConfig = cloneHttpConfig(config, action);
Logger.d(TAG, String.format("uploadFile(config --->%s, \naction--->%s, \nparams --->%s, \nfilePath --->%s)", toJson(mConfig), toJson(action),
toJson(params), file.getAbsoluteFile()));
String key = KeyGenerator.generateMD5(action.getValue(), params);
Logger.d(TAG, String.format("cacheKey = %s", key));
T result = getHttpUtility(action).uploadFile(mConfig, action, params, file, headers, responseClass);
return result;
}
private HttpUtility getHttpUtility(Setting action) {
if (action.getExtras().get("http") != null && !TextUtils.isEmpty(action.getExtras().get("http").getValue())) {
try {
HttpUtility httpUtility = (HttpUtility) Class.forName(action.getExtras().get("http").getValue()).newInstance();
return httpUtility;
} catch (Exception e) {
e.printStackTrace();
Logger.w(TAG, "CacheUtility has not setting or error setting");
}
}
return mHttpUtility;
}
private String toJson(Object o) {
if (o == null)
return "null";
return JSON.toJSONString(o);
// return mGson.toJson(o);
}
/**
* 设置http相关参数
*
* @return
*/
abstract protected HttpConfig configHttpConfig();
/**
* 配置网络交互
*
* @return
*/
protected HttpUtility configHttpUtility() {
// 取配置的http
try {
if(!TextUtils.isEmpty(SettingUtility.getStringSetting("http")))
return (HttpUtility) Class.forName(SettingUtility.getStringSetting("http")).newInstance();
} catch (Exception e) {
}
return new DefHttpUtility();
}
private HttpConfig cloneHttpConfig(HttpConfig config, Setting actionSetting) {
try {
HttpConfig mConfig = config;
if (actionSetting != null && actionSetting.getExtras().containsKey(Consts.Setting.BASE_URL))
mConfig.baseUrl = actionSetting.getExtras().get(Consts.Setting.BASE_URL).getValue().toString();
return mConfig;
} catch (Exception e) {
}
return config;
}
protected String getPageCount(Setting setting) {
return SettingUtil.getSettingValue(setting, "page_count");
}
protected HttpConfig getHttpConfig() {
return configHttpConfig();
}
public void putToCache(Setting setting, Params params, Object data, ICacheUtility cacheUtility) {
if (data instanceof IResult) {
IResult iResult = (IResult) data;
if (!iResult.isCache())
new PutCacheTask(setting, params, data, cacheUtility).execute();
}
else {
new PutCacheTask(setting, params, data, cacheUtility).execute();
}
}
protected CacheMode getCacheMode() {
return mCacheMode;
}
protected void setCacheMode(CacheMode cacheMode) {
this.mCacheMode = cacheMode;
}
class PutCacheTask extends WorkTask<Void, Void, Void> {
private Setting setting;
private Params params;
private Object o;
private ICacheUtility cacheUtility;
PutCacheTask(Setting setting, Params params, Object o, ICacheUtility cacheUtility) {
this.setting = setting;
this.params = params;
this.o = o;
this.cacheUtility = cacheUtility;
}
@Override
public Void workInBackground(Void... p) throws TaskException {
cacheUtility.addCacheData(setting, params, o);
return null;
}
}
}