Commit eb391238 authored by vince-bourgmayer's avatar vince-bourgmayer
Browse files

Create temp Operation class with 'v2' at name's end to adapt them to new...

Create temp Operation class with 'v2' at name's end to adapt them to new process which is in ObserverServiceV2. Work on creation of Operation to do list.
parent 62f35d6e
Pipeline #2714 failed with stage
in 11 seconds
......@@ -137,6 +137,11 @@ class SyncedFileStateDAO {
return result;
}
/**
* Fetch many SyncedFileState by its localPath
* @param syncedFolderids List<String> of path to filter. Need to be directory path
......
......@@ -166,7 +166,7 @@ public class DownloadFileOperation extends RemoteOperation implements Comparable
//So now, we can update instance of SyncedState and save it to DB
if( DbHelper.manageSyncedFileStateDB( mSyncedState, "UPDATE", mContext ) <= 0 ){
Log.e(TAG, "DB update failed: 0 affected row");
//@TODO : do smtg
//@TODO : do smtg if syncedFileState didn't update
}
return new RemoteOperationResult( mResultCode );
}
......
package io.eelo.drive.operations;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
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.RemoteFile;
import java.io.File;
import java.lang.annotation.Target;
import io.eelo.drive.utils.CommonUtils;
public class DownloadFileOperationV2 extends RemoteOperation implements ComparableOperation{
private final static String TAG = DownloadFileOperation.class.getSimpleName();
private final RemoteFile mRFile;
private final Context mContext;
private String mTargetPath;
private Boolean isMediaType;
/**
* COnstructor of download operation where syncedFileState is already known
* @param remoteFile remote file to Download
* @param targetPath can be null if defined in syncedFileState
* @param context calling context
*/
public DownloadFileOperationV2(RemoteFile remoteFile, String targetPath, boolean isMediaType, Context context){
this.mRFile = remoteFile;
this.mContext = context;
this.mTargetPath = targetPath;
this.isMediaType = isMediaType;
}
@Override
protected RemoteOperationResult run(OwnCloudClient ownCloudClient) {
Log.i(TAG, "run(ownCloudClient)");
//get or build synced file equivalent of this.mFile
if(mTargetPath == null || mTargetPath.isEmpty()) {
Log.e(TAG, "mSyncedState or mTargetPath is empty or null. Can't Download in those conditions");
return new RemoteOperationResult(RemoteOperationResult.ResultCode.FORBIDDEN);
}
String fileName = CommonUtils.getFileNameFromPath(mTargetPath);
String tmpTargetPath = mContext.getExternalCacheDir()+ FileUtils.PATH_SEPARATOR+fileName;
DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(mRFile.getRemotePath(),
tmpTargetPath);
RemoteOperationResult downloadResult = downloadOperation.execute( ownCloudClient );
RemoteOperationResult.ResultCode mResultCode;
if( downloadResult.isSuccess() ){
File tmpLocalFile = new File(tmpTargetPath);
if( !tmpLocalFile.exists() ){
Log.e(TAG, "Downloaded file doesn't exist or is null");
mResultCode = RemoteOperationResult.ResultCode.FILE_NOT_FOUND;
}else if(tmpLocalFile.length() != mRFile.getLength() ){
Log.e(TAG, "Local and remote file doesn't have the same size.");
mResultCode = RemoteOperationResult.ResultCode.INVALID_OVERWRITE;
tmpLocalFile.delete();
}else{
//file has been correctly download.
File localFile = new File(mTargetPath);
if( localFile.exists() ){
localFile.delete(); //Remove existing file
}
//Check parentFolder existence and create if needed
String parentFoldersPath = localFile.getParent();
File localParentFile = new File(parentFoldersPath);
if( !localParentFile.exists() ){
if( localParentFile.mkdirs() )
Log.d(TAG, "Created folders: "+parentFoldersPath );
else
Log.d(TAG, "Can't create folders: "+parentFoldersPath );
}
boolean renameResult = tmpLocalFile.renameTo(localFile);
if(!renameResult)
Log.d(TAG, "File hasn't been successfully moved at its place");
mResultCode = RemoteOperationResult.ResultCode.OK;
//needed to make Gallery show new image
CommonUtils.doActionMediaScannerConnexionScanFile(mContext, mTargetPath );
}
}else{
//If download failed
Log.e(TAG, "Download failed: "+downloadResult.getLogMessage() );
mResultCode = RemoteOperationResult.ResultCode.UNKNOWN_ERROR;
}
return new RemoteOperationResult( mResultCode );
}
@Override
public String getRemotePath() {
return mRFile.getRemotePath();
}
@Override
public String getLocalPath() {
return mTargetPath;
}
@Override
public boolean isMediaType() {
return isMediaType;
}
@Override
public RemoteOperation toRemoteOperation() {
return this;
}
}
package io.eelo.drive.operations;
import android.content.Context;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.UserInfo;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
import java.io.File;
import io.eelo.drive.utils.CommonUtils;
public class UploadFileOperationV2 extends RemoteOperation implements ComparableOperation {
private final static String TAG = UploadFileOperationV2.class.getSimpleName();
private boolean isMediaType;
private int restartCounter =0;
private long previousLastModified;
private boolean checkEtag;
private String mTargetPath;
private final File mFile;
private final Context mContext;
@Override
public RemoteOperation toRemoteOperation() {
return this;
}
/**
* Construct an upload operation with an already known syncedFileState
* @param file File to upload
* @param context context in which to upload
* @param checkEtag if we should use IF MATCH header with etag
*/
public UploadFileOperationV2 (File file, String mTargetPath, Context context, boolean checkEtag){
this.mFile = file;
this.mContext = context;
this.mTargetPath = mTargetPath;
this.checkEtag = checkEtag;
}
/**
* Execute the operation:
*
* creates UploadFileOperation and execute it synchronously.
* When result is get and if it's a success
* Start scan remoteFile to get remote file Etag and save it in the SyncedFileState database.
* @param client (OwnCloudClient)
* @return RemoteOperationResult. Contains "Unknown error" as result code if upload fails or can contains
* "conflict" result code if it can got new Etag. It contains resultCode "Ok" if everything is allright or "sync_conflict" if file
* hasn't change since last update or "forbidden" if no remote path can be fetch.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client ) {
//as operation isn't executed immediatly, file might have been deleted since creation of operation
if(mTargetPath == null || !mFile.exists()){
Log.e(TAG, "run(client): no syncedFileState or target path, can't perform upload operation");
return new RemoteOperationResult(RemoteOperationResult.ResultCode.FORBIDDEN);
}
/* @code to verify */
GetRemoteUserInfoOperation getRemoteUserInfoOperation = new GetRemoteUserInfoOperation();
RemoteOperationResult ocsResult = getRemoteUserInfoOperation.execute(client);
if(ocsResult.isSuccess() && ocsResult.getData() != null){
if( ((UserInfo) ocsResult.getData().get(0)).getQuota().getFree() < mFile.length() ) {
Log.w(TAG, "quota exceeded!");
return new RemoteOperationResult(RemoteOperationResult.ResultCode.QUOTA_EXCEEDED);
}else{
Log.d(TAG, "Quota Okay");
}
}else{
Log.w(TAG, "getRemoteUserInfoOperation failed: "+ocsResult.getHttpCode() );
return new RemoteOperationResult(ocsResult.getCode());
}
/* end of code to verify */
String timeStamp = ( (Long) ( mFile.lastModified() / 1000) ).toString() ;
//create UploadFileOperation
/*UploadFileRemoteOperation uploadRemoteFileOperation = new UploadFileRemoteOperation( mSyncedState.getLocalPath(),
( mTargetPath != null ) ? mTargetPath : mSyncedState.getRemotePath(),
CommonUtils.getMimeType( mFile ),
( !checkEtag || mSyncedState.getLastETAG().isEmpty() )? null : mSyncedState.getLastETAG(), //If not null, This can cause error 412; that means remote file has change
timeStamp );
uploadRemoteFileOperation.askResultEtag(true);*/
// Execute UploadFileOperation
//RemoteOperationResult uploadResult = uploadRemoteFileOperation.execute( client );
RemoteOperationResult.ResultCode mResultCode;
//if upload is a success
/*if( uploadResult.isSuccess() ){
// get new Etag of the file on the server
Object data = uploadResult.getSingleData();
if(data != null){
String etag = (String) data;
Log.d(TAG, "got new etag from PUT result: "+etag);
}
mResultCode = uploadResult.getCode();
}else{
//Si les répértoires ou mettre le fichier n'existe pas, on les ajoutes.
if( uploadResult.getCode() == RemoteOperationResult.ResultCode.FILE_NOT_FOUND ){
Log.d(TAG, "Catched a File not found result for : "+mFile.getName()+", create missing remote path then retry");
String remoteFoldersPath = mTargetPath.substring( 0, mTargetPath.lastIndexOf(FileUtils.PATH_SEPARATOR)+1 );
mResultCode = RemoteOperationResult.ResultCode.FILE_NOT_FOUND;
CreateFolderRemoteOperation createFolderOperation = new CreateFolderRemoteOperation( remoteFoldersPath, true );
try{
createFolderOperation.execute( client );
}catch(Exception e){
return new RemoteOperationResult(e);
}
}else if(uploadResult.getCode() == RemoteOperationResult.ResultCode.QUOTA_EXCEEDED){
mResultCode = RemoteOperationResult.ResultCode.QUOTA_EXCEEDED;
mustRestart = false;
}else{
//Upload failed
Log.e(TAG, "UploadRemoteFileOperation for : " + mFile.getName() + " failed => code: " + uploadResult.getCode());
mResultCode = RemoteOperationResult.ResultCode.UNKNOWN_ERROR;
}
}
// updated syncedFile in DB
DbHelper.manageSyncedFileStateDB(mSyncedState, "UPDATE", mContext);
ArrayList<Object> datas = new ArrayList<>();
datas.add(mSyncedState.getSyncedFolderId());
final RemoteOperationResult finalResult = new RemoteOperationResult(mResultCode);
finalResult.setData(datas);*/
return ocsResult;
}
/**
* Return the file that should be uploading
* @return File given to this operation
*/
public File getFile() {
return mFile;
}
/**
* tell what type of operation is it
* @return true if it is an operation for media's element, then false mean its a settings operation
*/
@Override
public boolean isMediaType(){
return isMediaType;
}
/**
* Return the path of a file in the cloud
* @return String. The path to the file
*/
@Override
public String getRemotePath() {
return mTargetPath;
}
/**
* Return the path on the device of a file.
* @return String. The path to the file
*/
@Override
public String getLocalPath() {
return CommonUtils.getLocalPath(mFile);
}
}
......@@ -201,6 +201,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
}
private String getExternalFolder(String directory){
return CommonUtils.getLocalPath(Environment.getExternalStoragePublicDirectory(directory))+ PATH_SEPARATOR;
}
......
......@@ -46,6 +46,7 @@ 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;
......@@ -235,56 +236,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene
}
/**
* Provide list<RemoteFile> from previous server state
* @return empty list if no file does not exist or if error occurs
*/
private List<RemoteFile> loadPreviousServerContent(){
List<RemoteFile> result = new ArrayList<>();
Type type = Types.newParameterizedType(List.class, RemoteFile.class);
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<List<RemoteFile>> jsonAdapter = moshi.adapter(type);
try{
String filePath = getFilesDir().getCanonicalPath() + PATH_SEPARATOR + AppConstants.SERVER_CONTENT_FILE_NAME;
if(new File(filePath).exists()) {
String content = new String(Files.readAllBytes(Paths.get(filePath)));
result = jsonAdapter.fromJson(content);
}
} catch (Exception e) {
Log.e(TAG, "Can't save file with package list: "+e.toString());
}
return result;
}
/**
* Save the content of the server into a file
* @param serverContent
*/
private void saveServerContentToInternalFile(List<RemoteFile> serverContent){
Type type = Types.newParameterizedType(List.class, RemoteFile.class);
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<List<RemoteFile>> jsonAdapter = moshi.adapter(type);
try {
FileOutputStream tmp = openFileOutput(AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP, Context.MODE_PRIVATE);
tmp.write(jsonAdapter.toJson(serverContent).getBytes());
tmp.close();
String filesdir = getFilesDir().getCanonicalPath()+PATH_SEPARATOR;
File tmp_file = new File(filesdir+AppConstants.SERVER_CONTENT_FILE_NAME_TMP);
File real_file = new File(filesdir+AppConstants.SERVER_CONTENT_FILE_NAME);
if ( tmp_file.length() != real_file.length() ) {
tmp_file.renameTo(real_file);
} else {
tmp_file.delete();
}
} catch (Exception e) {
Log.e(TAG, "Can't save file with package list: "+e.toString());
}
}
/**
......@@ -333,11 +284,13 @@ public class ObserverService extends Service implements OnRemoteOperationListene
Log.i( TAG, "onRemoteOperationFinish()" );
if( remoteOperation instanceof ListRemoteFileOperation_v2){
if( remoteOperationResult.isSuccess() ){
Log.d(TAG+"_onRemoteOperationFinish(...)", "ListRemoteFileOperation is a success");
List<Object> resultDatas = remoteOperationResult.getData();
if(resultDatas != null ){
List<SyncedFileState> syncedFileStateList = DbHelper.getSyncedFileStatesByFolders( this,
getIdsFromFolderToScan());
if(!resultDatas.isEmpty() || ! syncedFileStateList.isEmpty() && CommonUtils.isMediaSyncEnabled(mAccount)) {
handleRemoteFiles(resultDatas, syncedFileStateList);
}
......@@ -377,7 +330,57 @@ public class ObserverService extends Service implements OnRemoteOperationListene
Log.i(TAG, "handleRemoteFiles()");
Log.v(CURRENTTAG, "start to loop through remoteFiles");
List<RemoteFile> previousServerContent = loadPreviousServerContent();
/*List<SyncedFolder> folders = DbHelper.getAllSyncedFolders(this);
List<Long> idToIgnore = new ArrayList<>();
for (Object o : remoteFiles){
RemoteFile rf = (RemoteFile) o;
if(rf.getMimeType().equals("DIR")){
boolean equivalentFound = false;
ListIterator<SyncedFolder> folder = folders.listIterator();
while(folder.hasNext()) {
SyncedFolder sf = folder.next();
if (sf.getRemoteFolder().equals(rf.getPath())) {
equivalentFound = true;
if (!sf.getLastEtag().equals(rf.getEtag())) {
sf.setToSync(true);
} else {
idToIgnore.add((long) sf.getId());
}
}
}
if(equivalentFound = false){
SyncedFolder newSf = new SyncedFolder()
}
}else{
SyncedFileState sfs = DbHelper.loadSyncedFile(this, rf.getRemotePath(), false);
if(sfs != null){
}
}
}*/
ListIterator<SyncedFileState> syncedFileListIterator;
for( int i =-1, size = remoteFiles.size(); ++i < size; ){
......
......@@ -48,7 +48,10 @@ import io.eelo.drive.fileFilters.FileFilterFactory;
import io.eelo.drive.fileFilters.OnlyFileFilter;
import io.eelo.drive.models.Operation;
import io.eelo.drive.models.SyncedFolder;
import io.eelo.drive.operations.DownloadFileOperation;
import io.eelo.drive.operations.DownloadFileOperationV2;
import io.eelo.drive.operations.ListRemoteFileOperation_v2;
import io.eelo.drive.operations.UploadFileOperation;
import io.eelo.drive.utils.AppConstants;
import io.eelo.drive.utils.CommonUtils;
import io.eelo.drive.utils.IGetOCClient;
......@@ -118,8 +121,6 @@ public class ObserverServiceV2 extends Service implements OnRemoteOperationListe
Log.i(TAG, "onCreate()");
super.onCreate();
/* Test */
//@TODO check if needed
Intent opMgrSrvIntent = new Intent(this, OperationManagerService.class);
getApplicationContext().startService(opMgrSrvIntent);
}
......@@ -308,7 +309,7 @@ public class ObserverServiceV2 extends Service implements OnRemoteOperationListe
}
//@TODO need to look for folder inside OldOperation and new Operation (question when folder creation ?, how to differenciate really new folder from modified folder ?)
//@TODO need to look for folder inside OldOperation and new Operation ( how to differenciate really new folder from modified folder ?)
/*String displayOperationList ="OperationList: \n";
......@@ -329,8 +330,7 @@ public class ObserverServiceV2 extends Service implements OnRemoteOperationListe
/**
* Change the list obtained from scanning phone or server into a list of operation todo
* Todo:
* Change the list obtained from scanning phone or server into a list of operation
* - implement the "catch(Exception)" around getCanonicalPath.
*
* @return HashMap<String, Operation>
......@@ -364,7 +364,11 @@ public class ObserverServiceV2 extends Service implements OnRemoteOperationListe
/* Methods related to device Scanning */
/**TODO: don't forget to add operationList **/
/**
* Get the list of local file and compare with previous state then build operationList
* @param initialFolder
* @param operationToDo
*/
public void startLocalScan(List<SyncedFolder> initialFolder, HashMap<String, Operation> operationToDo){
if(CommonUtils.isSettingsSyncEnabled(mAccount) ) SpecificFileGenerator.writeAppListFile(this);
......@@ -407,11 +411,58 @@ public class ObserverServiceV2 extends Service implements OnRemoteOperationListe
Log.d(TAG, "[After]path to ignore: \n"+pathListToIgnore);
}
String display ="list of Operation before crossng \n";
for(Map.Entry<String, Operation> entry: operationToDo.entrySet() ){
display+= entry.getKey()+" : "+entry.getValue().getOperationCode()+"\n";
}
Log.d(TAG, display);
buildLocalOperationList(newDeviceContent, oldDeviceContent, initialFolder, operationToDo);
display ="list of Operation after crossng \n";
for(Map.Entry<String, Operation> entry: operationToDo.entrySet() ){
display+= entry.getKey()+" : "+entry.getValue().getOperationCode()+"\n";
}
Log.d(TAG, display);
}
/**
* Take operation list and send them to OperationManager
*/
public void performOperation(HashMap<String, Operation> operationToDo){
for(Map.Entry<String, Operation> entry: operationToDo.entrySet() ){
if(entry.getValue().getOperationCode() == Operation.OPERATION_DOWNLOAD) {
//DownloadFileOperationV2 downloadFileOperation = new DownloadFileOperationV2((RemoteFile) entry.getValue().getFile(), entry.getKey(), this);
//mOperationManagerService.addOperation(downloadFileOperation);
}
else if(entry.getValue().getOperationCode() == Operation.OPERATION_UPLOAD){
//UploadFileOperation uploadFileOperation = new UploadFileOperationV2();
//mOperationManagerService.addOperation(downloadFileOperation);
}
else if(entry.getValue().getOperationCode() == Operation.OPERATION_MKCOL){
//CreateFolderRemoteOperation mkcolOperation = new CreateFolderRemoteOperation();
//mOperationManagerService.addOperation(downloadFileOperation);
}
else if(entry.getValue().getOperationCode() == Operation.OPERATION_REMOVE_LOCAL){
}
else if(entry.getValue().getOperationCode() == Operation.OPERATION_REMOVE_REMOTE){
//RemoveFileOperation remove = new RemoveFileOperation();
//mOperationManagerService.addOperation(remove);
}
}
}
/**
* Provide list<RemoteFile> from previous server state
* @return empty list if no file does not exist or if error occurs
......@@ -462,23 +513,27 @@ public class ObserverServiceV2 extends Service implements OnRemoteOperationListe
}
/**
* Change the list obtained from scanning phone or server into a list of operation todo
* Todo:
* Change the list obtained from scanning phone or server into a list of operation
* To do:
* - implement the "catch(Exception)" around getCanonicalPath.
*
* @return HashMap<String, Operation>
*/