--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2012 Bartek Przybylski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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.Intent;
+import android.util.Log;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavEntry;
+import eu.alefzero.webdav.WebdavUtils;
+
+
+/**
+ * Remote operation performing the synchronization a the contents of a remote folder with the local database
+ *
+ * @author David A. Velasco
+ */
+public class SynchronizeFolderOperation extends RemoteOperation {
+
+ private static final String TAG = SynchronizeFolderOperation.class.getCanonicalName();
+
+ /** Remote folder to synchronize */
+ private String mRemotePath;
+
+ /** Timestamp for the synchronization in progress */
+ private long mCurrentSyncTime;
+
+ /** Id of the folder to synchronize in the local database */
+ private long mParentId;
+
+ /** Access to the local database */
+ private FileDataStorageManager mStorageManager;
+
+ /** Account where the file to synchronize belongs */
+ private Account mAccount;
+
+
+ SynchronizeFolderOperation(String remotePath, long currentSyncTime, long parentId, FileDataStorageManager storageManager, Account account) {
+ mRemotePath = remotePath;
+ mCurrentSyncTime = currentSyncTime;
+ mParentId = parentId;
+ mStorageManager = storageManager;
+ mAccount = account;
+ }
+
+
+ @Override
+ protected RemoteOperationResult run(WebdavClient client) {
+ RemoteOperationResult result = null;
+
+ // code before in FileSyncAdapter.fetchData
+ PropFindMethod query = null;
+ Vector<OCFile> children = null;
+ try {
+ Log.d(TAG, "Fetching files in " + mRemotePath);
+
+ // remote request
+ query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
+ int status = client.executeMethod(query);
+
+ if (isSuccess(status)) {
+
+ MultiStatus resp = query.getResponseBodyAsMultiStatus();
+
+ // reading files
+ 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 file = fillOCFile(we);
+ file.setParentId(mParentId);
+ OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath());
+ if (oldFile != null) {
+ if (oldFile.keepInSync() && file.getModificationTimestamp() > oldFile.getModificationTimestamp()) {
+ requestContentDownload();
+ }
+ 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)
+ mStorageManager.saveFiles(updatedFiles);
+
+
+ // removal of obsolete files
+ children = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId));
+ OCFile file;
+ String currentSavePath = FileDownloader.getSavePath(mAccount.name);
+ for (int i=0; i < children.size(); ) {
+ file = children.get(i);
+ if (file.getLastSyncDate() != mCurrentSyncTime) {
+ Log.d(TAG, "removing file: " + file);
+ mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath)));
+ children.remove(i);
+ } else {
+ i++;
+ }
+ }
+
+ } else if (status == HttpStatus.SC_UNAUTHORIZED) {
+ syncResult.stats.numAuthExceptions++;
+
+ } else {
+ // TODO something smart with syncResult? OR NOT
+ }
+
+ result = new RemoteOperationResult(isSuccess(status), status);
+ Log.i(TAG, "Synchronization of " + 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);
+
+ } 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);
+ }
+
+
+ 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.modifiedTimesamp());
+ file.setLastSyncDate(mCurrentSyncTime);
+ return file;
+ }
+
+}
import com.owncloud.android.datamodel.FileDataStorageManager;\r
import com.owncloud.android.datamodel.OCFile;\r
import com.owncloud.android.files.services.FileDownloader;\r
+import com.owncloud.android.operations.RemoteOperationResult;\r
import com.owncloud.android.utils.OwnCloudVersion;\r
\r
import android.accounts.Account;\r
\r
Log.d(TAG, "syncing owncloud account " + account.name);\r
\r
- sendStickyBroadcast(true, null); // message to signal the start to the UI\r
+ sendStickyBroadcast(true, null, null); // message to signal the start to the UI\r
\r
updateOCVersion();\r
\r
}\r
\r
\r
- private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) {\r
+ private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {\r
Intent i = new Intent(FileSyncService.SYNC_MESSAGE);\r
i.putExtra(FileSyncService.IN_PROGRESS, inProgress);\r
i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);\r
if (dirRemotePath != null) {\r
i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);\r
}\r
+ if (result != null) {\r
+ i.putExtra(FileSyncService.SYNC_RESULT, result);\r
+ }\r
getContext().sendStickyBroadcast(i);\r
}\r
\r