fbee3b000aab308a42d643b8d24f642a93ceb5ce
[pub/Android/ownCloud.git] / src / eu / alefzero / owncloud / syncadapter / FileSyncAdapter.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 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 eu.alefzero.owncloud.syncadapter;
20
21 import java.io.IOException;
22 import java.io.ObjectInputStream.GetField;
23 import java.util.List;
24 import java.util.Vector;
25
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.accounts.AuthenticatorException;
32 import android.accounts.OperationCanceledException;
33 import android.content.ContentProviderClient;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.SyncResult;
37 import android.os.Bundle;
38 import android.util.Log;
39 import eu.alefzero.owncloud.datamodel.FileDataStorageManager;
40 import eu.alefzero.owncloud.datamodel.OCFile;
41 import eu.alefzero.owncloud.files.services.FileDownloader;
42 import eu.alefzero.webdav.WebdavEntry;
43
44 /**
45 * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
46 * platform ContactOperations provider.
47 *
48 * @author Bartek Przybylski
49 */
50 public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
51
52 private final static String TAG = "FileSyncAdapter";
53
54 /* Commented code for ugly performance tests
55 private final static int MAX_DELAYS = 100;
56 private static long[] mResponseDelays = new long[MAX_DELAYS];
57 private static long[] mSaveDelays = new long[MAX_DELAYS];
58 private int mDelaysIndex = 0;
59 private int mDelaysCount = 0;
60 */
61
62 private long mCurrentSyncTime;
63
64 public FileSyncAdapter(Context context, boolean autoInitialize) {
65 super(context, autoInitialize);
66 }
67
68 @Override
69 public synchronized void onPerformSync(Account account, Bundle extras,
70 String authority, ContentProviderClient provider,
71 SyncResult syncResult) {
72
73 this.setAccount(account);
74 this.setContentProvider(provider);
75 this.setStorageManager(new FileDataStorageManager(account,
76 getContentProvider()));
77
78 /* Commented code for ugly performance tests
79 mDelaysIndex = 0;
80 mDelaysCount = 0;
81 */
82
83
84 Log.d(TAG, "syncing owncloud account " + account.name);
85
86 sendStickyBroadcast(true, null); // message to signal the start to the UI
87
88 PropFindMethod query;
89 try {
90 mCurrentSyncTime = System.currentTimeMillis();
91 query = new PropFindMethod(getUri().toString() + "/");
92 getClient().executeMethod(query);
93 MultiStatus resp = null;
94 resp = query.getResponseBodyAsMultiStatus();
95
96 if (resp.getResponses().length > 0) {
97 WebdavEntry we = new WebdavEntry(resp.getResponses()[0], getUri().getPath());
98 OCFile file = fillOCFile(we);
99 file.setParentId(0);
100 getStorageManager().saveFile(file);
101 fetchData(getUri().toString(), syncResult, file.getFileId(), account);
102 }
103 } catch (OperationCanceledException e) {
104 e.printStackTrace();
105 } catch (AuthenticatorException e) {
106 syncResult.stats.numAuthExceptions++;
107 e.printStackTrace();
108 } catch (IOException e) {
109 syncResult.stats.numIoExceptions++;
110 e.printStackTrace();
111 } catch (DavException e) {
112 syncResult.stats.numIoExceptions++;
113 e.printStackTrace();
114 } catch (Throwable t) {
115 // TODO update syncResult
116 Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t);
117 t.printStackTrace();
118 }
119
120 /* Commented code for ugly performance tests
121 long sum = 0, mean = 0, max = 0, min = Long.MAX_VALUE;
122 for (int i=0; i<MAX_DELAYS && i<mDelaysCount; i++) {
123 sum += mResponseDelays[i];
124 max = Math.max(max, mResponseDelays[i]);
125 min = Math.min(min, mResponseDelays[i]);
126 }
127 mean = sum / mDelaysCount;
128 Log.e(TAG, "SYNC STATS - response: mean time = " + mean + " ; max time = " + max + " ; min time = " + min);
129
130 sum = 0; max = 0; min = Long.MAX_VALUE;
131 for (int i=0; i<MAX_DELAYS && i<mDelaysCount; i++) {
132 sum += mSaveDelays[i];
133 max = Math.max(max, mSaveDelays[i]);
134 min = Math.min(min, mSaveDelays[i]);
135 }
136 mean = sum / mDelaysCount;
137 Log.e(TAG, "SYNC STATS - save: mean time = " + mean + " ; max time = " + max + " ; min time = " + min);
138 Log.e(TAG, "SYNC STATS - folders measured: " + mDelaysCount);
139 */
140
141 sendStickyBroadcast(false, null);
142 }
143
144 private void fetchData(String uri, SyncResult syncResult, long parentId, Account account) {
145 try {
146 //Log.v(TAG, "syncing: fetching " + uri);
147
148 // remote request
149 PropFindMethod query = new PropFindMethod(uri);
150 /* Commented code for ugly performance tests
151 long responseDelay = System.currentTimeMillis();
152 */
153 getClient().executeMethod(query);
154 /* Commented code for ugly performance tests
155 responseDelay = System.currentTimeMillis() - responseDelay;
156 Log.e(TAG, "syncing: RESPONSE TIME for " + uri + " contents, " + responseDelay + "ms");
157 */
158 MultiStatus resp = null;
159 resp = query.getResponseBodyAsMultiStatus();
160
161 // insertion or update of files
162 List<OCFile> updatedFiles = new Vector<OCFile>(resp.getResponses().length - 1);
163 for (int i = 1; i < resp.getResponses().length; ++i) {
164 WebdavEntry we = new WebdavEntry(resp.getResponses()[i], getUri().getPath());
165 OCFile file = fillOCFile(we);
166 file.setParentId(parentId);
167 if (getStorageManager().getFileByPath(file.getRemotePath()) != null &&
168 getStorageManager().getFileByPath(file.getRemotePath()).keepInSync() &&
169 file.getModificationTimestamp() > getStorageManager().getFileByPath(file.getRemotePath())
170 .getModificationTimestamp()) {
171 Intent intent = new Intent(this.getContext(), FileDownloader.class);
172 intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount());
173 intent.putExtra(FileDownloader.EXTRA_FILE_PATH, file.getURLDecodedRemotePath());
174 intent.putExtra(FileDownloader.EXTRA_REMOTE_PATH, file.getRemotePath());
175 intent.putExtra(FileDownloader.EXTRA_FILE_SIZE, file.getFileLength());
176 file.setKeepInSync(true);
177 getContext().startService(intent);
178 }
179 if (getStorageManager().getFileByPath(file.getRemotePath()) != null)
180 file.setKeepInSync(getStorageManager().getFileByPath(file.getRemotePath()).keepInSync());
181 //getStorageManager().saveFile(file);
182 updatedFiles.add(file);
183 if (parentId == 0)
184 parentId = file.getFileId();
185 }
186 /* Commented code for ugly performance tests
187 long saveDelay = System.currentTimeMillis();
188 */
189 getStorageManager().saveFiles(updatedFiles); // all "at once" ; trying to get a best performance in database update
190 /* Commented code for ugly performance tests
191 saveDelay = System.currentTimeMillis() - saveDelay;
192 Log.e(TAG, "syncing: SAVE TIME for " + uri + " contents, " + mSaveDelays[mDelaysIndex] + "ms");
193 */
194
195 // removal of obsolete files
196 Vector<OCFile> files = getStorageManager().getDirectoryContent(
197 getStorageManager().getFileById(parentId));
198 OCFile file;
199 for (int i=0; i < files.size(); ) {
200 file = files.get(i);
201 if (file.getLastSyncDate() != mCurrentSyncTime && file.getLastSyncDate() != 0) {
202 getStorageManager().removeFile(file);
203 files.remove(i);
204 } else {
205 i++;
206 }
207 }
208
209 // synchronized folder -> notice to UI
210 sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath());
211
212 // recursive fetch
213 for (OCFile newFile : files) {
214 if (newFile.getMimetype().equals("DIR")) {
215 fetchData(getUri().toString() + newFile.getRemotePath(), syncResult, newFile.getFileId(), account);
216 }
217 }
218
219 /* Commented code for ugly performance tests
220 mResponseDelays[mDelaysIndex] = responseDelay;
221 mSaveDelays[mDelaysIndex] = saveDelay;
222 mDelaysCount++;
223 mDelaysIndex++;
224 if (mDelaysIndex >= MAX_DELAYS)
225 mDelaysIndex = 0;
226 */
227
228
229
230 } catch (OperationCanceledException e) {
231 e.printStackTrace();
232 } catch (AuthenticatorException e) {
233 syncResult.stats.numAuthExceptions++;
234 e.printStackTrace();
235 } catch (IOException e) {
236 syncResult.stats.numIoExceptions++;
237 e.printStackTrace();
238 } catch (DavException e) {
239 syncResult.stats.numIoExceptions++;
240 e.printStackTrace();
241 } catch (Throwable t) {
242 // TODO update syncResult
243 Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t);
244 t.printStackTrace();
245 }
246 }
247
248 private OCFile fillOCFile(WebdavEntry we) {
249 OCFile file = new OCFile(we.path());
250 file.setCreationTimestamp(we.createTimestamp());
251 file.setFileLength(we.contentLength());
252 file.setMimetype(we.contentType());
253 file.setModificationTimestamp(we.modifiedTimesamp());
254 file.setLastSyncDate(mCurrentSyncTime);
255 return file;
256 }
257
258
259 private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) {
260 Intent i = new Intent(FileSyncService.SYNC_MESSAGE);
261 i.putExtra(FileSyncService.IN_PROGRESS, inProgress);
262 i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);
263 if (dirRemotePath != null) {
264 i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);
265 }
266 getContext().sendStickyBroadcast(i);
267 }
268
269 @Override
270 public void onSyncCanceled() {
271 Log.d(TAG, "sync is being cancelled !! ************************************************");
272 super.onSyncCanceled();
273 }
274
275 }