diff --git a/oc_framework/src/com/owncloud/android/oc_framework/operations/remote/DownloadRemoteFileOperation.java b/oc_framework/src/com/owncloud/android/oc_framework/operations/remote/DownloadRemoteFileOperation.java index a2f951b433..e3e7ee0735 100644 --- a/oc_framework/src/com/owncloud/android/oc_framework/operations/remote/DownloadRemoteFileOperation.java +++ b/oc_framework/src/com/owncloud/android/oc_framework/operations/remote/DownloadRemoteFileOperation.java @@ -17,7 +17,28 @@ package com.owncloud.android.oc_framework.operations.remote; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.http.HttpStatus; + +import android.util.Log; + +import com.owncloud.android.oc_framework.network.webdav.OnDatatransferProgressListener; import com.owncloud.android.oc_framework.network.webdav.WebdavClient; +import com.owncloud.android.oc_framework.network.webdav.WebdavUtils; +import com.owncloud.android.oc_framework.operations.OperationCancelledException; +import com.owncloud.android.oc_framework.operations.RemoteFile; import com.owncloud.android.oc_framework.operations.RemoteOperation; import com.owncloud.android.oc_framework.operations.RemoteOperationResult; @@ -29,15 +50,120 @@ import com.owncloud.android.oc_framework.operations.RemoteOperationResult; */ public class DownloadRemoteFileOperation extends RemoteOperation { - - public DownloadRemoteFileOperation() { - // TODO Auto-generated constructor stub + + private static final String TAG = DownloadRemoteFileOperation.class.getSimpleName(); + + private Set mDataTransferListeners = new HashSet(); + private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false); + private long mModificationTimestamp = 0; + private GetMethod mGet; + + private RemoteFile mRemoteFile; + private String mTemporalFolder; + + public DownloadRemoteFileOperation(RemoteFile remoteFile, String temporalFolder) { + mRemoteFile = remoteFile; + mTemporalFolder = temporalFolder; } @Override protected RemoteOperationResult run(WebdavClient client) { - // TODO Auto-generated method stub - return null; + RemoteOperationResult result = null; + + /// download will be performed to a temporal file, then moved to the final location + File tmpFile = new File(getTmpPath()); + + /// perform the download + try { + tmpFile.getParentFile().mkdirs(); + int status = downloadFile(client, tmpFile); + result = new RemoteOperationResult(isSuccess(status), status, (mGet != null ? mGet.getResponseHeaders() : null)); + Log.i(TAG, "Download of " + mRemoteFile.getRemotePath() + " to " + getTmpPath() + ": " + result.getLogMessage()); + + } catch (Exception e) { + result = new RemoteOperationResult(e); + Log.e(TAG, "Download of " + mRemoteFile.getRemotePath() + " to " + getTmpPath() + ": " + result.getLogMessage(), e); + } + + return result; } + + protected int downloadFile(WebdavClient client, File targetFile) throws HttpException, IOException, OperationCancelledException { + int status = -1; + boolean savedFile = false; + mGet = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemoteFile.getRemotePath())); + Iterator it = null; + + FileOutputStream fos = null; + try { + status = client.executeMethod(mGet); + if (isSuccess(status)) { + targetFile.createNewFile(); + BufferedInputStream bis = new BufferedInputStream(mGet.getResponseBodyAsStream()); + fos = new FileOutputStream(targetFile); + long transferred = 0; + + byte[] bytes = new byte[4096]; + int readResult = 0; + while ((readResult = bis.read(bytes)) != -1) { + synchronized(mCancellationRequested) { + if (mCancellationRequested.get()) { + mGet.abort(); + throw new OperationCancelledException(); + } + } + fos.write(bytes, 0, readResult); + transferred += readResult; + synchronized (mDataTransferListeners) { + it = mDataTransferListeners.iterator(); + while (it.hasNext()) { + it.next().onTransferProgress(readResult, transferred, mRemoteFile.getLength(), targetFile.getName()); + } + } + } + savedFile = true; + Header modificationTime = mGet.getResponseHeader("Last-Modified"); + if (modificationTime != null) { + Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue()); + mModificationTimestamp = (d != null) ? d.getTime() : 0; + } + + } else { + client.exhaustResponse(mGet.getResponseBodyAsStream()); + } + + } finally { + if (fos != null) fos.close(); + if (!savedFile && targetFile.exists()) { + targetFile.delete(); + } + mGet.releaseConnection(); // let the connection available for other methods + } + return status; + } + + private boolean isSuccess(int status) { + return (status == HttpStatus.SC_OK); + } + + private String getTmpPath() { + return mTemporalFolder + mRemoteFile.getRemotePath(); + } + + public void addDatatransferProgressListener (OnDatatransferProgressListener listener) { + synchronized (mDataTransferListeners) { + mDataTransferListeners.add(listener); + } + } + + public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) { + synchronized (mDataTransferListeners) { + mDataTransferListeners.remove(listener); + } + } + + public void cancel() { + mCancellationRequested.set(true); // atomic set; there is no need of synchronizing it + } } diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index 232a042a5e..7a5d9a97d6 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -146,10 +146,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis AbstractList requestedDownloads = new Vector(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection) String downloadKey = buildRemoteName(account, file); try { - DownloadFileOperation newDownload = new DownloadFileOperation(account, file); + DownloadFileOperation newDownload = new DownloadFileOperation(account, file, (FileDownloaderBinder) mBinder); mPendingDownloads.putIfAbsent(downloadKey, newDownload); - newDownload.addDatatransferProgressListener(this); - newDownload.addDatatransferProgressListener((FileDownloaderBinder)mBinder); requestedDownloads.add(downloadKey); sendBroadcastNewDownload(newDownload); diff --git a/src/com/owncloud/android/operations/DownloadFileOperation.java b/src/com/owncloud/android/operations/DownloadFileOperation.java index eb45d4ba05..fbd9f66d1a 100644 --- a/src/com/owncloud/android/operations/DownloadFileOperation.java +++ b/src/com/owncloud/android/operations/DownloadFileOperation.java @@ -17,28 +17,15 @@ package com.owncloud.android.operations; -import java.io.BufferedInputStream; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.http.HttpStatus; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.oc_framework.network.webdav.OnDatatransferProgressListener; import com.owncloud.android.oc_framework.network.webdav.WebdavClient; -import com.owncloud.android.oc_framework.network.webdav.WebdavUtils; -import com.owncloud.android.oc_framework.operations.OperationCancelledException; +import com.owncloud.android.oc_framework.operations.RemoteFile; import com.owncloud.android.oc_framework.operations.RemoteOperation; import com.owncloud.android.oc_framework.operations.RemoteOperationResult; +import com.owncloud.android.oc_framework.operations.remote.DownloadRemoteFileOperation; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.Log_OC; @@ -46,9 +33,10 @@ import android.accounts.Account; import android.webkit.MimeTypeMap; /** - * Remote operation performing the download of a file to an ownCloud server + * Remote mDownloadOperation performing the download of a file to an ownCloud server * * @author David A. Velasco + * @author masensio */ public class DownloadFileOperation extends RemoteOperation { @@ -56,13 +44,13 @@ public class DownloadFileOperation extends RemoteOperation { private Account mAccount; private OCFile mFile; - private Set mDataTransferListeners = new HashSet(); - private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false); + private OnDatatransferProgressListener mDatatransferProgressListener; private long mModificationTimestamp = 0; - private GetMethod mGet; + + private DownloadRemoteFileOperation mDownloadOperation; - public DownloadFileOperation(Account account, OCFile file) { + public DownloadFileOperation(Account account, OCFile file, OnDatatransferProgressListener listener) { if (account == null) throw new IllegalArgumentException("Illegal null account in DownloadFileOperation creation"); if (file == null) @@ -70,6 +58,8 @@ public class DownloadFileOperation extends RemoteOperation { mAccount = account; mFile = file; + + mDatatransferProgressListener = listener; } @@ -93,6 +83,10 @@ public class DownloadFileOperation extends RemoteOperation { return FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); } + public String getTmpFolder() { + return FileStorageUtils.getTemporalPath(mAccount.name); + } + public String getRemotePath() { return mFile.getRemotePath(); } @@ -121,19 +115,6 @@ public class DownloadFileOperation extends RemoteOperation { public long getModificationTimestamp() { return (mModificationTimestamp > 0) ? mModificationTimestamp : mFile.getModificationTimestamp(); } - - - public void addDatatransferProgressListener (OnDatatransferProgressListener listener) { - synchronized (mDataTransferListeners) { - mDataTransferListeners.add(listener); - } - } - - public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) { - synchronized (mDataTransferListeners) { - mDataTransferListeners.remove(listener); - } - } @Override protected RemoteOperationResult run(WebdavClient client) { @@ -144,92 +125,30 @@ public class DownloadFileOperation extends RemoteOperation { /// download will be performed to a temporal file, then moved to the final location File tmpFile = new File(getTmpPath()); + String tmpFolder = getTmpFolder(); + RemoteFile remoteFile = FileStorageUtils.fillRemoteFile(mFile); + /// perform the download - try { - tmpFile.getParentFile().mkdirs(); - int status = downloadFile(client, tmpFile); - if (isSuccess(status)) { - newFile = new File(getSavePath()); - newFile.getParentFile().mkdirs(); - moved = tmpFile.renameTo(newFile); - } + mDownloadOperation = new DownloadRemoteFileOperation(remoteFile, tmpFolder); + mDownloadOperation.addDatatransferProgressListener(mDatatransferProgressListener); + result = mDownloadOperation.execute(client); + + if (result.isSuccess()) { + newFile = new File(getSavePath()); + newFile.getParentFile().mkdirs(); + moved = tmpFile.renameTo(newFile); + if (!moved) result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED); - else - result = new RemoteOperationResult(isSuccess(status), status, (mGet != null ? mGet.getResponseHeaders() : null)); - Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage()); - - } catch (Exception e) { - result = new RemoteOperationResult(e); - Log_OC.e(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage(), e); } + Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage()); + return result; } - - public boolean isSuccess(int status) { - return (status == HttpStatus.SC_OK); - } - - - protected int downloadFile(WebdavClient client, File targetFile) throws HttpException, IOException, OperationCancelledException { - int status = -1; - boolean savedFile = false; - mGet = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath())); - Iterator it = null; - - FileOutputStream fos = null; - try { - status = client.executeMethod(mGet); - if (isSuccess(status)) { - targetFile.createNewFile(); - BufferedInputStream bis = new BufferedInputStream(mGet.getResponseBodyAsStream()); - fos = new FileOutputStream(targetFile); - long transferred = 0; - - byte[] bytes = new byte[4096]; - int readResult = 0; - while ((readResult = bis.read(bytes)) != -1) { - synchronized(mCancellationRequested) { - if (mCancellationRequested.get()) { - mGet.abort(); - throw new OperationCancelledException(); - } - } - fos.write(bytes, 0, readResult); - transferred += readResult; - synchronized (mDataTransferListeners) { - it = mDataTransferListeners.iterator(); - while (it.hasNext()) { - it.next().onTransferProgress(readResult, transferred, mFile.getFileLength(), targetFile.getName()); - } - } - } - savedFile = true; - Header modificationTime = mGet.getResponseHeader("Last-Modified"); - if (modificationTime != null) { - Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue()); - mModificationTimestamp = (d != null) ? d.getTime() : 0; - } - - } else { - client.exhaustResponse(mGet.getResponseBodyAsStream()); - } - - } finally { - if (fos != null) fos.close(); - if (!savedFile && targetFile.exists()) { - targetFile.delete(); - } - mGet.releaseConnection(); // let the connection available for other methods - } - return status; - } - - public void cancel() { - mCancellationRequested.set(true); // atomic set; there is no need of synchronizing it + mDownloadOperation.cancel(); } diff --git a/src/com/owncloud/android/utils/FileStorageUtils.java b/src/com/owncloud/android/utils/FileStorageUtils.java index 2520644319..16812c6530 100644 --- a/src/com/owncloud/android/utils/FileStorageUtils.java +++ b/src/com/owncloud/android/utils/FileStorageUtils.java @@ -22,6 +22,7 @@ import java.io.File; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.oc_framework.operations.RemoteFile; import android.annotation.SuppressLint; import android.content.Context; @@ -82,5 +83,22 @@ public class FileStorageUtils { parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR; return parentPath; } + + + /** + * Creates and populates a new {@link RemoteFile} object with the data read from an {@link OCFile}. + * + * @param oCFile OCFile + * @return New RemoteFile instance representing the resource described by ocFile. + */ + public static RemoteFile fillRemoteFile(OCFile ocFile){ + RemoteFile file = new RemoteFile(ocFile.getRemotePath()); + file.setCreationTimestamp(ocFile.getCreationTimestamp()); + file.setLength(ocFile.getFileLength()); + file.setMimeType(ocFile.getMimetype()); + file.setModifiedTimestamp(ocFile.getModificationTimestamp()); + file.setEtag(ocFile.getEtag()); + return file; + } } \ No newline at end of file