Merge remote-tracking branch 'origin/master' into cancel_in_upload
[pub/Android/ownCloud.git] / src / com / owncloud / android / operations / UploadFileOperation.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.File;
22 import java.io.IOException;
23 import java.util.HashSet;
24 import java.util.Set;
25
26 import org.apache.commons.httpclient.HttpException;
27 import org.apache.commons.httpclient.methods.PutMethod;
28 import org.apache.http.HttpStatus;
29
30 import com.owncloud.android.operations.RemoteOperation;
31 import com.owncloud.android.operations.RemoteOperationResult;
32
33 import eu.alefzero.webdav.FileRequestEntity;
34 import eu.alefzero.webdav.OnDatatransferProgressListener;
35 import eu.alefzero.webdav.WebdavClient;
36 import eu.alefzero.webdav.WebdavUtils;
37 import android.accounts.Account;
38 import android.util.Log;
39 import android.webkit.MimeTypeMap;
40
41 /**
42 * Remote operation performing the upload of a file to an ownCloud server
43 *
44 * @author David A. Velasco
45 */
46 public class UploadFileOperation extends RemoteOperation {
47
48 private static final String TAG = UploadFileOperation.class.getCanonicalName();
49
50 private Account mAccount = null;
51 private String mLocalPath = null;
52 private String mRemotePath = null;
53 private String mMimeType = null;
54 private boolean mIsInstant = false;
55 private boolean mForceOverwrite = false;
56 private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
57
58
59 public UploadFileOperation( Account account,
60 String localPath,
61 String remotePath,
62 String mimeType,
63 boolean isInstant,
64 boolean forceOverwrite) {
65 if (account == null)
66 throw new IllegalArgumentException("Illegal null account in UploadFileOperation creation");
67 if (localPath == null || localPath.length() <= 0)
68 throw new IllegalArgumentException("Illegal null or empty localPath in UploadFileOperation creation");
69 if (remotePath == null || remotePath.length() <= 0)
70 throw new IllegalArgumentException("Illegal null or empty remotePath in UploadFileOperation creation");
71
72 mAccount = account;
73 mLocalPath = localPath;
74 mRemotePath = remotePath;
75 mMimeType = mimeType;
76 if (mMimeType == null || mMimeType.length() <= 0) {
77 try {
78 mMimeType = MimeTypeMap.getSingleton()
79 .getMimeTypeFromExtension(
80 localPath.substring(localPath.lastIndexOf('.') + 1));
81 } catch (IndexOutOfBoundsException e) {
82 Log.e(TAG, "Trying to find out MIME type of a file without extension: " + localPath);
83 }
84 }
85 if (mMimeType == null) {
86 mMimeType = "application/octet-stream";
87 }
88 mIsInstant = isInstant;
89 mForceOverwrite = forceOverwrite;
90 }
91
92
93 public Account getAccount() {
94 return mAccount;
95 }
96
97 public String getLocalPath() {
98 return mLocalPath;
99 }
100
101 public String getRemotePath() {
102 return mRemotePath;
103 }
104
105 public String getMimeType() {
106 return mMimeType;
107 }
108
109 public boolean isInstant() {
110 return mIsInstant;
111 }
112
113 public boolean getForceOverwrite() {
114 return mForceOverwrite;
115 }
116
117
118 public Set<OnDatatransferProgressListener> getDataTransferListeners() {
119 return mDataTransferListeners;
120 }
121
122 public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
123 mDataTransferListeners.add(listener);
124 }
125
126
127 @Override
128 protected RemoteOperationResult run(WebdavClient client) {
129 RemoteOperationResult result = null;
130 boolean nameCheckPassed = false;
131 try {
132 /// rename the file to upload, if necessary
133 if (!mForceOverwrite) {
134 mRemotePath = getAvailableRemotePath(client, mRemotePath);
135 }
136
137 /// perform the upload
138 nameCheckPassed = true;
139 int status = uploadFile(client);
140 result = new RemoteOperationResult(isSuccess(status), status);
141 Log.i(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
142
143 } catch (Exception e) {
144 result = new RemoteOperationResult(e);
145 Log.e(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage() + (nameCheckPassed?"":" (while checking file existence in server)"), e);
146
147 }
148
149 return result;
150 }
151
152
153 public boolean isSuccess(int status) {
154 return ((status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT));
155 }
156
157
158 protected int uploadFile(WebdavClient client) throws HttpException, IOException {
159 int status = -1;
160 PutMethod put = new PutMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
161
162 try {
163 File f = new File(mLocalPath);
164 FileRequestEntity entity = new FileRequestEntity(f, mMimeType);
165 entity.addOnDatatransferProgressListeners(mDataTransferListeners);
166 put.setRequestEntity(entity);
167 status = client.executeMethod(put);
168 client.exhaustResponse(put.getResponseBodyAsStream());
169
170 } finally {
171 put.releaseConnection(); // let the connection available for other methods
172 }
173 return status;
174 }
175
176 /**
177 * Checks if remotePath does not exist in the server and returns it, or adds a suffix to it in order to avoid the server
178 * file is overwritten.
179 *
180 * @param string
181 * @return
182 */
183 private String getAvailableRemotePath(WebdavClient wc, String remotePath) throws Exception {
184 boolean check = wc.existsFile(remotePath);
185 if (!check) {
186 return remotePath;
187 }
188
189 int pos = remotePath.lastIndexOf(".");
190 String suffix = "";
191 String extension = "";
192 if (pos >= 0) {
193 extension = remotePath.substring(pos+1);
194 remotePath = remotePath.substring(0, pos);
195 }
196 int count = 2;
197 do {
198 suffix = " (" + count + ")";
199 if (pos >= 0)
200 check = wc.existsFile(remotePath + suffix + "." + extension);
201 else
202 check = wc.existsFile(remotePath + suffix);
203 count++;
204 } while (check);
205
206 if (pos >=0) {
207 return remotePath + suffix + "." + extension;
208 } else {
209 return remotePath + suffix;
210 }
211 }
212
213
214 }