Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.avos.avoscloud.PaasClient Maven / Gradle / Ivy
package com.avos.avoscloud;
import java.io.File;
import java.io.IOException;
import java.net.CookieHandler;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
import com.alibaba.fastjson.JSON;
import com.avos.avoscloud.internal.InternalCache;
import com.avos.avoscloud.internal.InternalConfigurationController;
import com.avos.avoscloud.okhttp.Call;
import com.avos.avoscloud.okhttp.Interceptor;
import com.avos.avoscloud.okhttp.MediaType;
import com.avos.avoscloud.okhttp.OkHttpClient;
import com.avos.avoscloud.okhttp.Request;
import com.avos.avoscloud.okhttp.RequestBody;
import com.avos.avoscloud.okhttp.Response;
import com.avos.avoscloud.okhttp.ResponseBody;
import com.avos.avoscloud.okhttp.internal.framed.Header;
import com.avos.avoscloud.okio.Buffer;
import com.avos.avoscloud.okio.BufferedSource;
import com.avos.avoscloud.okio.ForwardingSource;
import com.avos.avoscloud.okio.Okio;
import com.avos.avoscloud.okio.Source;
public class PaasClient {
private static final CookieHandler cookieHandler = new CookieHandler() {
@Override
public Map> get(URI uri, Map> map) throws IOException {
return Collections.emptyMap();
}
@Override
public void put(URI uri, Map> map) throws IOException {
}
};
private final String apiVersion;
protected static String sessionTokenField = "X-LC-Session";
private final AVOSServices service;
private boolean isProduction = true;
private static final String defaultEncoding = "UTF-8";
public static final String defaultContentType = "application/json";
public static final String DEFAULT_FAIL_STRING = "request failed!!!";
private AVACL defaultACL;
private volatile AVHttpClient httpClient;
private static boolean lastModifyEnabled = false;
private static String REQUEST_STATIS_HEADER = "X-Android-RS";
static Map serviceClientMap = new HashMap();
static Map internalObjectsForEventuallySave = Collections
.synchronizedMap(new HashMap());
private static Map lastModify = Collections
.synchronizedMap(new WeakHashMap());
void setProduction(boolean production) {
isProduction = production;
}
protected static PaasClient sharedInstance(AVOSServices service) {
PaasClient instance = serviceClientMap.get(service);
if (instance == null) {
instance = new PaasClient(service);
serviceClientMap.put(service, instance);
}
return instance;
}
public static PaasClient storageInstance() {
return sharedInstance(AVOSServices.API);
}
public static PaasClient cloudInstance() {
return sharedInstance(AVOSServices.ENGINE);
}
public static PaasClient statistisInstance() {
return sharedInstance(AVOSServices.STATS);
}
AVACL getDefaultACL() {
return defaultACL;
}
void setDefaultACL(AVACL acl) {
defaultACL = acl;
}
public Map userHeaderMap() {
AVUser user = AVUser.getCurrentUser();
if (user != null) {
return user.headerMap();
}
return null;
}
private PaasClient(AVOSServices service) {
apiVersion = "1.1";
this.service = service;
}
protected void updateHeaders(Request.Builder builder, Map header,
boolean needRequestStatistic) throws AVException {
if (!InternalConfigurationController.globalInstance().getAppConfiguration().isConfigured()) {
throw new AVException(AVException.NOT_INITIALIZED,
"You must call AVOSCloud.initialize before using the AVOSCloud library");
}
// if the field isnt exist, the server will assume it's true
builder.header("X-LC-Prod", isProduction ? "1" : "0");
AVUser currAVUser = AVUser.getCurrentUser();
builder.header(sessionTokenField,
(currAVUser != null && currAVUser.getSessionToken() != null) ? currAVUser.getSessionToken()
: "");
builder.header("Accept", defaultContentType);
builder.header("Content-Type", defaultContentType);
builder.header("User-Agent", InternalConfigurationController.globalInstance()
.getClientConfiguration().getUserAgent());
builder.header("X-LC-Sign", InternalConfigurationController.globalInstance()
.getInternalRequestSign().requestSign());
for (Map.Entry entry : InternalConfigurationController.globalInstance()
.getAppConfiguration().getRequestHeaders().entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
if (header != null) {
for (Map.Entry entry : header.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
}
if (needRequestStatistic) {
builder.header(REQUEST_STATIS_HEADER, "1");
}
}
public synchronized AVHttpClient clientInstance() {
if (httpClient == null) {
httpClient = new AVHttpClient();
}
httpClient.setConnectTimeout(InternalConfigurationController.globalInstance()
.getClientConfiguration().getNetworkTimeoutInMills(), TimeUnit.MILLISECONDS);
return httpClient;
}
public String buildUrl(final String path) {
return String.format("%s/%s/%s", InternalConfigurationController.globalInstance()
.getAppConfiguration().getServerUrl(service), apiVersion, path);
}
public String buildUrl(final String path, AVRequestParams params) {
String endPoint = buildUrl(path);
if (params == null || params.isEmpty()) {
return endPoint;
} else {
return params.getWholeUrl(endPoint);
}
}
private String batchUrl() {
return String.format("%s/%s/batch", InternalConfigurationController.globalInstance()
.getAppConfiguration().getServerUrl(service), apiVersion);
}
private String batchSaveRelativeUrl() {
return "batch/save";
}
private AsyncHttpResponseHandler createGetHandler(GenericObjectCallback callback,
AVQuery.CachePolicy policy, String absoluteURLString) {
AsyncHttpResponseHandler handler =
new GetHttpResponseHandler(callback, policy, absoluteURLString);
return handler;
}
private AsyncHttpResponseHandler createPostHandler(GenericObjectCallback callback) {
AsyncHttpResponseHandler handler = new PostHttpResponseHandler(callback);
return handler;
}
public String getApiVersion() {
return apiVersion;
}
public String getObject(final String relativePath, final AVRequestParams parameters,
final boolean sync, final Map header, final GenericObjectCallback callback,
final AVQuery.CachePolicy policy, final long maxAgeInMilliseconds) {
final String absoluteURLString = buildUrl(relativePath, parameters);
final String absolutURLString = generateQueryPath(relativePath, parameters);
final String lastModifyTime = getLastModify(absolutURLString);
switch (policy) {
default:
case IGNORE_CACHE:
getObject(relativePath, parameters, sync, header, callback, policy);
break;
case CACHE_ONLY:
InternalConfigurationController.globalInstance().getCache()
.get(absolutURLString, maxAgeInMilliseconds, lastModifyTime, callback);
break;
case NETWORK_ONLY:
getObject(relativePath, parameters, sync, header, callback, policy);
break;
case CACHE_ELSE_NETWORK:
InternalConfigurationController
.globalInstance()
.getCache()
.get(absolutURLString, maxAgeInMilliseconds, lastModifyTime,
new GenericObjectCallback() {
@Override
public void onSuccess(String content, AVException e) {
callback.onSuccess(content, e);
}
@Override
public void onFailure(Throwable error, String content) {
getObject(relativePath, parameters, sync, header, callback, policy);
}
});
break;
case NETWORK_ELSE_CACHE:
getObject(relativePath, parameters, sync, header, new GenericObjectCallback() {
@Override
public void onSuccess(String content, AVException e) {
callback.onSuccess(content, e);
}
@Override
public void onFailure(Throwable error, String content) {
InternalCache cacheManager =
InternalConfigurationController.globalInstance().getCache();
if (cacheManager.hasValidCache(absolutURLString, lastModifyTime, maxAgeInMilliseconds)) {
cacheManager.get(absolutURLString, maxAgeInMilliseconds, lastModifyTime, callback);
} else {
callback.onFailure(error, content);
}
}
}, policy);
break;
case CACHE_THEN_NETWORK:
InternalConfigurationController
.globalInstance()
.getCache()
.get(absolutURLString, maxAgeInMilliseconds, lastModifyTime,
new GenericObjectCallback() {
@Override
public void onSuccess(String content, AVException e) {
callback.onSuccess(content, e);
getObject(relativePath, parameters, sync, header, callback, policy);
}
@Override
public void onFailure(Throwable error, String content) {
callback.onFailure(error, content);
getObject(relativePath, parameters, sync, header, callback, policy);
}
});
break;
}
return absoluteURLString;
}
String generateQueryPath(final String relativePath, final AVRequestParams parameters) {
return buildUrl(relativePath, parameters);
}
public void getObject(final String relativePath, AVRequestParams parameters, boolean sync,
Map inputHeader, GenericObjectCallback callback, AVQuery.CachePolicy policy) {
getObject(relativePath, parameters, sync, inputHeader, callback, policy,
(!policy.equals(AVQuery.CachePolicy.CACHE_ONLY)) && isLastModifyEnabled());
}
public void getObject(final String relativePath, final AVRequestParams parameters,
final boolean sync, final Map inputHeader, GenericObjectCallback callback,
final AVQuery.CachePolicy policy, final boolean fetchRetry) {
Map myHeader = inputHeader;
if (inputHeader == null) {
myHeader = new HashMap();
}
updateHeaderForPath(relativePath, parameters, myHeader);
String url = buildUrl(relativePath, parameters);
AsyncHttpResponseHandler handler = createGetHandler(callback, policy, url);
if (InternalConfigurationController.globalInstance().getInternalLogger().isDebugEnabled()) {
dumpHttpGetRequest(buildUrl(relativePath),
parameters == null ? null : parameters.getDumpQueryString());
}
AVHttpClient client = clientInstance();
Request.Builder builder = new Request.Builder();
builder.url(url).get();
try {
updateHeaders(builder, myHeader, callback != null && callback.isRequestStatisticNeed());
} catch (AVException e) {
processException(e, callback);
}
client.execute(builder.build(), sync, handler);
}
public void getObject(final String relativePath, AVRequestParams parameters, boolean sync,
Map header, GenericObjectCallback callback) {
getObject(relativePath, parameters, sync, header, callback, AVQuery.CachePolicy.IGNORE_CACHE);
}
public void putObject(final String relativePath, String object, boolean sync,
Map header, GenericObjectCallback callback, String objectId,
String _internalId) {
putObject(relativePath, object, sync, false, header, callback, objectId, _internalId);
}
public void putObject(final String relativePath, String object, boolean sync,
boolean isEventually, Map header, GenericObjectCallback callback,
String objectId, String _internalId) {
try {
if (isEventually) {
File archivedFile = archiveRequest("put", relativePath, object, objectId, _internalId);
handleArchivedRequest(archivedFile, sync, callback);
} else {
String url = buildUrl(relativePath);
AsyncHttpResponseHandler handler = createPostHandler(callback);
if (InternalConfigurationController.globalInstance().getInternalLogger().isDebugEnabled()) {
dumpHttpPutRequest(header, url, object);
}
AVHttpClient client = clientInstance();
Request.Builder builder = new Request.Builder();
builder.url(url).put(RequestBody.create(AVHttpClient.JSON, object));
updateHeaders(builder, header, callback != null && callback.isRequestStatisticNeed());
client.execute(builder.build(), sync, handler);
}
} catch (Exception exception) {
processException(exception, callback);
}
}
private void processException(Exception e, GenericObjectCallback cb) {
if (cb != null) {
cb.onFailure(e, null);
}
}
// path=/1/classes/Parent/a1QCssTp7r
Map batchItemMap(String method, String path, Object body, Map params) {
// String myPath = String.format("/%s/%s",
// PaasClient.sharedInstance().apiVersion, path);
Map result = new HashMap();
result.put("method", method);
result.put("path", path);
result.put("body", body);
if (params != null) {
result.put("params", params);
}
return result;
}
Map batchItemMap(String method, String path, Object body) {
return this.batchItemMap(method, path, body, null);
}
@Deprecated
List assembleBatchOpsList(List itemList, String path) {
List list = new ArrayList();
for (Object object : itemList) {
Map opDict = batchItemMap("PUT", path, object);
list.add(opDict);
}
return list;
}
private Map batchRequest(List list) {
Map requests = new HashMap();
requests.put("requests", list);
return requests;
}
// only called @sendPendingOps
public void postBatchObject(List parameters, boolean sync, Map header,
GenericObjectCallback callback) {
try {
String url = batchUrl();
Map requests = batchRequest(parameters);
String json = JSON.toJSONString(requests);
if (InternalConfigurationController.globalInstance().getInternalLogger().isDebugEnabled()) {
dumpHttpPostRequest(header, url, json);
}
AsyncHttpResponseHandler handler = createPostHandler(callback);
AVHttpClient client = clientInstance();
Request.Builder builder = new Request.Builder();
builder.url(url).post(RequestBody.create(AVHttpClient.JSON, json));
updateHeaders(builder, header, callback != null && callback.isRequestStatisticNeed());
client.execute(builder.build(), sync, handler);
} catch (Exception exception) {
processException(exception, callback);
}
}
public void postBatchSave(final List list, final boolean sync, final boolean isEventually,
final Map header, final GenericObjectCallback callback,
final String objectId, final String _internalId) {
try {
Map params = new HashMap();
params.put("requests", list);
String paramString = AVUtils.jsonStringFromMapWithNull(params);
if (isEventually) {
File archivedFile =
archiveRequest("post", batchSaveRelativeUrl(), paramString, objectId, _internalId);
handleArchivedRequest(archivedFile, sync, callback);
} else {
String url = buildUrl(batchSaveRelativeUrl());
if (InternalConfigurationController.globalInstance().getInternalLogger().isDebugEnabled()) {
dumpHttpPostRequest(header, url, paramString);
}
AsyncHttpResponseHandler handler = createPostHandler(callback);
AVHttpClient client = clientInstance();
Request.Builder builder = new Request.Builder();
updateHeaders(builder, header, callback != null && callback.isRequestStatisticNeed());
builder.url(url).post(RequestBody.create(AVHttpClient.JSON, paramString));
client.execute(builder.build(), sync, handler);
}
} catch (Exception exception) {
processException(exception, callback);
}
}
public void postObject(final String relativePath, String object, boolean sync,
GenericObjectCallback callback) {
postObject(relativePath, object, sync, false, callback, null, null);
}
public void postObject(final String relativePath, String object, boolean sync,
boolean isEventually, GenericObjectCallback callback, String objectId, String _internalId) {
try {
if (isEventually) {
File archivedFile = archiveRequest("post", relativePath, object, objectId, _internalId);
handleArchivedRequest(archivedFile, sync, callback);
} else {
String url = buildUrl(relativePath);
if (InternalConfigurationController.globalInstance().getInternalLogger().isDebugEnabled()) {
dumpHttpPostRequest(null, url, object);
}
AsyncHttpResponseHandler handler = createPostHandler(callback);
AVHttpClient client = clientInstance();
Request.Builder builder = new Request.Builder();
updateHeaders(builder, null, callback != null && callback.isRequestStatisticNeed());
builder.url(url).post(RequestBody.create(AVHttpClient.JSON, object));
client.execute(builder.build(), sync, handler);
}
} catch (Exception exception) {
processException(exception, callback);
}
}
public void deleteObject(final String relativePath, boolean sync, GenericObjectCallback callback,
String objectId, String _internalId) {
Map emptymap = Collections.emptyMap();
deleteObject(relativePath, emptymap, sync, false, callback, objectId,
_internalId);
}
public void deleteObject(final String relativePath, Map object,
boolean sync,
boolean isEventually,
GenericObjectCallback callback, String objectId, String _internalId) {
try {
if (isEventually) {
File archivedFile = archiveRequest("delete", relativePath, null, objectId, _internalId);
handleArchivedRequest(archivedFile, sync, callback);
} else {
String url = buildUrl(relativePath);
String body = AVUtils.jsonStringFromMapWithNull(object);
if (InternalConfigurationController.globalInstance().getInternalLogger().isDebugEnabled()) {
dumpHttpDeleteRequest(null, url, body);
}
AsyncHttpResponseHandler handler = createPostHandler(callback);
AVHttpClient client = clientInstance();
Request.Builder builder = new Request.Builder();
updateHeaders(builder, null, callback != null && callback.isRequestStatisticNeed());
builder.url(url)
.delete(RequestBody.create(AVHttpClient.JSON, body));
client.execute(builder.build(), sync, handler);
}
} catch (Exception exception) {
processException(exception, callback);
}
}
// ================================================================================
// Archive and handle request
// ================================================================================
/*
* type for archive: 1. post 2. delete
*/
private File archiveRequest(String method, String relativePath, String paramString,
String objectId, String _internalId) {
File theArchivedFile =
new File(InternalConfigurationController.globalInstance().getInternalPersistence()
.getCommandCacheDir(), AVUtils.getArchiveRequestFileName(objectId, _internalId, method,
relativePath, paramString));
Map fileMap = new HashMap(3);
fileMap.put("method", method);
fileMap.put("relativePath", relativePath);
fileMap.put("paramString", paramString);
fileMap.put("objectId", objectId);
fileMap.put("_internalId", _internalId);
InternalConfigurationController.globalInstance().getInternalPersistence()
.saveContentToFile(AVUtils.toJSON(fileMap), theArchivedFile);
if (InternalConfigurationController.globalInstance().getInternalLogger().isDebugEnabled()) {
LogUtil.log.d(AVUtils.restfulServerData(fileMap) + "\n" + "did save to "
+ theArchivedFile.getAbsolutePath());
}
return theArchivedFile;
}
private void handleArchivedRequest(File archivedFile, boolean sync) {
handleArchivedRequest(archivedFile, sync, null);
}
private void handleArchivedRequest(final File archivedFile, boolean sync,
final GenericObjectCallback callback) {
try {
String archivedFileContent =
InternalConfigurationController.globalInstance().getInternalPersistence()
.readContentFromFile(archivedFile);
Map fileMap = null;
fileMap = AVUtils.getFromJSON(archivedFileContent, Map.class);
if (fileMap != null && !fileMap.isEmpty()) {
String method = fileMap.get("method");
String relativePath = fileMap.get("relativePath");
String paramString = fileMap.get("paramString");
String objectId = fileMap.get("objectId");
String _internalId = fileMap.get("_internalId");
GenericObjectCallback newCallback = new GenericObjectCallback() {
@Override
public void onSuccess(String content, AVException e) {
if (callback != null) {
callback.onSuccess(content, e);
}
try {
Map objectMap = AVUtils.getFromJSON(content, Map.class);
for (String _internalId : objectMap.keySet()) {
if (internalObjectsForEventuallySave.get(_internalId) != null) {
internalObjectsForEventuallySave.get(_internalId).getValue()
.copyFromMap(objectMap);
unregisterEvtuallyObject(internalObjectsForEventuallySave.get(_internalId)
.getValue());
}
}
} catch (Exception e1) {
LogUtil.avlog.e("parse exception during archive request" + e.getMessage());
}
InternalConfigurationController.globalInstance().getInternalPersistence()
.deleteFile(archivedFile);
}
@Override
public void onFailure(Throwable error, String content) {
// handle retry
if (callback != null)
callback.onFailure(error, content);
}
};
if (method == null) {
newCallback.onFailure(new AVRuntimeException("Null method."), null);
}
if ("post".equalsIgnoreCase(method)) {
postObject(relativePath, paramString, sync, newCallback);
} else if ("put".equalsIgnoreCase(method)) {
putObject(relativePath, paramString, sync, null, newCallback, objectId, _internalId);
} else if ("delete".equalsIgnoreCase(method)) {
deleteObject(relativePath, sync, newCallback, objectId, _internalId);
}
}
} catch (Exception e) {
return;
}
}
public void handleAllArchivedRequest() {
handleAllArchivedRequest(false);
}
protected void handleAllArchivedRequest(boolean sync) {
File commandCacheDir =
InternalConfigurationController.globalInstance().getInternalPersistence()
.getCommandCacheDir();
File[] archivedRequests = commandCacheDir.listFiles();
if (archivedRequests != null && archivedRequests.length > 0) {
Arrays.sort(archivedRequests, fileModifiedDateComparator);
for (File file : archivedRequests) {
if (file.isFile()) {
handleArchivedRequest(file, sync);
} else if (InternalConfigurationController.globalInstance().getInternalLogger()
.showInternalDebugLog()) {
LogUtil.avlog.e(file.getAbsolutePath() + " is a dir");
}
}
}
}
// ================================================================================
// For Debug
// ================================================================================
public void dumpHttpGetRequest(String path, String parameters) {
String string = "";
if (parameters != null) {
string =
String.format("curl -X GET %s -G --data-urlencode \'%s\' %s",
InternalConfigurationController.globalInstance().getAppConfiguration().dumpRequestHeaders(),
parameters, path);
} else {
string = String.format("curl -X GET %s %s", InternalConfigurationController.globalInstance()
.getAppConfiguration().dumpRequestHeaders(), path);
}
LogUtil.avlog.d(string);
}
private String headerString(Map header) {
String string =
InternalConfigurationController.globalInstance().getAppConfiguration().dumpRequestHeaders();
StringBuilder sb = new StringBuilder(string);
if (header != null) {
for (Map.Entry entry : header.entrySet()) {
String item = String.format(" -H \"%s: %s\" ", entry.getKey(), entry.getValue());
sb.append(item);
}
}
sb.append(" -H \"Content-Type: application/json\" ");
return sb.toString();
}
public void dumpHttpPutRequest(Map header, String path, String object) {
String string =
String.format("curl -X PUT %s -d \' %s \' %s", headerString(header), object, path);
LogUtil.avlog.d(string);
}
public void dumpHttpPostRequest(Map header, String path, String object) {
String string =
String.format("curl -X POST %s -d \'%s\' %s", headerString(header), object, path);
LogUtil.avlog.d(string);
}
public void dumpHttpDeleteRequest(Map header, String path, String object) {
String string =
String.format("curl -X DELETE %s -d \'%s\' %s", headerString(header), object, path);
LogUtil.avlog.d(string);
}
public void updateHeaderForPath(final String relativePath, AVRequestParams parameters,
final Map header) {
// if disabled, don't add modify to header so server side will
// return raw data instead of flag only.
if (PaasClient.isLastModifyEnabled() && null != header && !AVUtils.isBlankString(relativePath)) {
final String absoluteURLString = generateQueryPath(relativePath, parameters);
final String modify = getLastModify(absoluteURLString);
// double check local cache
boolean exist =
InternalConfigurationController.globalInstance().getCache()
.hasCache(absoluteURLString, modify);
if (modify != null && exist) {
header.put("If-Modified-Since", modify);
}
}
}
public static String getLastModify(final String absolutURLString) {
if (!PaasClient.isLastModifyEnabled()) {
return null;
}
return lastModify.get(absolutURLString);
}
public static boolean isLastModifyEnabled() {
return lastModifyEnabled;
}
public static void setLastModifyEnabled(boolean e) {
lastModifyEnabled = e;
}
public static void clearLastModifyCache() {
// also clear cache files
Iterator it = lastModify.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry) it.next();
InternalConfigurationController.globalInstance().getCache()
.remove((String) pairs.getKey(), (String) pairs.getValue());
}
lastModify.clear();
}
static public String lastModifyFromHeaders(Header[] headers) {
for (Header h : headers) {
if ("Last-Modified".equalsIgnoreCase(h.name.utf8())) {
return h.value.utf8();
}
}
return null;
}
public static boolean updateLastModify(final String absolutURLString, final String ts) {
if (!isLastModifyEnabled()) {
return false;
}
if (!AVUtils.isBlankString(ts)) {
lastModify.put(absolutURLString, ts);
return true;
}
return false;
}
public static void removeLastModifyForUrl(final String absolutURLString) {
lastModify.remove(absolutURLString);
}
protected static void registerEventuallyObject(AVObject object) {
if (object != null) {
synchronized (object) {
AVObjectReferenceCount counter = internalObjectsForEventuallySave.get(object.internalId());
if (counter != null) {
counter.increment();
} else {
counter = new AVObjectReferenceCount(object);
internalObjectsForEventuallySave.put(object.internalId(), counter);
}
}
}
}
protected static void unregisterEvtuallyObject(AVObject object) {
if (object != null) {
synchronized (object) {
AVObjectReferenceCount counter =
internalObjectsForEventuallySave.get(object.internalId()) == null ? internalObjectsForEventuallySave
.get(object.internalId()) : internalObjectsForEventuallySave.get(object.getUuid());
if (counter != null) {
if (counter.desc() <= 0) {
internalObjectsForEventuallySave.remove(object.internalId());
internalObjectsForEventuallySave.remove(object.getUuid());
}
}
}
}
}
private static Comparator fileModifiedDateComparator = new Comparator() {
@Override
public int compare(File f, File s) {
return (int) (f.lastModified() - s.lastModified());
}
};
public static class AVHttpClient {
OkHttpClient client;
public static final MediaType JSON = MediaType.parse(defaultContentType);
public AVHttpClient() {
client = new OkHttpClient();
client.setCookieHandler(cookieHandler);
client.interceptors().addAll(
InternalConfigurationController.globalInstance().getClientConfiguration()
.getClientInterceptors());
if (AVUtils.isAndroid()) {
client.setDns(DNSAmendNetwork.getInstance());
}
}
public void execute(Request request, boolean sync, ProgressListener progressListener,
final AsyncHttpResponseHandler handler) {
Call call = getProgressCall(request, progressListener);
if (sync) {
try {
Response response = call.execute();
handler.onResponse(response);
} catch (IOException e) {
handler.onFailure(request, e);
}
} else {
call.enqueue(handler);
}
}
public void execute(Request request, boolean sync, final AsyncHttpResponseHandler handler) {
Call call = getCall(request);
if (sync) {
try {
Response response = call.execute();
handler.onResponse(response);
} catch (IOException e) {
handler.onFailure(request, e);
}
} else {
call.enqueue(handler);
}
}
/**
* OkHttpClient newCall 时会调用 client.copyWithDefaults(); 也就是说 Call 中的 client 实际是 copy 出来的,而且
* Interceptor 也会 copy 所以这里通过这种方式获得可能更新进度的 Call 而不影响其他 为了避免多线程下调用 client.newCall 而造成影响,所以加了
* synchronized okhttp 版本为 cn.leancloud.android:okhttp:2.6.0-leancloud
*/
private synchronized Call getProgressCall(Request request, ProgressListener progressListener) {
ProgressInterceptor progressInterceptor = new ProgressInterceptor(progressListener);
client.networkInterceptors().add(progressInterceptor);
Call call = client.newCall(request);
client.networkInterceptors().remove(progressInterceptor);
return call;
}
private synchronized Call getCall(Request request) {
return client.newCall(request);
}
public void setConnectTimeout(long networkTimeout, TimeUnit timeUnit) {
client.setConnectTimeout(networkTimeout, timeUnit);
}
}
public static class ProgressInterceptor implements Interceptor {
private ProgressListener progressListener;
public ProgressInterceptor(ProgressListener progressListener) {
super();
this.progressListener = progressListener;
}
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener)).build();
}
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() throws IOException {
return responseBody.contentLength();
}
@Override
public BufferedSource source() throws IOException {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
public interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
}