4c92d09bb323cffa4c2afa975c539b2f95e34793
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / FileDataStorageManager.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.datamodel;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Vector;
27
28 import com.owncloud.android.db.ProviderMeta;
29 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
30 import com.owncloud.android.utils.FileStorageUtils;
31
32 import android.accounts.Account;
33 import android.content.ContentProviderClient;
34 import android.content.ContentProviderOperation;
35 import android.content.ContentProviderResult;
36 import android.content.ContentResolver;
37 import android.content.ContentValues;
38 import android.content.OperationApplicationException;
39 import android.database.Cursor;
40 import android.net.Uri;
41 import android.os.RemoteException;
42 import android.util.Log;
43
44 public class FileDataStorageManager implements DataStorageManager {
45
46 private ContentResolver mContentResolver;
47 private ContentProviderClient mContentProvider;
48 private Account mAccount;
49
50 private static String TAG = "FileDataStorageManager";
51
52 public FileDataStorageManager(Account account, ContentResolver cr) {
53 mContentProvider = null;
54 mContentResolver = cr;
55 mAccount = account;
56 }
57
58 public FileDataStorageManager(Account account, ContentProviderClient cp) {
59 mContentProvider = cp;
60 mContentResolver = null;
61 mAccount = account;
62 }
63
64 @Override
65 public OCFile getFileByPath(String path) {
66 Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path);
67 OCFile file = null;
68 if (c.moveToFirst()) {
69 file = createFileInstance(c);
70 }
71 c.close();
72 return file;
73 }
74
75 @Override
76 public OCFile getFileById(long id) {
77 Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
78 OCFile file = null;
79 if (c.moveToFirst()) {
80 file = createFileInstance(c);
81 }
82 c.close();
83 return file;
84 }
85
86 public OCFile getFileByLocalPath(String path) {
87 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
88 OCFile file = null;
89 if (c.moveToFirst()) {
90 file = createFileInstance(c);
91 }
92 c.close();
93 return file;
94 }
95
96 @Override
97 public boolean fileExists(long id) {
98 return fileExists(ProviderTableMeta._ID, String.valueOf(id));
99 }
100
101 @Override
102 public boolean fileExists(String path) {
103 return fileExists(ProviderTableMeta.FILE_PATH, path);
104 }
105
106 @Override
107 public boolean saveFile(OCFile file) {
108 boolean overriden = false;
109 ContentValues cv = new ContentValues();
110 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
111 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
112 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
113 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
114 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
115 if (file.getParentId() != 0)
116 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
117 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
118 if (!file.isDirectory())
119 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
120 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
121 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
122 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
123 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
124
125 if (fileExists(file.getRemotePath())) {
126 OCFile oldFile = getFileByPath(file.getRemotePath());
127 if (file.getStoragePath() == null && oldFile.isDown())
128 file.setStoragePath(oldFile.getStoragePath());
129 if (!file.isDirectory());
130 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
131 file.setFileId(oldFile.getFileId());
132
133 overriden = true;
134 if (getContentResolver() != null) {
135 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
136 ProviderTableMeta._ID + "=?",
137 new String[] { String.valueOf(file.getFileId()) });
138 } else {
139 try {
140 getContentProvider().update(ProviderTableMeta.CONTENT_URI,
141 cv, ProviderTableMeta._ID + "=?",
142 new String[] { String.valueOf(file.getFileId()) });
143 } catch (RemoteException e) {
144 Log.e(TAG,
145 "Fail to insert insert file to database "
146 + e.getMessage());
147 }
148 }
149 } else {
150 Uri result_uri = null;
151 if (getContentResolver() != null) {
152 result_uri = getContentResolver().insert(
153 ProviderTableMeta.CONTENT_URI_FILE, cv);
154 } else {
155 try {
156 result_uri = getContentProvider().insert(
157 ProviderTableMeta.CONTENT_URI_FILE, cv);
158 } catch (RemoteException e) {
159 Log.e(TAG,
160 "Fail to insert insert file to database "
161 + e.getMessage());
162 }
163 }
164 if (result_uri != null) {
165 long new_id = Long.parseLong(result_uri.getPathSegments()
166 .get(1));
167 file.setFileId(new_id);
168 }
169 }
170
171 if (file.isDirectory() && file.needsUpdatingWhileSaving())
172 for (OCFile f : getDirectoryContent(file))
173 saveFile(f);
174
175 return overriden;
176 }
177
178
179 @Override
180 public void saveFiles(List<OCFile> files) {
181
182 Iterator<OCFile> filesIt = files.iterator();
183 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(files.size());
184 OCFile file = null;
185
186 // prepare operations to perform
187 while (filesIt.hasNext()) {
188 file = filesIt.next();
189 ContentValues cv = new ContentValues();
190 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
191 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
192 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
193 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
194 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
195 if (file.getParentId() != 0)
196 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
197 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
198 if (!file.isDirectory())
199 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
200 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
201 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
202 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
203 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
204
205 if (fileExists(file.getRemotePath())) {
206 OCFile tmpfile = getFileByPath(file.getRemotePath());
207 file.setStoragePath(tmpfile.getStoragePath());
208 if (!file.isDirectory());
209 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
210 file.setFileId(tmpfile.getFileId());
211
212 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
213 withValues(cv).
214 withSelection( ProviderTableMeta._ID + "=?",
215 new String[] { String.valueOf(file.getFileId()) })
216 .build());
217
218 } else {
219 operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
220 }
221 }
222
223 // apply operations in batch
224 ContentProviderResult[] results = null;
225 try {
226 if (getContentResolver() != null) {
227 results = getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
228
229 } else {
230 results = getContentProvider().applyBatch(operations);
231 }
232
233 } catch (OperationApplicationException e) {
234 Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
235
236 } catch (RemoteException e) {
237 Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
238 }
239
240 // update new id in file objects for insertions
241 if (results != null) {
242 long newId;
243 for (int i=0; i<results.length; i++) {
244 if (results[i].uri != null) {
245 newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
246 files.get(i).setFileId(newId);
247 //Log.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath());
248 }
249 }
250 }
251
252 for (OCFile aFile : files) {
253 if (aFile.isDirectory() && aFile.needsUpdatingWhileSaving())
254 saveFiles(getDirectoryContent(aFile));
255 }
256
257 }
258
259 public void setAccount(Account account) {
260 mAccount = account;
261 }
262
263 public Account getAccount() {
264 return mAccount;
265 }
266
267 public void setContentResolver(ContentResolver cr) {
268 mContentResolver = cr;
269 }
270
271 public ContentResolver getContentResolver() {
272 return mContentResolver;
273 }
274
275 public void setContentProvider(ContentProviderClient cp) {
276 mContentProvider = cp;
277 }
278
279 public ContentProviderClient getContentProvider() {
280 return mContentProvider;
281 }
282
283 @Override
284 public Vector<OCFile> getDirectoryContent(OCFile f) {
285 if (f != null && f.isDirectory() && f.getFileId() != -1) {
286 Vector<OCFile> ret = new Vector<OCFile>();
287
288 Uri req_uri = Uri.withAppendedPath(
289 ProviderTableMeta.CONTENT_URI_DIR,
290 String.valueOf(f.getFileId()));
291 Cursor c = null;
292
293 if (getContentProvider() != null) {
294 try {
295 c = getContentProvider().query(req_uri, null,
296 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
297 new String[] { mAccount.name }, null);
298 } catch (RemoteException e) {
299 Log.e(TAG, e.getMessage());
300 return ret;
301 }
302 } else {
303 c = getContentResolver().query(req_uri, null,
304 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
305 new String[] { mAccount.name }, null);
306 }
307
308 if (c.moveToFirst()) {
309 do {
310 OCFile child = createFileInstance(c);
311 ret.add(child);
312 } while (c.moveToNext());
313 }
314
315 c.close();
316
317 Collections.sort(ret);
318
319 return ret;
320 }
321 return null;
322 }
323
324 private boolean fileExists(String cmp_key, String value) {
325 Cursor c;
326 if (getContentResolver() != null) {
327 c = getContentResolver()
328 .query(ProviderTableMeta.CONTENT_URI,
329 null,
330 cmp_key + "=? AND "
331 + ProviderTableMeta.FILE_ACCOUNT_OWNER
332 + "=?",
333 new String[] { value, mAccount.name }, null);
334 } else {
335 try {
336 c = getContentProvider().query(
337 ProviderTableMeta.CONTENT_URI,
338 null,
339 cmp_key + "=? AND "
340 + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
341 new String[] { value, mAccount.name }, null);
342 } catch (RemoteException e) {
343 Log.e(TAG,
344 "Couldn't determine file existance, assuming non existance: "
345 + e.getMessage());
346 return false;
347 }
348 }
349 boolean retval = c.moveToFirst();
350 c.close();
351 return retval;
352 }
353
354 private Cursor getCursorForValue(String key, String value) {
355 Cursor c = null;
356 if (getContentResolver() != null) {
357 c = getContentResolver()
358 .query(ProviderTableMeta.CONTENT_URI,
359 null,
360 key + "=? AND "
361 + ProviderTableMeta.FILE_ACCOUNT_OWNER
362 + "=?",
363 new String[] { value, mAccount.name }, null);
364 } else {
365 try {
366 c = getContentProvider().query(
367 ProviderTableMeta.CONTENT_URI,
368 null,
369 key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER
370 + "=?", new String[] { value, mAccount.name },
371 null);
372 } catch (RemoteException e) {
373 Log.e(TAG, "Could not get file details: " + e.getMessage());
374 c = null;
375 }
376 }
377 return c;
378 }
379
380 private OCFile createFileInstance(Cursor c) {
381 OCFile file = null;
382 if (c != null) {
383 file = new OCFile(c.getString(c
384 .getColumnIndex(ProviderTableMeta.FILE_PATH)));
385 file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
386 file.setParentId(c.getLong(c
387 .getColumnIndex(ProviderTableMeta.FILE_PARENT)));
388 file.setMimetype(c.getString(c
389 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
390 if (!file.isDirectory()) {
391 file.setStoragePath(c.getString(c
392 .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
393 if (file.getStoragePath() == null) {
394 // try to find existing file and bind it with current account
395 File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
396 if (f.exists())
397 file.setStoragePath(f.getAbsolutePath());
398 }
399 }
400 file.setFileLength(c.getLong(c
401 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
402 file.setCreationTimestamp(c.getLong(c
403 .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
404 file.setModificationTimestamp(c.getLong(c
405 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
406 file.setLastSyncDateForProperties(c.getLong(c
407 .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
408 file.setLastSyncDateForData(c.getLong(c.
409 getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
410 file.setKeepInSync(c.getInt(
411 c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
412 }
413 return file;
414 }
415
416 @Override
417 public void removeFile(OCFile file, boolean removeLocalCopy) {
418 Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId());
419 if (getContentProvider() != null) {
420 try {
421 getContentProvider().delete(file_uri,
422 ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
423 new String[]{mAccount.name});
424 } catch (RemoteException e) {
425 e.printStackTrace();
426 }
427 } else {
428 getContentResolver().delete(file_uri,
429 ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
430 new String[]{mAccount.name});
431 }
432 if (file.isDown() && removeLocalCopy) {
433 new File(file.getStoragePath()).delete();
434 }
435 }
436
437 }