mirror of
https://github.com/owncloud/android-library.git
synced 2025-06-07 16:06:08 +00:00
Merge pull request #83 from owncloud/sync_full_folder
Minor changes to support synchronization of full folders in OC app
This commit is contained in:
commit
f02dffb1d3
@ -129,7 +129,7 @@ public class WebdavEntry {
|
|||||||
prop = propSet.get(DavPropertyName.GETETAG);
|
prop = propSet.get(DavPropertyName.GETETAG);
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
mEtag = (String) prop.getValue();
|
mEtag = (String) prop.getValue();
|
||||||
mEtag = mEtag.substring(1, mEtag.length()-1);
|
mEtag = WebdavUtils.parseEtag(mEtag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// {DAV:}quota-used-bytes
|
// {DAV:}quota-used-bytes
|
||||||
|
@ -32,6 +32,8 @@ import java.util.Locale;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import org.apache.commons.httpclient.Header;
|
||||||
|
import org.apache.commons.httpclient.HttpMethod;
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
|
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
|
||||||
import org.apache.jackrabbit.webdav.xml.Namespace;
|
import org.apache.jackrabbit.webdav.xml.Namespace;
|
||||||
@ -131,4 +133,47 @@ public class WebdavUtils {
|
|||||||
|
|
||||||
return propSet;
|
return propSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param rawEtag
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String parseEtag(String rawEtag) {
|
||||||
|
if (rawEtag == null || rawEtag.length() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (rawEtag.endsWith("-gzip")) {
|
||||||
|
rawEtag = rawEtag.substring(0, rawEtag.length() - 5);
|
||||||
|
}
|
||||||
|
if (rawEtag.length() >= 2 && rawEtag.startsWith("\"") && rawEtag.endsWith("\"")) {
|
||||||
|
rawEtag = rawEtag.substring(1, rawEtag.length() - 1);
|
||||||
|
}
|
||||||
|
return rawEtag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param method
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getEtagFromResponse(HttpMethod method) {
|
||||||
|
Header eTag = method.getResponseHeader("OC-ETag");
|
||||||
|
if (eTag == null) {
|
||||||
|
eTag = method.getResponseHeader("oc-etag");
|
||||||
|
}
|
||||||
|
if (eTag == null) {
|
||||||
|
eTag = method.getResponseHeader("ETag");
|
||||||
|
}
|
||||||
|
if (eTag == null) {
|
||||||
|
eTag = method.getResponseHeader("etag");
|
||||||
|
}
|
||||||
|
String result = "";
|
||||||
|
if (eTag != null) {
|
||||||
|
result = parseEtag(eTag.getValue());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -390,11 +390,16 @@ public class RemoteOperationResult implements Serializable {
|
|||||||
|
|
||||||
} else if (mCode == ResultCode.ACCOUNT_NOT_THE_SAME) {
|
} else if (mCode == ResultCode.ACCOUNT_NOT_THE_SAME) {
|
||||||
return "Authenticated with a different account than the one updating";
|
return "Authenticated with a different account than the one updating";
|
||||||
|
|
||||||
} else if (mCode == ResultCode.INVALID_CHARACTER_IN_NAME) {
|
} else if (mCode == ResultCode.INVALID_CHARACTER_IN_NAME) {
|
||||||
return "The file name contains an forbidden character";
|
return "The file name contains an forbidden character";
|
||||||
|
|
||||||
} else if (mCode == ResultCode.FILE_NOT_FOUND) {
|
} else if (mCode == ResultCode.FILE_NOT_FOUND) {
|
||||||
return "Local file does not exist";
|
return "Local file does not exist";
|
||||||
}
|
|
||||||
|
} else if (mCode == ResultCode.SYNC_CONFLICT) {
|
||||||
|
return "Synchronization conflict";
|
||||||
|
}
|
||||||
|
|
||||||
return "Operation finished with HTTP status code " + mHttpCode + " (" +
|
return "Operation finished with HTTP status code " + mHttpCode + " (" +
|
||||||
(isSuccess() ? "success" : "fail") + ")";
|
(isSuccess() ? "success" : "fail") + ")";
|
||||||
|
@ -32,8 +32,7 @@ public class Log_OC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void i(String TAG, String message){
|
public static void i(String TAG, String message){
|
||||||
|
Log.i(TAG, message);
|
||||||
// Write the log message to the file
|
|
||||||
appendLog(TAG+" : "+ message);
|
appendLog(TAG+" : "+ message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ import java.io.RandomAccessFile;
|
|||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.methods.PutMethod;
|
import org.apache.commons.httpclient.methods.PutMethod;
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||||
@ -47,14 +46,21 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
|
|||||||
|
|
||||||
public static final long CHUNK_SIZE = 1024000;
|
public static final long CHUNK_SIZE = 1024000;
|
||||||
private static final String OC_CHUNKED_HEADER = "OC-Chunked";
|
private static final String OC_CHUNKED_HEADER = "OC-Chunked";
|
||||||
|
private static final String OC_CHUNK_SIZE_HEADER = "OC-Chunk-Size";
|
||||||
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
|
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
|
||||||
|
|
||||||
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType){
|
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType){
|
||||||
super(storagePath, remotePath, mimeType);
|
super(storagePath, remotePath, mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkedUploadRemoteFileOperation(
|
||||||
|
String storagePath, String remotePath, String mimeType, String requiredEtag
|
||||||
|
){
|
||||||
|
super(storagePath, remotePath, mimeType, requiredEtag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int uploadFile(OwnCloudClient client) throws HttpException, IOException {
|
protected int uploadFile(OwnCloudClient client) throws IOException {
|
||||||
int status = -1;
|
int status = -1;
|
||||||
|
|
||||||
FileChannel channel = null;
|
FileChannel channel = null;
|
||||||
@ -64,8 +70,6 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
|
|||||||
raf = new RandomAccessFile(file, "r");
|
raf = new RandomAccessFile(file, "r");
|
||||||
channel = raf.getChannel();
|
channel = raf.getChannel();
|
||||||
mEntity = new ChunkFromFileChannelRequestEntity(channel, mMimeType, CHUNK_SIZE, file);
|
mEntity = new ChunkFromFileChannelRequestEntity(channel, mMimeType, CHUNK_SIZE, file);
|
||||||
//((ProgressiveDataTransferer)mEntity).
|
|
||||||
// addDatatransferProgressListeners(getDataTransferListeners());
|
|
||||||
synchronized (mDataTransferListeners) {
|
synchronized (mDataTransferListeners) {
|
||||||
((ProgressiveDataTransferer)mEntity)
|
((ProgressiveDataTransferer)mEntity)
|
||||||
.addDatatransferProgressListeners(mDataTransferListeners);
|
.addDatatransferProgressListeners(mDataTransferListeners);
|
||||||
@ -74,17 +78,31 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
|
|||||||
long offset = 0;
|
long offset = 0;
|
||||||
String uriPrefix = client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath) +
|
String uriPrefix = client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath) +
|
||||||
"-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
|
"-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
|
||||||
long chunkCount = (long) Math.ceil((double)file.length() / CHUNK_SIZE);
|
long totalLength = file.length();
|
||||||
|
long chunkCount = (long) Math.ceil((double)totalLength / CHUNK_SIZE);
|
||||||
|
String chunkSizeStr = String.valueOf(CHUNK_SIZE);
|
||||||
|
String totalLengthStr = String.valueOf(file.length());
|
||||||
for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
|
for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
|
||||||
|
if (chunkIndex == chunkCount - 1) {
|
||||||
|
chunkSizeStr = String.valueOf(CHUNK_SIZE * chunkCount - totalLength);
|
||||||
|
}
|
||||||
if (mPutMethod != null) {
|
if (mPutMethod != null) {
|
||||||
mPutMethod.releaseConnection(); // let the connection available
|
mPutMethod.releaseConnection(); // let the connection available
|
||||||
// for other methods
|
// for other methods
|
||||||
}
|
}
|
||||||
mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
|
mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
|
||||||
|
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
|
||||||
|
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
|
||||||
|
}
|
||||||
mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
|
mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
|
||||||
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(file.length()));
|
mPutMethod.addRequestHeader(OC_CHUNK_SIZE_HEADER, chunkSizeStr);
|
||||||
|
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, totalLengthStr);
|
||||||
((ChunkFromFileChannelRequestEntity) mEntity).setOffset(offset);
|
((ChunkFromFileChannelRequestEntity) mEntity).setOffset(offset);
|
||||||
mPutMethod.setRequestEntity(mEntity);
|
mPutMethod.setRequestEntity(mEntity);
|
||||||
|
if (mCancellationRequested.get()) {
|
||||||
|
mPutMethod.abort();
|
||||||
|
// next method will throw an exception
|
||||||
|
}
|
||||||
status = client.executeMethod(mPutMethod);
|
status = client.executeMethod(mPutMethod);
|
||||||
|
|
||||||
if (status == 400) {
|
if (status == 400) {
|
||||||
|
@ -61,6 +61,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
|
|||||||
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
||||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||||
private long mModificationTimestamp = 0;
|
private long mModificationTimestamp = 0;
|
||||||
|
private String mEtag = "";
|
||||||
private GetMethod mGet;
|
private GetMethod mGet;
|
||||||
|
|
||||||
private String mRemotePath;
|
private String mRemotePath;
|
||||||
@ -140,12 +141,24 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
|
|||||||
if (transferred == totalToTransfer) { // Check if the file is completed
|
if (transferred == totalToTransfer) { // Check if the file is completed
|
||||||
savedFile = true;
|
savedFile = true;
|
||||||
Header modificationTime = mGet.getResponseHeader("Last-Modified");
|
Header modificationTime = mGet.getResponseHeader("Last-Modified");
|
||||||
|
if (modificationTime == null) {
|
||||||
|
modificationTime = mGet.getResponseHeader("last-modified");
|
||||||
|
}
|
||||||
if (modificationTime != null) {
|
if (modificationTime != null) {
|
||||||
Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
|
Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
|
||||||
mModificationTimestamp = (d != null) ? d.getTime() : 0;
|
mModificationTimestamp = (d != null) ? d.getTime() : 0;
|
||||||
}
|
} else {
|
||||||
|
Log_OC.e(TAG, "Could not read modification time from response downloading " + mRemotePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
mEtag = WebdavUtils.getEtagFromResponse(mGet);
|
||||||
|
if (mEtag.length() == 0) {
|
||||||
|
Log_OC.e(TAG, "Could not read eTag from response downloading " + mRemotePath);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
client.exhaustResponse(mGet.getResponseBodyAsStream());
|
client.exhaustResponse(mGet.getResponseBodyAsStream());
|
||||||
|
// TODO some kind of error control!
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -190,4 +203,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
|
|||||||
return mModificationTimestamp;
|
return mModificationTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEtag() {
|
||||||
|
return mEtag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import java.util.HashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.methods.PutMethod;
|
import org.apache.commons.httpclient.methods.PutMethod;
|
||||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
import org.apache.commons.httpclient.methods.RequestEntity;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
@ -60,14 +59,16 @@ public class UploadRemoteFileOperation extends RemoteOperation {
|
|||||||
private static final String TAG = UploadRemoteFileOperation.class.getSimpleName();
|
private static final String TAG = UploadRemoteFileOperation.class.getSimpleName();
|
||||||
|
|
||||||
protected static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
|
protected static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
|
||||||
|
protected static final String IF_MATCH_HEADER = "If-Match";
|
||||||
|
|
||||||
protected String mLocalPath;
|
protected String mLocalPath;
|
||||||
protected String mRemotePath;
|
protected String mRemotePath;
|
||||||
protected String mMimeType;
|
protected String mMimeType;
|
||||||
protected PutMethod mPutMethod = null;
|
protected PutMethod mPutMethod = null;
|
||||||
protected boolean mForbiddenCharsInServer = false;
|
protected boolean mForbiddenCharsInServer = false;
|
||||||
|
protected String mRequiredEtag = null;
|
||||||
|
|
||||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||||
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
||||||
|
|
||||||
protected RequestEntity mEntity = null;
|
protected RequestEntity mEntity = null;
|
||||||
@ -75,7 +76,12 @@ public class UploadRemoteFileOperation extends RemoteOperation {
|
|||||||
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType) {
|
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType) {
|
||||||
mLocalPath = localPath;
|
mLocalPath = localPath;
|
||||||
mRemotePath = remotePath;
|
mRemotePath = remotePath;
|
||||||
mMimeType = mimeType;
|
mMimeType = mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType, String requiredEtag) {
|
||||||
|
this(localPath, remotePath, mimeType);
|
||||||
|
mRequiredEtag = requiredEtag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -83,28 +89,28 @@ public class UploadRemoteFileOperation extends RemoteOperation {
|
|||||||
RemoteOperationResult result = null;
|
RemoteOperationResult result = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// / perform the upload
|
mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
|
||||||
synchronized (mCancellationRequested) {
|
|
||||||
if (mCancellationRequested.get()) {
|
if (mCancellationRequested.get()) {
|
||||||
throw new OperationCancelledException();
|
// the operation was cancelled before getting it's turn to be executed in the queue of uploads
|
||||||
|
result = new RemoteOperationResult(new OperationCancelledException());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// perform the upload
|
||||||
|
int status = uploadFile(client);
|
||||||
|
if (mForbiddenCharsInServer){
|
||||||
|
result = new RemoteOperationResult(
|
||||||
|
RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
|
||||||
} else {
|
} else {
|
||||||
mPutMethod = new PutMethod(client.getWebdavUri() +
|
result = new RemoteOperationResult(isSuccess(status), status,
|
||||||
WebdavUtils.encodePath(mRemotePath));
|
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int status = uploadFile(client);
|
|
||||||
if (mForbiddenCharsInServer){
|
|
||||||
result = new RemoteOperationResult(
|
|
||||||
RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
|
|
||||||
} else {
|
|
||||||
result = new RemoteOperationResult(isSuccess(status), status,
|
|
||||||
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO something cleaner with cancellations
|
if (mPutMethod != null && mPutMethod.isAborted()) {
|
||||||
if (mCancellationRequested.get()) {
|
|
||||||
result = new RemoteOperationResult(new OperationCancelledException());
|
result = new RemoteOperationResult(new OperationCancelledException());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
result = new RemoteOperationResult(e);
|
result = new RemoteOperationResult(e);
|
||||||
}
|
}
|
||||||
@ -117,8 +123,7 @@ public class UploadRemoteFileOperation extends RemoteOperation {
|
|||||||
status == HttpStatus.SC_NO_CONTENT));
|
status == HttpStatus.SC_NO_CONTENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int uploadFile(OwnCloudClient client) throws HttpException, IOException,
|
protected int uploadFile(OwnCloudClient client) throws IOException {
|
||||||
OperationCancelledException {
|
|
||||||
int status = -1;
|
int status = -1;
|
||||||
try {
|
try {
|
||||||
File f = new File(mLocalPath);
|
File f = new File(mLocalPath);
|
||||||
@ -127,6 +132,9 @@ public class UploadRemoteFileOperation extends RemoteOperation {
|
|||||||
((ProgressiveDataTransferer)mEntity)
|
((ProgressiveDataTransferer)mEntity)
|
||||||
.addDatatransferProgressListeners(mDataTransferListeners);
|
.addDatatransferProgressListeners(mDataTransferListeners);
|
||||||
}
|
}
|
||||||
|
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
|
||||||
|
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
|
||||||
|
}
|
||||||
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(f.length()));
|
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(f.length()));
|
||||||
mPutMethod.setRequestEntity(mEntity);
|
mPutMethod.setRequestEntity(mEntity);
|
||||||
status = client.executeMethod(mPutMethod);
|
status = client.executeMethod(mPutMethod);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user