package com.owncloud.android.operations;
-import java.io.IOException;
import java.util.List;
import java.util.Vector;
import org.apache.http.HttpStatus;
-import org.apache.jackrabbit.webdav.DavException;
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.util.Log;
-import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.DataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileObserverService;
+import com.owncloud.android.utils.FileStorageUtils;
import eu.alefzero.webdav.WebdavClient;
import eu.alefzero.webdav.WebdavEntry;
*/
public class SynchronizeFolderOperation extends RemoteOperation {
- private static final String TAG = SynchronizeFolderOperation.class.getCanonicalName();
+ private static final String TAG = SynchronizeFolderOperation.class.getSimpleName();
/** Remote folder to synchronize */
private String mRemotePath;
private long mParentId;
/** Access to the local database */
- private FileDataStorageManager mStorageManager;
+ private DataStorageManager mStorageManager;
/** Account where the file to synchronize belongs */
private Account mAccount;
+ /** Android context; necessary to send requests to the download service; maybe something to refactor */
+ private Context mContext;
- SynchronizeFolderOperation(String remotePath, long currentSyncTime, long parentId, FileDataStorageManager storageManager, Account account) {
+ /** Files and folders contained in the synchronized folder */
+ private List<OCFile> mChildren;
+
+
+ public SynchronizeFolderOperation( String remotePath,
+ long currentSyncTime,
+ long parentId,
+ DataStorageManager dataStorageManager,
+ Account account,
+ Context context ) {
mRemotePath = remotePath;
mCurrentSyncTime = currentSyncTime;
mParentId = parentId;
- mStorageManager = storageManager;
+ mStorageManager = dataStorageManager;
mAccount = account;
+ mContext = context;
+ }
+
+
+ /**
+ * Returns the list of files and folders contained in the synchronized folder, if called after synchronization is complete.
+ *
+ * @return List of files and folders contained in the synchronized folder.
+ */
+ public List<OCFile> getChildren() {
+ return mChildren;
}
// code before in FileSyncAdapter.fetchData
PropFindMethod query = null;
- Vector<OCFile> children = null;
try {
- Log.d(TAG, "Fetching files in " + mRemotePath);
+ Log.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath);
// remote request
query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
int status = client.executeMethod(query);
- if (isSuccess(status)) {
-
+ // check and process response - /// TODO take into account all the possible status per child-resource
+ if (isMultiStatus(status)) {
MultiStatus resp = query.getResponseBodyAsMultiStatus();
- // reading files
+ // synchronize properties of the parent folder, if necessary
+ if (mParentId == DataStorageManager.ROOT_PARENT_ID) {
+ WebdavEntry we = new WebdavEntry(resp.getResponses()[0], client.getBaseUri().getPath());
+ OCFile parent = fillOCFile(we);
+ parent.setParentId(mParentId);
+ mStorageManager.saveFile(parent);
+ mParentId = parent.getFileId();
+ }
+
+ // read contents in folder
List<OCFile> updatedFiles = new Vector<OCFile>(resp.getResponses().length - 1);
for (int i = 1; i < resp.getResponses().length; ++i) {
WebdavEntry we = new WebdavEntry(resp.getResponses()[i], client.getBaseUri().getPath());
OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath());
if (oldFile != null) {
if (oldFile.keepInSync() && file.getModificationTimestamp() > oldFile.getModificationTimestamp()) {
- requestContentDownload();
+ disableObservance(file); // first disable observer so we won't get file upload right after download
+ requestContentDownload(file);
}
file.setKeepInSync(oldFile.keepInSync());
}
updatedFiles.add(file);
}
-
-
- // save updated files in local database; all at once, trying to get a best performance in database update (not a big deal, indeed)
+
+ // save updated contents in local database; all at once, trying to get a best performance in database update (not a big deal, indeed)
mStorageManager.saveFiles(updatedFiles);
// removal of obsolete files
- children = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId));
+ mChildren = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId));
OCFile file;
- String currentSavePath = FileDownloader.getSavePath(mAccount.name);
- for (int i=0; i < children.size(); ) {
- file = children.get(i);
+ String currentSavePath = FileStorageUtils.getSavePath(mAccount.name);
+ for (int i=0; i < mChildren.size(); ) {
+ file = mChildren.get(i);
if (file.getLastSyncDate() != mCurrentSyncTime) {
Log.d(TAG, "removing file: " + file);
mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath)));
- children.remove(i);
+ mChildren.remove(i);
} else {
i++;
}
}
- } else if (status == HttpStatus.SC_UNAUTHORIZED) {
- syncResult.stats.numAuthExceptions++;
-
} else {
- // TODO something smart with syncResult? OR NOT
+ client.exhaustResponse(query.getResponseBodyAsStream());
}
- result = new RemoteOperationResult(isSuccess(status), status);
- Log.i(TAG, "Synchronization of " + mRemotePath + ": " + result.getLogMessage());
+ // prepare result object
+ result = new RemoteOperationResult(isMultiStatus(status), status);
+ Log.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage());
- } catch (IOException e) {
- syncResult.stats.numIoExceptions++;
- logException(e, uri);
-
- } catch (DavException e) {
- syncResult.stats.numParseExceptions++;
- logException(e, uri);
-
} catch (Exception e) {
- // TODO something smart with syncresult
- mRightSync = false;
- logException(e, uri);
+ result = new RemoteOperationResult(e);
+ Log.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException());
} finally {
if (query != null)
query.releaseConnection(); // let the connection available for other methods
-
- // synchronized folder -> notice to UI
- sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath());
}
-
return result;
}
-
- public boolean isSuccess(int status) {
- return (status == HttpStatus.SC_MULTI_STATUS); // TODO check other possible OK codes; doc doesn't help
- }
-
- private void requestContentDownload() {
- Intent intent = new Intent(this.getContext(), FileDownloader.class);
- intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount());
- intent.putExtra(FileDownloader.EXTRA_FILE, file);
- file.setKeepInSync(true);
- getContext().startService(intent);
+ public boolean isMultiStatus(int status) {
+ 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).
+ * @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());
return file;
}
+
+ /**
+ * Request to stop the observance of local updates for a file.
+ *
+ * @param file OCFile representing the remote file to stop to monitor for local updates
+ */
+ private void disableObservance(OCFile file) {
+ Log.d(TAG, "Disabling observation of remote file" + file.getRemotePath());
+ Intent intent = new Intent(mContext, FileObserverService.class);
+ intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_ADD_DOWNLOADING_FILE);
+ intent.putExtra(FileObserverService.KEY_CMD_ARG, file.getRemotePath());
+ mContext.startService(intent);
+
+ }
+
+
+ /**
+ * Requests a download to the file download service
+ *
+ * @param file OCFile representing the remote file to download
+ */
+ private void requestContentDownload(OCFile file) {
+ Intent intent = new Intent(mContext, FileDownloader.class);
+ intent.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+ intent.putExtra(FileDownloader.EXTRA_FILE, file);
+ mContext.startService(intent);
+ }
+
+
}