X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/af62f9857d72b4df230797c4738d5f8752ac1785..901b6ac61e4a84d281e86b4989aa099801b28de7:/src/com/owncloud/android/operations/SynchronizeFolderOperation.java diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java index 2c8cfe4b..68e78578 100644 --- a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -23,29 +23,36 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import org.apache.http.HttpStatus; -import org.apache.jackrabbit.webdav.MultiStatus; -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; - import android.accounts.Account; import android.content.Context; import android.content.Intent; +//import android.support.v4.content.LocalBroadcastManager; -import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.operations.RemoteOperationResult.ResultCode; -import com.owncloud.android.syncadapter.FileSyncService; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.resources.shares.OCShare; +import com.owncloud.android.lib.common.operations.RemoteOperation; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation; +import com.owncloud.android.lib.resources.files.FileUtils; +import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation; +import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; +import com.owncloud.android.lib.resources.files.RemoteFile; + +import com.owncloud.android.syncadapter.FileSyncAdapter; import com.owncloud.android.utils.FileStorageUtils; +import com.owncloud.android.utils.Log_OC; -import eu.alefzero.webdav.WebdavClient; -import eu.alefzero.webdav.WebdavEntry; -import eu.alefzero.webdav.WebdavUtils; /** @@ -63,6 +70,8 @@ public class SynchronizeFolderOperation extends RemoteOperation { private static final String TAG = SynchronizeFolderOperation.class.getSimpleName(); + public static final String EVENT_SINGLE_FOLDER_CONTENTS_SYNCED = SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_CONTENTS_SYNCED"; + public static final String EVENT_SINGLE_FOLDER_SHARES_SYNCED = SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_SHARES_SYNCED"; /** Time stamp for the synchronization process in progress */ private long mCurrentSyncTime; @@ -70,9 +79,6 @@ public class SynchronizeFolderOperation extends RemoteOperation { /** Remote folder to synchronize */ private OCFile mLocalFolder; - /** 'True' means that the properties of the folder should be updated also, not just its content */ - private boolean mUpdateFolderProperties; - /** Access to the local database */ private FileDataStorageManager mStorageManager; @@ -96,7 +102,13 @@ public class SynchronizeFolderOperation extends RemoteOperation { /** 'True' means that this operation is part of a full account synchronization */ private boolean mSyncFullAccount; + + /** 'True' means that Share resources bound to the files into the folder should be refreshed also */ + private boolean mIsShareSupported; + /** 'True' means that the remote folder changed from last synchronization and should be fetched */ + private boolean mRemoteFolderChanged; + /** * Creates a new instance of {@link SynchronizeFolderOperation}. @@ -112,19 +124,20 @@ public class SynchronizeFolderOperation extends RemoteOperation { */ public SynchronizeFolderOperation( OCFile folder, long currentSyncTime, - boolean updateFolderProperties, boolean syncFullAccount, + boolean isShareSupported, FileDataStorageManager dataStorageManager, Account account, Context context ) { mLocalFolder = folder; mCurrentSyncTime = currentSyncTime; - mUpdateFolderProperties = updateFolderProperties; mSyncFullAccount = syncFullAccount; + mIsShareSupported = isShareSupported; mStorageManager = dataStorageManager; mAccount = account; mContext = context; mForgottenLocalFiles = new HashMap(); + mRemoteFolderChanged = false; } @@ -155,181 +168,206 @@ public class SynchronizeFolderOperation extends RemoteOperation { * {@inheritDoc} */ @Override - protected RemoteOperationResult run(WebdavClient client) { + protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; mFailsInFavouritesFound = 0; mConflictsFound = 0; mForgottenLocalFiles.clear(); - String remotePath = null; - PropFindMethod query = null; - try { - remotePath = mLocalFolder.getRemotePath(); - Log_OC.d(TAG, "Synchronizing " + mAccount.name + remotePath); - - // remote request - query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(remotePath)); - int status = client.executeMethod(query); - - // check and process response - if (isMultiStatus(status)) { - boolean folderChanged = synchronizeData(query.getResponseBodyAsMultiStatus(), client); - if (folderChanged) { - if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { - result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); // should be different result, but will do the job - } else { - result = new RemoteOperationResult(true, status, query.getResponseHeaders()); - } - } else { - result = new RemoteOperationResult(ResultCode.OK_NO_CHANGES_ON_DIR); - } - + + if (FileUtils.PATH_SEPARATOR.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) { + updateOCVersion(client); + } + + result = checkForChanges(client); + + if (result.isSuccess()) { + if (mRemoteFolderChanged) { + result = fetchAndSyncRemoteFolder(client); } else { - // synchronization failed - client.exhaustResponse(query.getResponseBodyAsStream()); - if (status == HttpStatus.SC_NOT_FOUND) { - if (mStorageManager.fileExists(mLocalFolder.getFileId())) { - String currentSavePath = FileStorageUtils.getSavePath(mAccount.name); - mStorageManager.removeFolder(mLocalFolder, true, (mLocalFolder.isDown() && mLocalFolder.getStoragePath().startsWith(currentSavePath))); - } - } - result = new RemoteOperationResult(false, status, query.getResponseHeaders()); + mChildren = mStorageManager.getFolderContent(mLocalFolder); } + } + + if (!mSyncFullAccount) { + sendLocalBroadcast(EVENT_SINGLE_FOLDER_CONTENTS_SYNCED, mLocalFolder.getRemotePath(), result); + } + + if (result.isSuccess() && mIsShareSupported && !mSyncFullAccount) { + refreshSharesForFolder(client); // share result is ignored + } + + if (!mSyncFullAccount) { + sendLocalBroadcast(EVENT_SINGLE_FOLDER_SHARES_SYNCED, mLocalFolder.getRemotePath(), result); + } + + return result; + + } - } catch (Exception e) { - result = new RemoteOperationResult(e); - - } finally { - if (query != null) - query.releaseConnection(); // let the connection available for other methods - if (result.isSuccess()) { - Log_OC.i(TAG, "Synchronized " + mAccount.name + remotePath + ": " + result.getLogMessage()); - } else { - if (result.isException()) { - Log_OC.e(TAG, "Synchronized " + mAccount.name + remotePath + ": " + result.getLogMessage(), result.getException()); - } else { - Log_OC.e(TAG, "Synchronized " + mAccount.name + remotePath + ": " + result.getLogMessage()); - } - } + private void updateOCVersion(OwnCloudClient client) { + UpdateOCVersionOperation update = new UpdateOCVersionOperation(mAccount, mContext); + RemoteOperationResult result = update.execute(client); + if (result.isSuccess()) { + mIsShareSupported = update.getOCVersion().isSharedSupported(); + } + } + + + private RemoteOperationResult checkForChanges(OwnCloudClient client) { + mRemoteFolderChanged = false; + RemoteOperationResult result = null; + String remotePath = null; + + remotePath = mLocalFolder.getRemotePath(); + Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath); + + // remote request + ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath); + result = operation.execute(client); + if (result.isSuccess()){ + OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0)); + + // check if remote and local folder are different + mRemoteFolderChanged = !(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag())); + + result = new RemoteOperationResult(ResultCode.OK); + + Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " + (mRemoteFolderChanged ? "changed" : "not changed")); - if (!mSyncFullAccount) { - sendStickyBroadcast(false, remotePath, result); + } else { + // check failed + if (result.getCode() == ResultCode.FILE_NOT_FOUND) { + removeLocalFolder(); + } + if (result.isException()) { + Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + result.getLogMessage(), result.getException()); + } else { + Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + result.getLogMessage()); } } + + return result; + } + + private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) { + String remotePath = mLocalFolder.getRemotePath(); + ReadRemoteFolderOperation operation = new ReadRemoteFolderOperation(remotePath); + RemoteOperationResult result = operation.execute(client); + Log_OC.d(TAG, "Synchronizing " + mAccount.name + remotePath); + + if (result.isSuccess()) { + synchronizeData(result.getData(), client); + if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { + result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); // should be different result, but will do the job + } + } else { + if (result.getCode() == ResultCode.FILE_NOT_FOUND) + removeLocalFolder(); + } + return result; } + + private void removeLocalFolder() { + if (mStorageManager.fileExists(mLocalFolder.getFileId())) { + String currentSavePath = FileStorageUtils.getSavePath(mAccount.name); + mStorageManager.removeFolder(mLocalFolder, true, (mLocalFolder.isDown() && mLocalFolder.getStoragePath().startsWith(currentSavePath))); + } + } + /** * Synchronizes the data retrieved from the server about the contents of the target folder * with the current data in the local database. * * Grants that mChildren is updated with fresh data after execution. - * - * @param dataInServer Full response got from the server with the data of the target - * folder and its direct children. + * + * @param folderAndFiles Remote folder and children files in Folder + * * @param client Client instance to the remote server where the data were * retrieved. * @return 'True' when any change was made in the local data, 'false' otherwise. */ - private boolean synchronizeData(MultiStatus dataInServer, WebdavClient client) { + private void synchronizeData(ArrayList folderAndFiles, OwnCloudClient client) { // get 'fresh data' from the database - mLocalFolder = mStorageManager.getFileById(mLocalFolder.getFileId()); + mLocalFolder = mStorageManager.getFileByPath(mLocalFolder.getRemotePath()); // parse data from remote folder - WebdavEntry we = new WebdavEntry(dataInServer.getResponses()[0], client.getBaseUri().getPath()); - OCFile remoteFolder = fillOCFile(we); + OCFile remoteFolder = fillOCFile((RemoteFile)folderAndFiles.get(0)); remoteFolder.setParentId(mLocalFolder.getParentId()); remoteFolder.setFileId(mLocalFolder.getFileId()); - // check if remote and local folder are different - boolean folderChanged = !(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag())); + Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() + " changed - starting update of local data "); - if (!folderChanged) { - if (mUpdateFolderProperties) { // TODO check if this is really necessary - mStorageManager.saveFile(remoteFolder); - } - - Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() + " didn't change"); - mChildren = mStorageManager.getFolderContent(mLocalFolder); - - } else { - Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() + " changed - starting update of local data "); - - List updatedFiles = new Vector(dataInServer.getResponses().length - 1); - List filesToSyncContents = new Vector(); - - // get current data about local contents of the folder to synchronize - List localFiles = mStorageManager.getFolderContent(mLocalFolder); - Map localFilesMap = new HashMap(localFiles.size()); - for (OCFile file : localFiles) { - localFilesMap.put(file.getRemotePath(), file); - } + List updatedFiles = new Vector(folderAndFiles.size() - 1); + List filesToSyncContents = new Vector(); + + // get current data about local contents of the folder to synchronize + List localFiles = mStorageManager.getFolderContent(mLocalFolder); + Map localFilesMap = new HashMap(localFiles.size()); + for (OCFile file : localFiles) { + localFilesMap.put(file.getRemotePath(), file); + } + + // loop to update every child + OCFile remoteFile = null, localFile = null; + for (int i=1; i filesToSyncContents, WebdavClient client) { + private void startContentSynchronizations(List filesToSyncContents, OwnCloudClient client) { RemoteOperationResult contentsResult = null; for (SynchronizeFileOperation op: filesToSyncContents) { contentsResult = op.execute(client); // returns without waiting for upload or download finishes @@ -365,20 +403,19 @@ public class SynchronizeFolderOperation extends RemoteOperation { return (status == HttpStatus.SC_MULTI_STATUS); } - /** * Creates and populates a new {@link OCFile} object with the data read from the server. * - * @param we WebDAV entry read from the server for a WebDAV resource (remote file or folder). + * @param remote remote file read from the server (remote file or folder). * @return New OCFile instance representing the remote resource described by we. */ - private OCFile fillOCFile(WebdavEntry we) { - OCFile file = new OCFile(we.decodedPath()); - file.setCreationTimestamp(we.createTimestamp()); - file.setFileLength(we.contentLength()); - file.setMimetype(we.contentType()); - file.setModificationTimestamp(we.modifiedTimestamp()); - file.setEtag(we.etag()); + private OCFile fillOCFile(RemoteFile remote) { + OCFile file = new OCFile(remote.getRemotePath()); + file.setCreationTimestamp(remote.getCreationTimestamp()); + file.setFileLength(remote.getLength()); + file.setMimetype(remote.getMimeType()); + file.setModificationTimestamp(remote.getModifiedTimestamp()); + file.setEtag(remote.getEtag()); return file; } @@ -445,7 +482,27 @@ public class SynchronizeFolderOperation extends RemoteOperation { } } } + + + private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) { + RemoteOperationResult result = null; + + // remote request + GetRemoteSharesForFileOperation operation = new GetRemoteSharesForFileOperation(mLocalFolder.getRemotePath(), false, true); + result = operation.execute(client); + + if (result.isSuccess()) { + // update local database + ArrayList shares = new ArrayList(); + for(Object obj: result.getData()) { + shares.add((OCShare) obj); + } + mStorageManager.saveSharesInFolder(shares, mLocalFolder); + } + return result; + } + /** * Scans the default location for saving local copies of files searching for @@ -468,20 +525,25 @@ public class SynchronizeFolderOperation extends RemoteOperation { /** * Sends a message to any application component interested in the progress of the synchronization. * - * @param inProgress 'True' when the synchronization progress is not finished. + * @param event * @param dirRemotePath Remote path of a folder that was just synchronized (with or without success) + * @param result */ - private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) { - Intent i = new Intent(FileSyncService.SYNC_MESSAGE); - i.putExtra(FileSyncService.IN_PROGRESS, inProgress); - i.putExtra(FileSyncService.ACCOUNT_NAME, mAccount.name); + private void sendLocalBroadcast(String event, String dirRemotePath, RemoteOperationResult result) { + Log_OC.d(TAG, "Send broadcast " + event); + Intent intent = new Intent(event); + intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, mAccount.name); if (dirRemotePath != null) { - i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath); - } - if (result != null) { - i.putExtra(FileSyncService.SYNC_RESULT, result); + intent.putExtra(FileSyncAdapter.EXTRA_FOLDER_PATH, dirRemotePath); } - mContext.sendStickyBroadcast(i); + intent.putExtra(FileSyncAdapter.EXTRA_RESULT, result); + mContext.sendStickyBroadcast(intent); + //LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent); + } + + + public boolean getRemoteFolderChanged() { + return mRemoteFolderChanged; } }