36b9b2295b447bb9827c0799995452fea800b4ed
[pub/Android/ownCloud.git] / src / com / owncloud / android / operations / SynchronizeFolderOperation.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.IOException;
22 import java.util.List;
23 import java.util.Vector;
24
25 import org.apache.http.HttpStatus;
26 import org.apache.jackrabbit.webdav.DavException;
27 import org.apache.jackrabbit.webdav.MultiStatus;
28 import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
29
30 import android.accounts.Account;
31 import android.content.Intent;
32 import android.util.Log;
33
34 import com.owncloud.android.datamodel.FileDataStorageManager;
35 import com.owncloud.android.datamodel.OCFile;
36 import com.owncloud.android.files.services.FileDownloader;
37
38 import eu.alefzero.webdav.WebdavClient;
39 import eu.alefzero.webdav.WebdavEntry;
40 import eu.alefzero.webdav.WebdavUtils;
41
42
43 /**
44 * Remote operation performing the synchronization a the contents of a remote folder with the local database
45 *
46 * @author David A. Velasco
47 */
48 public class SynchronizeFolderOperation extends RemoteOperation {
49
50 private static final String TAG = SynchronizeFolderOperation.class.getCanonicalName();
51
52 /** Remote folder to synchronize */
53 private String mRemotePath;
54
55 /** Timestamp for the synchronization in progress */
56 private long mCurrentSyncTime;
57
58 /** Id of the folder to synchronize in the local database */
59 private long mParentId;
60
61 /** Access to the local database */
62 private FileDataStorageManager mStorageManager;
63
64 /** Account where the file to synchronize belongs */
65 private Account mAccount;
66
67
68 SynchronizeFolderOperation(String remotePath, long currentSyncTime, long parentId, FileDataStorageManager storageManager, Account account) {
69 mRemotePath = remotePath;
70 mCurrentSyncTime = currentSyncTime;
71 mParentId = parentId;
72 mStorageManager = storageManager;
73 mAccount = account;
74 }
75
76
77 @Override
78 protected RemoteOperationResult run(WebdavClient client) {
79 RemoteOperationResult result = null;
80
81 // code before in FileSyncAdapter.fetchData
82 PropFindMethod query = null;
83 Vector<OCFile> children = null;
84 try {
85 Log.d(TAG, "Fetching files in " + mRemotePath);
86
87 // remote request
88 query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
89 int status = client.executeMethod(query);
90
91 if (isSuccess(status)) {
92
93 MultiStatus resp = query.getResponseBodyAsMultiStatus();
94
95 // reading files
96 List<OCFile> updatedFiles = new Vector<OCFile>(resp.getResponses().length - 1);
97 for (int i = 1; i < resp.getResponses().length; ++i) {
98 WebdavEntry we = new WebdavEntry(resp.getResponses()[i], client.getBaseUri().getPath());
99 OCFile file = fillOCFile(we);
100 file.setParentId(mParentId);
101 OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath());
102 if (oldFile != null) {
103 if (oldFile.keepInSync() && file.getModificationTimestamp() > oldFile.getModificationTimestamp()) {
104 requestContentDownload();
105 }
106 file.setKeepInSync(oldFile.keepInSync());
107 }
108
109 updatedFiles.add(file);
110 }
111
112
113 // save updated files in local database; all at once, trying to get a best performance in database update (not a big deal, indeed)
114 mStorageManager.saveFiles(updatedFiles);
115
116
117 // removal of obsolete files
118 children = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId));
119 OCFile file;
120 String currentSavePath = FileDownloader.getSavePath(mAccount.name);
121 for (int i=0; i < children.size(); ) {
122 file = children.get(i);
123 if (file.getLastSyncDate() != mCurrentSyncTime) {
124 Log.d(TAG, "removing file: " + file);
125 mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath)));
126 children.remove(i);
127 } else {
128 i++;
129 }
130 }
131
132 } else if (status == HttpStatus.SC_UNAUTHORIZED) {
133 syncResult.stats.numAuthExceptions++;
134
135 } else {
136 // TODO something smart with syncResult? OR NOT
137 }
138
139 result = new RemoteOperationResult(isSuccess(status), status);
140 Log.i(TAG, "Synchronization of " + mRemotePath + ": " + result.getLogMessage());
141
142
143 } catch (IOException e) {
144 syncResult.stats.numIoExceptions++;
145 logException(e, uri);
146
147 } catch (DavException e) {
148 syncResult.stats.numParseExceptions++;
149 logException(e, uri);
150
151 } catch (Exception e) {
152 // TODO something smart with syncresult
153 mRightSync = false;
154 logException(e, uri);
155
156 } finally {
157 if (query != null)
158 query.releaseConnection(); // let the connection available for other methods
159
160 // synchronized folder -> notice to UI
161 sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath());
162 }
163
164
165 return result;
166 }
167
168
169 public boolean isSuccess(int status) {
170 return (status == HttpStatus.SC_MULTI_STATUS); // TODO check other possible OK codes; doc doesn't help
171 }
172
173
174 private void requestContentDownload() {
175 Intent intent = new Intent(this.getContext(), FileDownloader.class);
176 intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount());
177 intent.putExtra(FileDownloader.EXTRA_FILE, file);
178 file.setKeepInSync(true);
179 getContext().startService(intent);
180 }
181
182
183 private OCFile fillOCFile(WebdavEntry we) {
184 OCFile file = new OCFile(we.decodedPath());
185 file.setCreationTimestamp(we.createTimestamp());
186 file.setFileLength(we.contentLength());
187 file.setMimetype(we.contentType());
188 file.setModificationTimestamp(we.modifiedTimesamp());
189 file.setLastSyncDate(mCurrentSyncTime);
190 return file;
191 }
192
193 }