1 /* ownCloud Android Library is available under MIT license
2 * Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 package com
.owncloud
.android
.lib
.operations
.remote
;
27 import java
.io
.BufferedInputStream
;
29 import java
.io
.FileOutputStream
;
30 import java
.io
.IOException
;
31 import java
.util
.HashSet
;
32 import java
.util
.Iterator
;
34 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
36 import org
.apache
.commons
.httpclient
.Header
;
37 import org
.apache
.commons
.httpclient
.HttpException
;
38 import org
.apache
.commons
.httpclient
.methods
.GetMethod
;
39 import org
.apache
.http
.HttpStatus
;
41 import android
.util
.Log
;
43 import com
.owncloud
.android
.lib
.network
.OnDatatransferProgressListener
;
44 import com
.owncloud
.android
.lib
.network
.OwnCloudClient
;
45 import com
.owncloud
.android
.lib
.network
.webdav
.WebdavUtils
;
46 import com
.owncloud
.android
.lib
.operations
.common
.OperationCancelledException
;
47 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperation
;
48 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperationResult
;
51 * Remote operation performing the download of a remote file in the ownCloud server.
53 * @author David A. Velasco
57 public class DownloadRemoteFileOperation
extends RemoteOperation
{
59 private static final String TAG
= DownloadRemoteFileOperation
.class.getSimpleName();
61 private Set
<OnDatatransferProgressListener
> mDataTransferListeners
= new HashSet
<OnDatatransferProgressListener
>();
62 private final AtomicBoolean mCancellationRequested
= new AtomicBoolean(false
);
63 //private long mModificationTimestamp = 0;
64 private GetMethod mGet
;
66 private String mRemotePath
;
67 private String mDownloadFolderPath
;
69 public DownloadRemoteFileOperation(String remotePath
, String downloadFolderPath
) {
70 mRemotePath
= remotePath
;
71 mDownloadFolderPath
= downloadFolderPath
;
75 protected RemoteOperationResult
run(OwnCloudClient client
) {
76 RemoteOperationResult result
= null
;
78 /// download will be performed to a temporal file, then moved to the final location
79 File tmpFile
= new File(getTmpPath());
81 /// perform the download
83 tmpFile
.getParentFile().mkdirs();
84 int status
= downloadFile(client
, tmpFile
);
85 result
= new RemoteOperationResult(isSuccess(status
), status
, (mGet
!= null ? mGet
.getResponseHeaders() : null
));
86 Log
.i(TAG
, "Download of " + mRemotePath
+ " to " + getTmpPath() + ": " + result
.getLogMessage());
88 } catch (Exception e
) {
89 result
= new RemoteOperationResult(e
);
90 Log
.e(TAG
, "Download of " + mRemotePath
+ " to " + getTmpPath() + ": " + result
.getLogMessage(), e
);
97 protected int downloadFile(OwnCloudClient client
, File targetFile
) throws HttpException
, IOException
, OperationCancelledException
{
99 boolean savedFile
= false
;
100 mGet
= new GetMethod(client
.getBaseUri() + WebdavUtils
.encodePath(mRemotePath
));
101 Iterator
<OnDatatransferProgressListener
> it
= null
;
103 FileOutputStream fos
= null
;
105 status
= client
.executeMethod(mGet
);
106 if (isSuccess(status
)) {
107 targetFile
.createNewFile();
108 BufferedInputStream bis
= new BufferedInputStream(mGet
.getResponseBodyAsStream());
109 fos
= new FileOutputStream(targetFile
);
110 long transferred
= 0;
112 Header contentLength
= mGet
.getResponseHeader("Content-Length");
113 long totalToTransfer
= (contentLength
!= null
&& contentLength
.getValue().length() >0) ? Long
.parseLong(contentLength
.getValue()) : 0;
115 byte[] bytes
= new byte[4096];
117 while ((readResult
= bis
.read(bytes
)) != -1) {
118 synchronized(mCancellationRequested
) {
119 if (mCancellationRequested
.get()) {
121 throw new OperationCancelledException();
124 fos
.write(bytes
, 0, readResult
);
125 transferred
+= readResult
;
126 synchronized (mDataTransferListeners
) {
127 it
= mDataTransferListeners
.iterator();
128 while (it
.hasNext()) {
129 it
.next().onTransferProgress(readResult
, transferred
, totalToTransfer
, targetFile
.getName());
135 Header modificationTime = mGet.getResponseHeader("Last-Modified");
136 if (modificationTime != null) {
137 Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
138 mModificationTimestamp = (d != null) ? d.getTime() : 0;
143 client
.exhaustResponse(mGet
.getResponseBodyAsStream());
147 if (fos
!= null
) fos
.close();
148 if (!savedFile
&& targetFile
.exists()) {
151 mGet
.releaseConnection(); // let the connection available for other methods
156 private boolean isSuccess(int status
) {
157 return (status
== HttpStatus
.SC_OK
);
160 private String
getTmpPath() {
161 return mDownloadFolderPath
+ mRemotePath
;
164 public void addDatatransferProgressListener (OnDatatransferProgressListener listener
) {
165 synchronized (mDataTransferListeners
) {
166 mDataTransferListeners
.add(listener
);
170 public void removeDatatransferProgressListener(OnDatatransferProgressListener listener
) {
171 synchronized (mDataTransferListeners
) {
172 mDataTransferListeners
.remove(listener
);
176 public void cancel() {
177 mCancellationRequested
.set(true
); // atomic set; there is no need of synchronizing it