com.feedhenry.sdk.sync.FHSyncClient Maven / Gradle / Ivy
/**
* Copyright Red Hat, Inc, and individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.feedhenry.sdk.sync;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;
import com.feedhenry.sdk.FH;
import com.feedhenry.sdk.FHActCallback;
import com.feedhenry.sdk.api.FHActRequest;
import com.feedhenry.sdk.exceptions.DataSetNotFound;
import com.feedhenry.sdk.exceptions.FHNotReadyException;
import com.feedhenry.sdk.utils.FHLog;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.json.fh.JSONObject;
/**
* The sync client is part of the FeedHenry data sync framework. It provides a
* mechanism to manage bi-direction data synchronization. For more details,
* please check
* data sync
* framework docs.
*/
public class FHSyncClient {
private static FHSyncClient mInstance;
protected static final String LOG_TAG = "com.feedhenry.sdk.sync.FHSyncClient";
private final Handler mHandler;
private Context mContext;
private Map mDataSets = new HashMap();
private FHSyncConfig mConfig = new FHSyncConfig();
private FHSyncListener mSyncListener = null;
private FHSyncNotificationHandler mNotificationHandler;
private boolean mInitialised = false;
private MonitorTask mMonitorTask = null;
/**
* Gets the singleton instance of the sync client.
*
* @return the sync client instance
*/
public static FHSyncClient getInstance() {
if (null == mInstance) {
mInstance = new FHSyncClient();
}
return mInstance;
}
public FHSyncClient() {
HandlerThread thread = new HandlerThread("FHSyncClient");
thread.start();
mHandler = new Handler(thread.getLooper());
}
/**
* Initializes the sync client. Should be called every time an app/activity
* starts.
*
* @param pContext The app context
* @param pConfig The sync configuration
* @param pListener The sync listener
*/
public void init(Context pContext, FHSyncConfig pConfig, FHSyncListener pListener) {
mContext = pContext.getApplicationContext();
mConfig = pConfig;
mSyncListener = pListener;
initHandlers();
mInitialised = true;
if (null == mMonitorTask) {
HandlerThread thread = new HandlerThread("monitor task");
thread.start();
Handler handler = new Handler(thread.getLooper());
mMonitorTask = new MonitorTask();
handler.post(mMonitorTask);
}
}
/**
* Initializes the notification handlers.
*/
private void initHandlers() {
if (null != Looper.myLooper()) {
mNotificationHandler = new FHSyncNotificationHandler(this.mSyncListener);
} else {
HandlerThread ht = new HandlerThread("FHSyncClientNotificationHanlder");
mNotificationHandler = new FHSyncNotificationHandler(ht.getLooper(), this.mSyncListener);
ht.start();
}
}
/**
* Re-sets the sync listener.
*
* @param pListener the new sync listener
*/
public void setListener(FHSyncListener pListener) {
mSyncListener = pListener;
if (null != mNotificationHandler) {
mNotificationHandler.setSyncListener(mSyncListener);
}
}
/**
* Uses the sync client to manage a dataset.
*
* @param pDataId The id of the dataset.
* @param pConfig The sync configuration for the dataset. If not specified,
* the sync configuration passed in the initDev method will be used
* @param pQueryParams Query parameters for the dataset
* @throws IllegalStateException thrown if FHSyncClient isn't initialised.
*/
public void manage(String pDataId, FHSyncConfig pConfig, JSONObject pQueryParams) {
manage(pDataId, pConfig, pQueryParams, new JSONObject());
}
/**
* Uses the sync client to manage a dataset.
*
* @param pDataId The id of the dataset.
* @param pConfig The sync configuration for the dataset. If not specified,
* the sync configuration passed in the initDev method will be used
* @param pQueryParams Query parameters for the dataset
* @param pMetaData Meta for the dataset
* @throws IllegalStateException thrown if FHSyncClient isn't initialised.
*/
public void manage(String pDataId, FHSyncConfig pConfig, JSONObject pQueryParams, JSONObject pMetaData) {
if (!mInitialised) {
throw new IllegalStateException("FHSyncClient isn't initialised. Have you called the initDev function?");
}
FHSyncDataset dataset = mDataSets.get(pDataId);
FHSyncConfig syncConfig = mConfig;
if (null != pConfig) {
syncConfig = pConfig;
}
if (null != dataset) {
dataset.setContext(mContext);
dataset.setNotificationHandler(mNotificationHandler);
} else {
dataset
= new FHSyncDataset(mContext, mNotificationHandler, pDataId, syncConfig, pQueryParams, pMetaData);
mDataSets.put(pDataId, dataset);
dataset.setSyncRunning(false);
dataset.setInitialised(true);
}
dataset.setSyncConfig(syncConfig);
dataset.setSyncPending(true);
dataset.writeToFile();
}
/**
* Causes the sync framework to schedule for immediate execution a sync.
*
* @param pDataId The id of the dataset
*/
public void forceSync(String pDataId) {
FHSyncDataset dataset = mDataSets.get(pDataId);
if (null != dataset) {
dataset.setSyncPending(true);
}
}
/**
* Lists all the data in the dataset with pDataId.
*
* @param pDataId The id of the dataset
* @return all data records. Each record contains a key "uid" with the id
* value and a key "data" with the JSON data.
*/
public JSONObject list(String pDataId) {
FHSyncDataset dataset = mDataSets.get(pDataId);
JSONObject data = null;
if (null != dataset) {
data = dataset.listData();
}
return data;
}
/**
* Reads a data record with pUID in dataset with pDataId.
*
* @param pDataId the id of the dataset
* @param pUID the id of the data record
* @return the data record. Each record contains a key "uid" with the id
* value and a key "data" with the JSON data.
*/
public JSONObject read(String pDataId, String pUID) {
FHSyncDataset dataset = mDataSets.get(pDataId);
JSONObject data = null;
if (null != dataset) {
data = dataset.readData(pUID);
}
return data;
}
/**
* Creates a new data record in dataset with pDataId.
*
* @param pDataId the id of the dataset
* @param pData the actual data
* @return the created data record. Each record contains a key "uid" with
* the id value and a key "data" with the JSON data.
* @throws DataSetNotFound if the dataId is not known
*/
public JSONObject create(String pDataId, JSONObject pData) throws DataSetNotFound {
FHSyncDataset dataset = mDataSets.get(pDataId);
if (null != dataset) {
return dataset.createData(pData);
} else {
throw new DataSetNotFound("Unknown dataId : " + pDataId);
}
}
/**
* Updates an existing data record in dataset with pDataId.
*
* @param pDataId the id of the dataset
* @param pUID the id of the data record
* @param pData the new content of the data record
* @return the updated data record. Each record contains a key "uid" with
* the id value and a key "data" with the JSON data.
* @throws DataSetNotFound if the dataId is not known
*/
public JSONObject update(String pDataId, String pUID, JSONObject pData) throws DataSetNotFound {
FHSyncDataset dataset = mDataSets.get(pDataId);
if (null != dataset) {
return dataset.updateData(pUID, pData);
} else {
throw new DataSetNotFound("Unknown dataId : " + pDataId);
}
}
/**
* Deletes a data record in the dataset with pDataId.
*
* @param pDataId the id of the dataset
* @param pUID the id of the data record
* @return the deleted data record. Each record contains a key "uid" with
* the id value and a key "data" with the JSON data.
* @throws DataSetNotFound if the dataId is not known
*/
public JSONObject delete(String pDataId, String pUID) throws DataSetNotFound {
FHSyncDataset dataset = mDataSets.get(pDataId);
if (null != dataset) {
return dataset.deleteData(pUID);
} else {
throw new DataSetNotFound("Unknown dataId : " + pDataId);
}
}
/**
* Lists sync collisions in dataset with id pDataId.
*
* @param pDataId the id of the dataset
* @param pCallback the callback function
* @throws FHNotReadyException if FH is not initialized.
*
*/
public void listCollisions(String pDataId, FHActCallback pCallback) throws FHNotReadyException {
JSONObject params = new JSONObject();
params.put("fn", "listCollisions");
FHActRequest request = FH.buildActRequest(pDataId, params);
request.executeAsync(pCallback);
}
/**
* Removes a sync collision record in the dataset with id pDataId.
*
* @param pDataId the id of the dataset
* @param pCollisionHash the hash value of the collision record
* @param pCallback the callback function
* @throws FHNotReadyException thrown if FH is not initialized.
*/
public void removeCollision(String pDataId, String pCollisionHash, FHActCallback pCallback) throws FHNotReadyException {
JSONObject params = new JSONObject();
params.put("fn", "removeCollision");
params.put("hash", pCollisionHash);
FHActRequest request = FH.buildActRequest(pDataId, params);
request.executeAsync(pCallback);
}
/**
* This method will begin synchronization. It should be called in the
* {@link Activity#onResume()} block.
*
* @param listener the listener to. If null the current listener will be
* used.
*
*/
public void resumeSync(FHSyncListener listener) {
if (listener != null) {
this.mSyncListener = listener;
}
for (FHSyncDataset dataSet : mDataSets.values()) {
dataSet.stopSync(false);
}
}
/**
* This method will pause synchronization. It should be called in the
* {@link Activity#onPause()} block.
*/
public void pauseSync() {
for (FHSyncDataset dataSet : mDataSets.values()) {
dataSet.stopSync(true);
}
this.mSyncListener = null;
}
/**
* Stops the sync process for dataset with id pDataId.
*
* @param pDataId the id of the dataset
*/
public void stop(String pDataId) {
FHSyncDataset dataset = mDataSets.get(pDataId);
if (null != dataset) {
dataset.stopSync(true);
}
}
/**
* Stops all sync processes for all the datasets managed by the sync client.
*/
public void destroy() {
if (mInitialised) {
if (null != mMonitorTask) {
mMonitorTask.stopRunning();
}
for (String key : mDataSets.keySet()) {
stop(key);
}
mSyncListener = null;
mNotificationHandler = null;
mDataSets = new HashMap();
mInitialised = false;
}
}
private class MonitorTask implements Runnable {
private boolean mKeepRunning = true;
public void stopRunning() {
mKeepRunning = false;
Thread.currentThread().interrupt();
}
private void checkDatasets() {
if (null != mDataSets) {
for (Map.Entry entry : mDataSets.entrySet()) {
final FHSyncDataset dataset = entry.getValue();
boolean syncRunning = dataset.isSyncRunning();
if (!syncRunning && !dataset.isStopSync()) {
// sync isn't running for dataId at the moment, check if needs to start it
Date lastSyncStart = dataset.getSyncStart();
Date lastSyncEnd = dataset.getSyncEnd();
if (null == lastSyncStart) {
dataset.setSyncPending(true);
} else if (null != lastSyncEnd) {
long interval = new Date().getTime() - lastSyncEnd.getTime();
if (interval > dataset.getSyncConfig().getSyncFrequency() * 1000) {
Log.d(LOG_TAG, "Should start sync!!");
dataset.setSyncPending(true);
}
}
if (dataset.isSyncPending()) {
mHandler.post(
new Runnable() {
@Override
public void run() {
dataset.startSyncLoop();
}
});
}
}
}
}
}
@Override
public void run() {
while (mKeepRunning && !Thread.currentThread().isInterrupted()) {
checkDatasets();
try {
Thread.sleep(1000);
} catch (Exception e) {
FHLog.e(LOG_TAG, "MonitorTask thread is interrupted", e);
Thread.currentThread().interrupt();
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy