-/* ownCloud Android client application
- * Copyright (C) 2012 Bartek Przybylski
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2015 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 java.io.File;
import java.io.IOException;
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
-//import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
-
-import android.util.Log;
-
-import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileDownloader;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.utils.FileStorageUtils;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
/**
* Remote operation performing the rename of a remote file (or folder?) in the ownCloud server.
- *
- * @author David A. Velasco
*/
-public class RenameFileOperation extends RemoteOperation {
+public class RenameFileOperation extends SyncOperation {
- private static final String TAG = RemoveFileOperation.class.getSimpleName();
-
- private static final int RENAME_READ_TIMEOUT = 10000;
- private static final int RENAME_CONNECTION_TIMEOUT = 5000;
+ private static final String TAG = RenameFileOperation.class.getSimpleName();
-
private OCFile mFile;
+ private String mRemotePath;
private String mNewName;
- private DataStorageManager mStorageManager;
+ private String mNewRemotePath;
+
/**
* Constructor
*
- * @param file OCFile instance describing the remote file or folder to rename
+ * @param remotePath RemotePath of the OCFile instance describing the remote file or
+ * folder to rename
* @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.
*/
- public RenameFileOperation(OCFile file, String newName, DataStorageManager storageManager) {
- mFile = file;
+ public RenameFileOperation(String remotePath, String newName) {
+ mRemotePath = remotePath;
mNewName = newName;
- mStorageManager = storageManager;
+ mNewRemotePath = null;
}
public OCFile getFile() {
* @param client Client object to communicate with the remote ownCloud server.
*/
@Override
- protected RemoteOperationResult run(WebdavClient client) {
+ protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
- LocalMoveMethod move = null;
- //MoveMethod move = null; // TODO find out why not use this
- String newRemotePath = null;
- try {
- if (mNewName.equals(mFile.getFileName())) {
- return new RemoteOperationResult(ResultCode.OK);
- }
+ mFile = getStorageManager().getFileByPath(mRemotePath);
- newRemotePath = (new File(mFile.getRemotePath())).getParent() + mNewName;
-
- // check if the new name is valid in the local file system
+ // check if the new name is valid in the local file system
+ try {
if (!isValidNewName()) {
return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME);
}
-
- // check if a remote file with the new name already exists
- if (client.existsFile(newRemotePath)) {
- return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
+ String parent = (new File(mFile.getRemotePath())).getParent();
+ parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent +
+ OCFile.PATH_SEPARATOR;
+ mNewRemotePath = parent + mNewName;
+ if (mFile.isFolder()) {
+ mNewRemotePath += OCFile.PATH_SEPARATOR;
}
- /*move = new MoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()),
- client.getBaseUri() + WebdavUtils.encodePath(newRemotePath),
- false);*/
- move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()),
- client.getBaseUri() + WebdavUtils.encodePath(newRemotePath));
- int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
- if (move.succeeded()) {
- // create new OCFile instance for the renamed file
- OCFile newFile = obtainUpdatedFile();
- OCFile oldFile = mFile;
- mFile = newFile;
-
- // try to rename the local copy of the file
- if (oldFile.isDown()) {
- File f = new File(oldFile.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);
-
+ // check local overwrite
+ if (getStorageManager().getFileByPath(mNewRemotePath) != null) {
+ return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
}
- move.getResponseBodyAsString(); // exhaust response, although not interesting
- result = new RemoteOperationResult(move.succeeded(), status);
- Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + newRemotePath + ": " + result.getLogMessage());
-
- } catch (Exception e) {
- result = new RemoteOperationResult(e);
- Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((newRemotePath==null) ? mNewName : newRemotePath) + ": " + result.getLogMessage(), e);
+ RenameRemoteFileOperation operation = new RenameRemoteFileOperation(mFile.getFileName(),
+ mFile.getRemotePath(),
+ mNewName, mFile.isFolder());
+ result = operation.execute(client);
+
+ if (result.isSuccess()) {
+ if (mFile.isFolder()) {
+ getStorageManager().moveLocalFile(mFile, mNewRemotePath, parent);
+ //saveLocalDirectory();
+
+ } else {
+ saveLocalFile();
+ }
+ }
- } finally {
- if (move != null)
- move.releaseConnection();
+ } catch (IOException e) {
+ Log_OC.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ?
+ mNewName : mNewRemotePath) + ": " +
+ ((result!= null) ? result.getLogMessage() : ""), e);
}
+
return result;
}
-
+ private void saveLocalFile() {
+ mFile.setFileName(mNewName);
+
+ // try to rename the local copy of the file
+ if (mFile.isDown()) {
+ String oldPath = mFile.getStoragePath();
+ File f = new File(oldPath);
+ String parentStoragePath = f.getParent();
+ if (!parentStoragePath.endsWith(File.separator))
+ parentStoragePath += File.separator;
+ if (f.renameTo(new File(parentStoragePath + mNewName))) {
+ String newPath = parentStoragePath + mNewName;
+ mFile.setStoragePath(newPath);
+
+ // notify MediaScanner about removed file
+ getStorageManager().deleteFileInMediaScan(oldPath);
+ // notify to scan about new file
+ getStorageManager().triggerMediaScan(newPath);
+ }
+ // 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
+ }
+
+ getStorageManager().saveFile(mFile);
+ }
+
/**
* Checks if the new name to set is valid in the file system
*
- * The only way to be sure is trying to create a file with that name. It's made in the temporal directory
- * for downloads, out of any account, and then removed.
+ * The only way to be sure is trying to create a file with that name. It's made in the
+ * temporal directory for downloads, out of any account, and then removed.
*
- * IMPORTANT: The test must be made in the same file system where files are download. The internal storage
- * could be formatted with a different file system.
+ * IMPORTANT: The test must be made in the same file system where files are download.
+ * The internal storage could be formatted with a different file system.
*
- * @return 'True' if a temporal file named with the name to set could be created in the file system where
- * local files are stored.
+ * TODO move this method, and maybe FileDownload.get***Path(), to a class with utilities
+ * specific for the interactions with the file system
+ *
+ * @return 'True' if a temporal file named with the name to set could be
+ * created in the file system where local files are stored.
+ * @throws IOException When the temporal folder can not be created.
*/
- private boolean isValidNewName() {
+ private boolean isValidNewName() throws IOException {
// check tricky names
- if (mNewName == null || mNewName.length() <= 0 || mNewName.contains(File.separator)) {
+ if (mNewName == null || mNewName.length() <= 0 || mNewName.contains(File.separator)) {
return false;
}
// create a test file
- String tmpFolder = FileDownloader.getTemporalPath("");
- File testFile = new File(tmpFolder + mNewName);
+ String tmpFolderName = FileStorageUtils.getTemporalPath("");
+ File testFile = new File(tmpFolderName + mNewName);
+ File tmpFolder = testFile.getParentFile();
+ tmpFolder.mkdirs();
+ if (!tmpFolder.isDirectory()) {
+ throw new IOException("Unexpected error: temporal directory could not be created");
+ }
try {
- testFile.createNewFile(); // return value is ignored; it could be 'false' because the file already existed, that doesn't invalidate the name
+ testFile.createNewFile(); // return value is ignored; it could be 'false' because
+ // the file already existed, that doesn't invalidate the name
} catch (IOException e) {
- Log.i(TAG, "Test for validity of name " + mNewName + " in the file system failed");
+ Log_OC.i(TAG, "Test for validity of name " + mNewName + " in the file system failed");
return false;
}
boolean result = (testFile.exists() && testFile.isFile());
- // cleaning ; result is ignored, since there is not much we could do in case of failure, but repeat and repeat...
+ // cleaning ; result is ignored, since there is not much we could do in case of failure,
+ // but repeat and repeat...
testFile.delete();
return result;
}
-
- /**
- * Creates a new OCFile for the new remote name of the renamed file.
- *
- * @return OCFile object with the same information than mFile, but the renamed remoteFile and the storagePath (empty)
- */
- private OCFile obtainUpdatedFile() {
- OCFile file = new OCFile(mStorageManager.getFileById(mFile.getParentId()).getRemotePath() + mNewName);
- file.setCreationTimestamp(mFile.getCreationTimestamp());
- file.setFileId(mFile.getFileId());
- file.setFileLength(mFile.getFileLength());
- file.setKeepInSync(mFile.keepInSync());
- file.setLastSyncDate(mFile.getLastSyncDate());
- file.setMimetype(mFile.getMimetype());
- file.setModificationTimestamp(mFile.getModificationTimestamp());
- file.setParentId(mFile.getParentId());
- return file;
- }
-
-
- // move operation - TODO: find out why org.apache.jackrabbit.webdav.client.methods.MoveMethod is not used instead ¿?
- private class LocalMoveMethod extends DavMethodBase {
-
- public LocalMoveMethod(String uri, String dest) {
- super(uri);
- addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest));
- }
-
- @Override
- public String getName() {
- return "MOVE";
- }
-
- @Override
- protected boolean isSuccess(int status) {
- return status == 201 || status == 204;
- }
-
- }
-
-
}