Fixed database update due to renaming folders

This commit is contained in:
David A. Velasco 2012-11-21 14:32:40 +01:00
parent 85e9a40dbe
commit d0b7df16e7
5 changed files with 125 additions and 26 deletions

View file

@ -42,4 +42,6 @@ public interface DataStorageManager {
public void removeFile(OCFile file, boolean removeLocalCopy); public void removeFile(OCFile file, boolean removeLocalCopy);
public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent); public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent);
public void moveDirectory(OCFile dir, String newPath);
} }

View file

@ -501,4 +501,75 @@ public class FileDataStorageManager implements DataStorageManager {
} }
} }
/**
* Updates database for a folder that was moved to a different location.
*
* TODO explore better (faster) implementations
* TODO throw exceptions up !
*/
@Override
public void moveDirectory(OCFile dir, String newPath) {
// TODO check newPath
if (dir != null && dir.isDirectory() && dir.fileExists() && !dir.getFileName().equals(OCFile.PATH_SEPARATOR)) {
/// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
Cursor c = null;
if (getContentProvider() != null) {
try {
c = getContentProvider().query(ProviderTableMeta.CONTENT_URI,
null,
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage());
}
} else {
c = getContentResolver().query(ProviderTableMeta.CONTENT_URI,
null,
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
}
/// 2. prepare a batch of update operations to change all the descendants
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
ContentValues cv = new ContentValues();
int lengthOfOldPath = dir.getRemotePath().length();
String defaultSavePath = FileDownloader.getSavePath(mAccount.name);
int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
if (c.moveToFirst()) {
do {
OCFile child = createFileInstance(c);
cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
}
operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
withValues(cv).
withSelection( ProviderTableMeta._ID + "=?",
new String[] { String.valueOf(child.getFileId()) })
.build());
} while (c.moveToNext());
}
c.close();
/// 3. apply updates in batch
try {
if (getContentResolver() != null) {
getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
} else {
getContentProvider().applyBatch(operations);
}
} catch (OperationApplicationException e) {
Log.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e);
} catch (RemoteException e) {
Log.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e);
}
}
}
} }

View file

@ -24,6 +24,7 @@ import java.io.IOException;
import org.apache.jackrabbit.webdav.client.methods.DavMethodBase; import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
//import org.apache.jackrabbit.webdav.client.methods.MoveMethod; //import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
import android.accounts.Account;
import android.util.Log; import android.util.Log;
import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.DataStorageManager;
@ -48,7 +49,9 @@ public class RenameFileOperation extends RemoteOperation {
private OCFile mFile; private OCFile mFile;
private Account mAccount;
private String mNewName; private String mNewName;
private String mNewRemotePath;
private DataStorageManager mStorageManager; private DataStorageManager mStorageManager;
@ -56,12 +59,15 @@ public class RenameFileOperation extends RemoteOperation {
* Constructor * Constructor
* *
* @param file OCFile instance describing the remote file or folder to rename * @param file OCFile instance describing the remote file or folder to rename
* @param account OwnCloud account containing the remote file
* @param newName New name to set as the name of file. * @param newName New name to set as the name of file.
* @param storageManager Reference to the local database corresponding to the account where the file is contained. * @param storageManager Reference to the local database corresponding to the account where the file is contained.
*/ */
public RenameFileOperation(OCFile file, String newName, DataStorageManager storageManager) { public RenameFileOperation(OCFile file, Account account, String newName, DataStorageManager storageManager) {
mFile = file; mFile = file;
mAccount = account;
mNewName = newName; mNewName = newName;
mNewRemotePath = null;
mStorageManager = storageManager; mStorageManager = storageManager;
} }
@ -80,7 +86,7 @@ public class RenameFileOperation extends RemoteOperation {
RemoteOperationResult result = null; RemoteOperationResult result = null;
LocalMoveMethod move = null; LocalMoveMethod move = null;
String newRemotePath = null; mNewRemotePath = null;
try { try {
if (mNewName.equals(mFile.getFileName())) { if (mNewName.equals(mFile.getFileName())) {
return new RemoteOperationResult(ResultCode.OK); return new RemoteOperationResult(ResultCode.OK);
@ -88,7 +94,10 @@ public class RenameFileOperation extends RemoteOperation {
String parent = (new File(mFile.getRemotePath())).getParent(); String parent = (new File(mFile.getRemotePath())).getParent();
parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR; parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR;
newRemotePath = parent + mNewName; mNewRemotePath = parent + mNewName;
if (mFile.isDirectory()) {
mNewRemotePath += OCFile.PATH_SEPARATOR;
}
// check if the new name is valid in the local file system // check if the new name is valid in the local file system
if (!isValidNewName()) { if (!isValidNewName()) {
@ -96,34 +105,22 @@ public class RenameFileOperation extends RemoteOperation {
} }
// check if a file with the new name already exists // check if a file with the new name already exists
if (client.existsFile(newRemotePath) || // remote check could fail by network failure, or by indeterminate behavior of HEAD for folders ... if (client.existsFile(mNewRemotePath) || // remote check could fail by network failure, or by indeterminate behavior of HEAD for folders ...
mStorageManager.getFileByPath(newRemotePath) != null) { // ... so local check is convenient mStorageManager.getFileByPath(mNewRemotePath) != null) { // ... so local check is convenient
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
} }
move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()), move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()),
client.getBaseUri() + WebdavUtils.encodePath(newRemotePath)); client.getBaseUri() + WebdavUtils.encodePath(mNewRemotePath));
int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT); int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
if (move.succeeded()) { if (move.succeeded()) {
// create new OCFile instance for the renamed file if (mFile.isDirectory()) {
/*OCFile newFile = new OCFile(mStorageManager.getFileById(mFile.getParentId()).getRemotePath() + mNewName; // TODO - NOT CREATE NEW OCFILE; ADD setFileName METHOD saveLocalDirectory();
OCFile oldFile = mFile;
mFile = newFile; */
mFile.setFileName(mNewName);
// try to rename the local copy of the file } else {
if (mFile.isDown()) { saveLocalFile();
File f = new File(mFile.getStoragePath());
String newStoragePath = f.getParent() + mNewName;
if (f.renameTo(new File(newStoragePath))) {
mFile.setStoragePath(newStoragePath);
}
// else - NOTHING: the link to the local file is kept although the local name can't be updated
// TODO - study conditions when this could be a problem
}
//mStorageManager.removeFile(oldFile, false); }
mStorageManager.saveFile(mFile);
/* /*
*} else if (mFile.isDirectory() && (status == 207 || status >= 500)) { *} else if (mFile.isDirectory() && (status == 207 || status >= 500)) {
@ -141,11 +138,11 @@ public class RenameFileOperation extends RemoteOperation {
move.getResponseBodyAsString(); // exhaust response, although not interesting move.getResponseBodyAsString(); // exhaust response, although not interesting
result = new RemoteOperationResult(move.succeeded(), status); result = new RemoteOperationResult(move.succeeded(), status);
Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + newRemotePath + ": " + result.getLogMessage()); Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage());
} catch (Exception e) { } catch (Exception e) {
result = new RemoteOperationResult(e); result = new RemoteOperationResult(e);
Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((newRemotePath==null) ? mNewName : newRemotePath) + ": " + result.getLogMessage(), e); Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e);
} finally { } finally {
if (move != null) if (move != null)
@ -155,6 +152,33 @@ public class RenameFileOperation extends RemoteOperation {
} }
private void saveLocalDirectory() {
mStorageManager.moveDirectory(mFile, mNewRemotePath);
String localPath = FileDownloader.getSavePath(mAccount.name) + mFile.getRemotePath();
File localDir = new File(localPath);
if (localDir.exists()) {
localDir.renameTo(new File(FileDownloader.getSavePath(mAccount.name) + mNewRemotePath));
// TODO - if renameTo fails, children files that are already down will result unlinked
}
}
private void saveLocalFile() {
mFile.setFileName(mNewName);
// try to rename the local copy of the file
if (mFile.isDown()) {
File f = new File(mFile.getStoragePath());
String newStoragePath = f.getParent() + mNewName;
if (f.renameTo(new File(newStoragePath))) {
mFile.setStoragePath(newStoragePath);
}
// else - NOTHING: the link to the local file is kept although the local name can't be updated
// TODO - study conditions when this could be a problem
}
mStorageManager.saveFile(mFile);
}
/** /**
* Checks if the new name to set is valid in the file system * Checks if the new name to set is valid in the file system
* *

View file

@ -829,6 +829,7 @@ public class FileDetailFragment extends SherlockFragment implements
String newFilename = dialog.getNewFilename(); String newFilename = dialog.getNewFilename();
Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);
mLastRemoteOperation = new RenameFileOperation( mFile, mLastRemoteOperation = new RenameFileOperation( mFile,
mAccount,
newFilename, newFilename,
new FileDataStorageManager(mAccount, getActivity().getContentResolver())); new FileDataStorageManager(mAccount, getActivity().getContentResolver()));
WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());

View file

@ -441,6 +441,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
String newFilename = dialog.getNewFilename(); String newFilename = dialog.getNewFilename();
Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);
RemoteOperation operation = new RenameFileOperation(mTargetFile, RemoteOperation operation = new RenameFileOperation(mTargetFile,
AccountUtils.getCurrentOwnCloudAccount(getActivity()),
newFilename, newFilename,
mContainerActivity.getStorageManager()); mContainerActivity.getStorageManager());
WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext()); WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());