Commit 505e9640 authored by vince-bourgmayer's avatar vince-bourgmayer
Browse files

continue to implement operationDoneObject, create an abstract DAO class to be...

continue to implement operationDoneObject, create an abstract DAO class to be extended by concrete DAO class. work hard on local file change détection, and find an unwanted behaviour in method to find change on remote server
parent eb391238
Pipeline #2754 failed with stage
in 22 seconds
android-nc-lib @ b0ff4872
Subproject commit a86f6d38600b74dd697bcd8ad410a93a7c4637f1
Subproject commit b0ff4872a08bd5eab75708c8acf3518abe6fd374
package io.eelo.drive.database;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
public abstract class AbstractDAO {
protected SQLiteDatabase mDB;
protected final DbHelper mHelper;
protected AbstractDAO(Context context){
this.mHelper = new DbHelper(context);
}
/**
* Open Database connexion
* @param writeMod Connexion mod. If set to true, database is open in writable mod, else it is opened in read mod.
* @throws SQLException SqlException
*/
protected void open(Boolean writeMod) throws SQLException {
mDB = (writeMod)? mHelper.getWritableDatabase() : mHelper.getReadableDatabase();
}
/**
* Close Database connexion
*/
protected void close() {
mHelper.close();
}
}
......@@ -16,6 +16,7 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import io.eelo.drive.models.OperationDone;
import io.eelo.drive.models.SyncedFolder;
import io.eelo.drive.models.SyncedFileState;
......@@ -29,7 +30,7 @@ import io.eelo.drive.models.SyncedFileState;
public final class DbHelper extends SQLiteOpenHelper {
final private static String TAG = DbHelper.class.getSimpleName(); //Tag for log
private static final int DATABASE_VERSION = 19; //20/09/2018
private static final int DATABASE_VERSION = 20; //20/09/2018
public static final String DATABASE_NAME = "eelo_drive.db";
/**
......@@ -47,6 +48,7 @@ public final class DbHelper extends SQLiteOpenHelper {
public void onCreate(SQLiteDatabase db) {
db.execSQL(SyncedFolderContract.SQL_CREATE_TABLE_SYNCEDFOLDER);
db.execSQL(SyncedFileStateContract.SQL_CREATE_TABLE_SYNCEDFILESTATE);
db.execSQL(OperationDoneContract.SQL_CREATE_TABLE_OPERATIONDONE);
}
/**
......
package io.eelo.drive.database;
import android.provider.BaseColumns;
public class OperationDoneContract implements BaseColumns {
/** Table structure **/
static final String TABLE_NAME ="operation_done";
static final String TARGET_PATH ="target_path";
static final String SOURCE_PATH ="source_path";
static final String OPERATION_CODE = "operation_code";
static final String RESULT_CODE = "result_code";
static final String IS_SUCCESS = "is_success";
static final String NEW_ETAG = "new_etag";
static final String SQL_CREATE_TABLE_OPERATIONDONE=
"CREATE TABLE "+TABLE_NAME+" ( "
+_ID+" INTEGER PRIMARY KEY, "
+TARGET_PATH+" TEXT, "
+SOURCE_PATH+" TEXT, "
+OPERATION_CODE+" INTEGER, "
+RESULT_CODE+" TEXT, "
+IS_SUCCESS+" INTEGER, "
+ NEW_ETAG +" TEXT, "
+"CONSTRAINT synced_unicity_constraint UNIQUE ("
+TARGET_PATH+", "
+SOURCE_PATH
+"))";
static final String SQL_DELETE_TABLE_OPERATIONDONE = " DROP TABLE IF EXISTS "
+ TABLE_NAME;
}
package io.eelo.drive.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import io.eelo.drive.models.OperationDone;
import static io.eelo.drive.database.OperationDoneContract.IS_SUCCESS;
import static io.eelo.drive.database.OperationDoneContract.NEW_ETAG;
import static io.eelo.drive.database.OperationDoneContract.OPERATION_CODE;
import static io.eelo.drive.database.OperationDoneContract.RESULT_CODE;
import static io.eelo.drive.database.OperationDoneContract.SOURCE_PATH;
import static io.eelo.drive.database.OperationDoneContract.TABLE_NAME;
import static io.eelo.drive.database.OperationDoneContract.TARGET_PATH;
public class OperationDoneDAO extends AbstractDAO {
final private static String TAG = OperationDoneDAO.class.getSimpleName();
private final String[] allColumns = {
OperationDoneContract._ID,
TARGET_PATH,
SOURCE_PATH,
OPERATION_CODE,
RESULT_CODE,
IS_SUCCESS,
NEW_ETAG
};
OperationDoneDAO(Context context){
super(context);
}
/**
* Remove all entry from DB
* @return
*/
public int clearTable(){
return mDB.delete(TABLE_NAME, "1", null);
}
/**
* Get list of OperationDone
* @param selection A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table.
* @param args You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
* @return List of all OperationDone
*/
List<OperationDone> getOperationDoneList(String selection, String[] args) {
List<OperationDone> result = new ArrayList<OperationDone>();
Cursor cursor = mDB.query(TABLE_NAME, allColumns, selection,args, null, null,
null);
cursor.moveToFirst();
while ( !cursor.isAfterLast() ) {
OperationDone operationDone = cursorToOperationDone(cursor);
if(operationDone != null ){
result.add(operationDone);
}
cursor.moveToNext();
}
cursor.close();
return result;
}
/**
* Insert new OperationDone
* @param operationDone element to register
* @return the row ID of the newly inserted row OR -1
*/
long insert(OperationDone operationDone){
return mDB.insertWithOnConflict(TABLE_NAME,
null,
toContentValues(operationDone),
SQLiteDatabase.CONFLICT_IGNORE);
}
/**
* Update a specific OperationDone
* @param operationDone OperationDone to update
* @return Number of row affected
*/
public int update(OperationDone operationDone){
int result = 0;
try{
result = mDB.update(TABLE_NAME,
toContentValues(operationDone),
OperationDoneContract._ID+" = "+ operationDone.getId(),
null);
}catch(Exception e){
Log.e(TAG, e.toString());
}
return result;
}
/**
* Convert a operationDone into a ContentValues object
* @param operationDone syncedFileState to convert
* @return a ContentValues object
*/
private ContentValues toContentValues(OperationDone operationDone){
ContentValues values = new ContentValues();
values.put( TARGET_PATH, operationDone.getTargetPath() );
values.put( SOURCE_PATH, operationDone.getSourcePath() );
values.put( OPERATION_CODE, operationDone.getOperationCode() );
values.put( RESULT_CODE, operationDone.getResultCode() );
values.put( IS_SUCCESS, operationDone.isSuccess() ? 1 : 0 );
values.put( NEW_ETAG, operationDone.getNewEtag() );
return values;
}
/**
* Create SyncedFileState from cursor
* @param cursor Cursor containing data to build SyncedFileState
* @return SyncedFileState instance
*/
private OperationDone cursorToOperationDone(Cursor cursor) {
OperationDone result = new OperationDone(
cursor.getString(1 ),//targetPath
cursor.getString(2 ),//sourcePath
cursor.getInt(3 ),//operationCode
cursor.getString(4 ),//resultCode
(cursor.getInt(5) == 1 ) //is success
);
result.setId( cursor.getInt(0)); //Id
result.setNewEtag(cursor.getString(6)); //Etag
return result;
}
}
......@@ -11,7 +11,6 @@ package io.eelo.drive.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
......@@ -34,11 +33,9 @@ import static io.eelo.drive.database.SyncedFileStateContract.SYNCEDFOLDER_ID;
* @author Vincent Bourgmayer
* Offers Query to CRUD operation for SyncedFIleState Object
*/
class SyncedFileStateDAO {
class SyncedFileStateDAO extends AbstractDAO {
final private static String TAG = SyncedFileStateDAO.class.getSimpleName(); //Tag for log
private SQLiteDatabase mDB;
private final DbHelper mHelper;
/*private final String[] allColumns = { SyncedFileStateContract._ID,
SyncedFileStateContract.FILE_NAME,
SyncedFileStateContract.LOCAL_PATH,
......@@ -51,23 +48,7 @@ class SyncedFileStateDAO {
};*/
SyncedFileStateDAO(Context context){
this.mHelper = new DbHelper(context);
}
/**
* Open Database connexion
* @param writeMod if true, open DB in write mod, else open it in read mod
* @throws SQLException throw an SQL Exception
*/
void open(Boolean writeMod ) throws SQLException {
this.mDB = ( writeMod ) ? mHelper.getWritableDatabase(): mHelper.getReadableDatabase();
}
/**
* Close DB connexion.
*/
void close() {
mHelper.close();
super(context);
}
/**
......
......@@ -11,7 +11,6 @@ package io.eelo.drive.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import java.util.ArrayList;
......@@ -33,10 +32,9 @@ import static io.eelo.drive.database.SyncedFolderContract.TABLE_NAME;
* @author Vincent Bourgmayer
* Source: https://vogella.developpez.com/tutoriels/android/utilisation-base-donnees-sqlite/
*/
class SyncedFolderDAO {
class SyncedFolderDAO extends AbstractDAO {
final private static String TAG = SyncedFolderDAO.class.getSimpleName(); //Tag for log
private SQLiteDatabase mDB;
private final DbHelper mHelper;
private final String[] allColumns = { SyncedFolderContract._ID,
CATEGORIE_LABEL,
LOCAL_PATH,
......@@ -50,23 +48,7 @@ class SyncedFolderDAO {
};
SyncedFolderDAO(Context context){
this.mHelper = new DbHelper(context);
}
/**
* Open Database connexion
* @param writeMod Connexion mod. If set to true, database is open in writable mod, else it is opened in read mod.
* @throws SQLException SqlException
*/
void open(Boolean writeMod) throws SQLException {
mDB = (writeMod)? mHelper.getWritableDatabase() : mHelper.getReadableDatabase();
}
/**
* Close Database connexion
*/
void close() {
mHelper.close();
super(context);
}
/**
......
......@@ -3,18 +3,21 @@ package io.eelo.drive.models;
import com.owncloud.android.lib.resources.files.model.ISynchronizableContent;
public class Operation{
public final static int OPERATION_DOWNLOAD =0;
public final static int OPERATION_UPLOAD = 1;
public final static int OPERATION_REMOVE_REMOTE = 2;
public final static int OPERATION_REMOVE_LOCAL = 3;
public final static int OPERATION_MKCOL =4;
public final static int OPERATION_CREATE_FOLDER_LOCAL = 5;
public final static int OPERATION_DOWNLOAD =0; //opposed = 1;
public final static int OPERATION_UPLOAD = 1; //opposed = 0;
public final static int OPERATION_REMOVE_REMOTE = 2; // opposed = 3;
public final static int OPERATION_REMOVE_LOCAL = 3; //opposed = 2
public final static int OPERATION_MKCOL =4; //opposed = 5;
public final static int OPERATION_CREATE_FOLDER_LOCAL = 5; // opposed = 4;
private ISynchronizableContent file;
private int operationCode;
private int operationCode; //Identify which type of operation it is
private String resultHash;
private boolean isSuccess;
private boolean isMediaType; //define if it's media or settings
public Operation(ISynchronizableContent file, int operationCode){
this.file = file;
......@@ -42,4 +45,28 @@ public class Operation{
return this.resultHash;
}
public void setFile(ISynchronizableContent file) {
this.file = file;
}
public void setOperationCode(int operationCode) {
this.operationCode = operationCode;
}
public void setResultHash(String resultHash) {
this.resultHash = resultHash;
}
public void setSuccess(boolean success) {
isSuccess = success;
}
public boolean isMediaType() {
return isMediaType;
}
public void setMediaType(boolean mediaType) {
isMediaType = mediaType;
}
}
package io.eelo.drive.models;
public class OperationDone {
private int id;
private String targetPath;
private String sourcePath;
private int operationCode;
private String resultCode;
private boolean isSuccess;
private String newEtag; // Upload operation only
public OperationDone(String targetPath, String sourcePath, int operationCode, String resultCode, boolean isSuccess){
this.targetPath = targetPath;
this.sourcePath = sourcePath;
this.operationCode = operationCode;
this.resultCode = resultCode;
this.isSuccess = isSuccess;
}
/**
* Return the new etag after an upload operation
* @return can be null if it's not an upload operation
*/
public String getNewEtag(){
return newEtag;
}
public void setNewEtag(String value){
this.newEtag = value;
}
public String getTargetPath() {
return targetPath;
}
public void setTargetPath(String targetPath) {
this.targetPath = targetPath;
}
public String getSourcePath() {
return sourcePath;
}
public void setSourcePath(String sourcePath) {
this.sourcePath = sourcePath;
}
public int getOperationCode() {
return operationCode;
}
public void setOperationCode(int operationCode) {
this.operationCode = operationCode;
}
public String getResultCode() {
return resultCode;
}
public void setResultCode(String resultCode) {
this.resultCode = resultCode;
}
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean success) {
isSuccess = success;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
......@@ -57,7 +57,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
@Override
public void onCreate() {
Log.i(TAG, "onCreate()");
//Log.i(TAG, "onCreate()");
super.onCreate();
this.existingRemoteFolderCounter = 0;
//JobUtils.scheduleInitializerJob(getApplicationContext());
......@@ -65,7 +65,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
@Override
public int onStartCommand( Intent intent, int flags, int startId ) {
Log.i(TAG, "onStartCommand(...)");
//Log.i(TAG, "onStartCommand(...)");
//Get account
SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE );
......@@ -91,6 +91,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
Log.w(TAG, "Account's name not found. Neither in shared prefs nor in intent's extras");
//JobUtils.stopScheduledJob(getApplicationContext(), JobUtils.InitializerJobId);
stopSelf();
}else{
this.mAccount = CommonUtils.getAccount( accountName, accountType, AccountManager.get(this) );
//Get OwnCloudlient
......@@ -113,7 +114,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
*/
@Override
public void onOCClientReceived(Object result) {
Log.i(TAG, "ocOCClientReceived");
//Log.i(TAG, "ocOCClientReceived");
try {
this.mCloudClient = (OwnCloudClient) result;
......@@ -146,7 +147,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
* @param categories categories indicating which syncedFolder to create
*/
private void getInitialSyncedFolders( List<String> categories){
Log.i(TAG, "getInitialSyncedFolders");
//Log.i(TAG, "getInitialSyncedFolders");
this.mSyncedFolders = new ArrayList<>();
......@@ -209,7 +210,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
* Start to createSyncedFolder in the cloud
*/
private void CreateNextRemoteFolder(){
Log.i(TAG, "createNextRemoteFolder()");
//Log.i(TAG, "createNextRemoteFolder()");
this.restartFolderCreationCounter = 0;
if( this.mSyncedFolders == null || this.mSyncedFolders.isEmpty() ){
......@@ -235,14 +236,14 @@ public class InitializerService extends Service implements OnRemoteOperationList
doLastStep();
}else{
Log.e(TAG, "this.existingRemoteFolderCounter : "+this.existingRemoteFolderCounter+" > this.mSyncedFolders.size() : "+this.mSyncedFolders.size() );
//Log.e(TAG, "this.existingRemoteFolderCounter : "+this.existingRemoteFolderCounter+" > this.mSyncedFolders.size() : "+this.mSyncedFolders.size() );
this.stopSelf();
}
}
@Override
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
Log.i(TAG, "onRemoteOperationFinish()");
//Log.i(TAG, "onRemoteOperationFinish()");
if(operation instanceof CreateInitialRemoteFolderOperation){
if(result.isSuccess() || result.getCode() == RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS){
......@@ -253,7 +254,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
Log.e( TAG, result.getLogMessage() );
if( this.restartFolderCreationCounter < 3) {
Log.w( TAG, " restart operation" );
//Log.w( TAG, " restart operation" );
operation.execute( this.mCloudClient, this, this.mHandler );
this.restartFolderCreationCounter+=1;
......@@ -274,7 +275,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
* Function to check if all remote folder have been created
**/
private void doLastStep(){
Log.i(TAG, "doLastStep()");
//Log.i(TAG, "doLastStep()");
getApplicationContext().getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME,
Context.MODE_PRIVATE )
......
......@@ -28,25 +28,12 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.model.ISynchronizableContent;
import com.owncloud.android.lib.resources.files.model.RemoteFile;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
......@@ -56,7 +43,6 @@ import io.eelo.drive.fileFilters.OnlyFileFilter;
import io.eelo.drive.models.SyncedFolder;
import io.eelo.drive.models.SyncedFileState;
import io.eelo.drive.operations.DownloadFileOperation;
import io.eelo.drive.operations.ListRemoteFileOperation;
import io.eelo.drive.operations.ListRemoteFileOperation_v2;
import io.eelo.drive.operations.RemoveFileOperation;
import io.eelo.drive.operations.UploadFileOperation;
......@@ -178,14 +164,11 @@ public class ObserverService extends Service implements OnRemoteOperationListene
bindService(opMgrSrvIntent, this.mOperationManagerServiceConnection, Context.BIND_NOT_FOREGROUND);
} else {
handleCachedFile();
Log.d(TAG+"_begin()", "going to call startScan(true)");
startScan(true);
}
} else {
Log.e(TAG, "Can't work because there is no internet connexion");
}
}else{
Log.v(TAG, "Tried to restart ObserverService while working");
}
}