/* ownCloud Android client application
* Copyright (C) 2012 Bartek Przybylski
+ * Copyright (C) 2012-2013 ownCloud Inc.
*
* 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.
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
-import android.util.Log;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.DataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
public class SynchronizeFileOperation extends RemoteOperation {
private String TAG = SynchronizeFileOperation.class.getSimpleName();
- private String mRemotePath;
+ private static final int SYNC_READ_TIMEOUT = 10000;
+ private static final int SYNC_CONNECTION_TIMEOUT = 5000;
+
+ private OCFile mLocalFile;
+ private OCFile mServerFile;
private DataStorageManager mStorageManager;
private Account mAccount;
private boolean mSyncFileContents;
private boolean mTransferWasRequested = false;
public SynchronizeFileOperation(
- String remotePath,
- DataStorageManager dataStorageManager,
+ OCFile localFile,
+ OCFile serverFile, // make this null to let the operation checks the server; added to reuse info from SynchronizeFolderOperation
+ DataStorageManager storageManager,
Account account,
boolean syncFileContents,
- boolean localChangeAlreadyKnown,
+ boolean localChangeAlreadyKnown,
Context context) {
- mRemotePath = remotePath;
- mStorageManager = dataStorageManager;
+ mLocalFile = localFile;
+ mServerFile = serverFile;
+ mStorageManager = storageManager;
mAccount = account;
mSyncFileContents = syncFileContents;
mLocalChangeAlreadyKnown = localChangeAlreadyKnown;
mContext = context;
}
-
+
@Override
protected RemoteOperationResult run(WebdavClient client) {
RemoteOperationResult result = null;
mTransferWasRequested = false;
try {
- OCFile localFile = mStorageManager.getFileByPath(mRemotePath);
-
- if (!localFile.isDown()) {
+ if (!mLocalFile.isDown()) {
/// easy decision
- requestForDownload(localFile);
+ requestForDownload(mLocalFile);
result = new RemoteOperationResult(ResultCode.OK);
} else {
- /// local copy in the device -> need to think a bit more before do nothing
+ /// local copy in the device -> need to think a bit more before do anything
- propfind = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
- int status = client.executeMethod(propfind);
- boolean isMultiStatus = status == HttpStatus.SC_MULTI_STATUS;
- if (isMultiStatus) {
- MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
- WebdavEntry we = new WebdavEntry(resp.getResponses()[0],
+ if (mServerFile == null) {
+ /// take the duty of check the server for the current state of the file there
+ propfind = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mLocalFile.getRemotePath()));
+ int status = client.executeMethod(propfind, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT);
+ boolean isMultiStatus = status == HttpStatus.SC_MULTI_STATUS;
+ if (isMultiStatus) {
+ MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
+ WebdavEntry we = new WebdavEntry(resp.getResponses()[0],
client.getBaseUri().getPath());
- OCFile serverFile = fillOCFile(we);
+ mServerFile = fillOCFile(we);
+ mServerFile.setLastSyncDateForProperties(System.currentTimeMillis());
+
+ } else {
+ client.exhaustResponse(propfind.getResponseBodyAsStream());
+ result = new RemoteOperationResult(false, status, propfind.getResponseHeaders());
+ }
+ }
+
+ if (result == null) { // true if the server was not checked. nothing was wrong with the remote request
/// check changes in server and local file
boolean serverChanged = false;
- if (serverFile.getEtag() != null) {
- serverChanged = (!serverFile.getEtag().equals(localFile.getEtag()));
+ if (mServerFile.getEtag() != null) {
+ serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag())); // TODO could this be dangerous when the user upgrades the server from non-tagged to tagged?
} else {
// server without etags
- serverChanged = (serverFile.getModificationTimestamp() > localFile.getModificationTimestamp());
+ serverChanged = (mServerFile.getModificationTimestamp() > mLocalFile.getModificationTimestampAtLastSyncForData());
}
- boolean localChanged = (mLocalChangeAlreadyKnown || localFile.getLocalModificationTimestamp() > localFile.getLastSyncDateForData());
+ boolean localChanged = (mLocalChangeAlreadyKnown || mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData());
+ // TODO this will be always true after the app is upgraded to database version 2; will result in unnecessary uploads
/// decide action to perform depending upon changes
if (localChanged && serverChanged) {
- // conflict
result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
} else if (localChanged) {
if (mSyncFileContents) {
- requestForUpload(localFile);
+ requestForUpload(mLocalFile);
// the local update of file properties will be done by the FileUploader service when the upload finishes
} else {
// NOTHING TO DO HERE: updating the properties of the file in the server without uploading the contents would be stupid;
} else if (serverChanged) {
if (mSyncFileContents) {
- requestForDownload(serverFile);
+ requestForDownload(mLocalFile); // local, not server; we won't to keep the value of keepInSync!
// the update of local data will be done later by the FileUploader service when the upload finishes
} else {
// TODO CHECK: is this really useful in some point in the code?
- serverFile.setKeepInSync(localFile.keepInSync());
- serverFile.setParentId(localFile.getParentId());
- mStorageManager.saveFile(serverFile);
+ mServerFile.setKeepInSync(mLocalFile.keepInSync());
+ mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData());
+ mServerFile.setStoragePath(mLocalFile.getStoragePath());
+ mServerFile.setParentId(mLocalFile.getParentId());
+ mStorageManager.saveFile(mServerFile);
}
result = new RemoteOperationResult(ResultCode.OK);
result = new RemoteOperationResult(ResultCode.OK);
}
- } else {
- client.exhaustResponse(propfind.getResponseBodyAsStream());
- result = new RemoteOperationResult(false, status);
- }
+ }
}
- Log.i(TAG, "Synchronizing " + mAccount.name + ", file " + mRemotePath + ": " + result.getLogMessage());
+ Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
- Log.e(TAG, "Synchronizing " + mAccount.name + ", file " + mRemotePath + ": " + result.getLogMessage(), result.getException());
+ Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", file " + (mLocalFile != null ? mLocalFile.getRemotePath() : "NULL") + ": " + result.getLogMessage(), result.getException());
} finally {
if (propfind != null)
/**
* Requests for an upload to the FileUploader service
*
- * @param localFile OCFile object representing the file to upload
+ * @param file OCFile object representing the file to upload
*/
- private void requestForUpload(OCFile localFile) {
+ private void requestForUpload(OCFile file) {
Intent i = new Intent(mContext, FileUploader.class);
i.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
- i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath);
- i.putExtra(FileUploader.KEY_LOCAL_FILE, localFile.getStoragePath());
+ i.putExtra(FileUploader.KEY_FILE, file);
+ /*i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath); // doing this we would lose the value of keepInSync in the road, and maybe it's not updated in the database when the FileUploader service gets it!
+ i.putExtra(FileUploader.KEY_LOCAL_FILE, localFile.getStoragePath());*/
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
i.putExtra(FileUploader.KEY_FORCE_OVERWRITE, true);
mContext.startService(i);
file.setCreationTimestamp(we.createTimestamp());
file.setFileLength(we.contentLength());
file.setMimetype(we.contentType());
- file.setModificationTimestamp(we.modifiedTimesamp());
- file.setLastSyncDateForProperties(System.currentTimeMillis());
- file.setLastSyncDateForData(0);
+ file.setModificationTimestamp(we.modifiedTimestamp());
+ file.setEtag(we.etag());
+
return file;
}
return mTransferWasRequested;
}
+
+ public OCFile getLocalFile() {
+ return mLocalFile;
+ }
+
}