fbeedd8a17c866a3224314446dcee94ee99e9d4d
[pub/Android/ownCloud.git] / src / com / owncloud / android / operations / DownloadFileOperation.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.operations;
20
21 import java.io.BufferedInputStream;
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.Set;
28
29 import org.apache.commons.httpclient.HttpException;
30 import org.apache.commons.httpclient.methods.GetMethod;
31 import org.apache.http.HttpStatus;
32
33 import com.owncloud.android.files.services.FileDownloader;
34 import com.owncloud.android.operations.RemoteOperation;
35 import com.owncloud.android.operations.RemoteOperationResult;
36
37 import eu.alefzero.webdav.OnDatatransferProgressListener;
38 import eu.alefzero.webdav.WebdavClient;
39 import eu.alefzero.webdav.WebdavUtils;
40 import android.accounts.Account;
41 import android.util.Log;
42 import android.webkit.MimeTypeMap;
43
44 /**
45 * Remote operation performing the download of a file to an ownCloud server
46 *
47 * @author David A. Velasco
48 */
49 public class DownloadFileOperation extends RemoteOperation {
50
51 private static final String TAG = DownloadFileOperation.class.getCanonicalName();
52
53 private Account mAccount = null;
54 private String mLocalPath = null;
55 private String mRemotePath = null;
56 private String mMimeType = null;
57 private long mSize = -1;
58 private Boolean mCancellationRequested = false;
59
60 private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
61
62
63 public Account getAccount() {
64 return mAccount;
65 }
66
67 public String getLocalPath() {
68 return mLocalPath;
69 }
70
71 public String getRemotePath() {
72 return mRemotePath;
73 }
74
75 public String getMimeType() {
76 return mMimeType;
77 }
78
79 public long getSize() {
80 return mSize;
81 }
82
83
84 public DownloadFileOperation( Account account,
85 String localPath,
86 String remotePath,
87 String mimeType,
88 long size,
89 boolean forceOverwrite) {
90
91 if (account == null)
92 throw new IllegalArgumentException("Illegal null account in DownloadFileOperation creation");
93 if (localPath == null)
94 throw new IllegalArgumentException("Illegal null local path in DownloadFileOperation creation");
95 if (remotePath == null)
96 throw new IllegalArgumentException("Illegal null remote path in DownloadFileOperation creation");
97
98 mAccount = account;
99 mLocalPath = localPath;
100 mRemotePath = remotePath;
101 mMimeType = mimeType;
102 if (mMimeType == null) {
103 try {
104 mMimeType = MimeTypeMap.getSingleton()
105 .getMimeTypeFromExtension(
106 localPath.substring(localPath.lastIndexOf('.') + 1));
107 } catch (IndexOutOfBoundsException e) {
108 Log.e(TAG, "Trying to find out MIME type of a file without extension: " + localPath);
109 }
110 }
111 if (mMimeType == null) {
112 mMimeType = "application/octet-stream";
113 }
114 mSize = size;
115 }
116
117 public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
118 mDataTransferListeners.add(listener);
119 }
120
121
122
123 @Override
124 protected RemoteOperationResult run(WebdavClient client) {
125 RemoteOperationResult result = null;
126 File newFile = null;
127 boolean moved = false;
128
129 /// download will be in a temporal file
130 File tmpFile = new File(FileDownloader.getTemporalPath(mAccount.name) + mLocalPath);
131
132 /// perform the download
133 try {
134 tmpFile.getParentFile().mkdirs();
135 int status = downloadFile(client, tmpFile);
136 if (isSuccess(status)) {
137 newFile = new File(FileDownloader.getSavePath(mAccount.name) + mLocalPath);
138 newFile.getParentFile().mkdirs();
139 moved = tmpFile.renameTo(newFile);
140 }
141 if (!moved)
142 result = new RemoteOperationResult(RemoteOperationResult.ResultCode.STORAGE_ERROR_MOVING_FROM_TMP);
143 else
144 result = new RemoteOperationResult(isSuccess(status), status);
145 Log.i(TAG, "Download of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
146
147 } catch (Exception e) {
148 result = new RemoteOperationResult(e);
149 Log.e(TAG, "Download of " + mRemotePath + " to " + mLocalPath + ": " + result.getLogMessage(), e);
150 }
151
152 return result;
153 }
154
155
156 public boolean isSuccess(int status) {
157 return (status == HttpStatus.SC_OK);
158 }
159
160
161 protected int downloadFile(WebdavClient client, File targetFile) throws HttpException, IOException, OperationCancelledException {
162 int status = -1;
163 boolean savedFile = false;
164 GetMethod get = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
165 Iterator<OnDatatransferProgressListener> it = null;
166
167 try {
168 status = client.executeMethod(get);
169 if (isSuccess(status)) {
170 targetFile.createNewFile();
171 BufferedInputStream bis = new BufferedInputStream(get.getResponseBodyAsStream());
172 FileOutputStream fos = new FileOutputStream(targetFile);
173 long transferred = 0;
174
175 byte[] bytes = new byte[4096];
176 int readResult = 0;
177 while ((readResult = bis.read(bytes)) != -1) {
178 synchronized(mCancellationRequested) {
179 if (mCancellationRequested) {
180 throw new OperationCancelledException();
181 }
182 }
183 fos.write(bytes, 0, readResult);
184 transferred += readResult;
185 it = mDataTransferListeners.iterator();
186 while (it.hasNext()) {
187 it.next().onTransferProgress(readResult, transferred, mSize, targetFile.getName());
188 }
189 }
190 fos.close();
191 savedFile = true;
192
193 } else {
194 client.exhaustResponse(get.getResponseBodyAsStream());
195 }
196
197 } finally {
198 if (!savedFile && targetFile.exists()) {
199 targetFile.delete();
200 }
201 get.releaseConnection(); // let the connection available for other methods
202 }
203 return status;
204 }
205
206
207 public void cancel() {
208 synchronized(mCancellationRequested) {
209 mCancellationRequested = true;
210 }
211 }
212
213 }