X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/dc8c32fb3f7033d6fdfa7e1b64eaa77884da678a..7f75f13f0c47b5cc4f5fe6a743a6fb8a9281fef7:/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java diff --git a/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java b/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java index ef9da411..d14151a2 100644 --- a/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java +++ b/src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java @@ -19,25 +19,26 @@ package eu.alefzero.owncloud.syncadapter; import java.io.IOException; +import java.util.List; +import java.util.Vector; -import org.apache.http.entity.StringEntity; +import org.apache.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.MultiStatus; +import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; import android.accounts.Account; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.ContentProviderClient; -import android.content.ContentValues; import android.content.Context; +import android.content.Intent; import android.content.SyncResult; -import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; -import android.os.RemoteException; import android.util.Log; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.webdav.HttpPropFind; -import eu.alefzero.webdav.TreeNode; -import eu.alefzero.webdav.TreeNode.NodeProperty; +import eu.alefzero.owncloud.datamodel.FileDataStorageManager; +import eu.alefzero.owncloud.datamodel.OCFile; +import eu.alefzero.owncloud.files.services.FileDownloader; +import eu.alefzero.webdav.WebdavEntry; import eu.alefzero.webdav.WebdavUtils; /** @@ -47,96 +48,245 @@ import eu.alefzero.webdav.WebdavUtils; * @author Bartek Przybylski */ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { - private static final String TAG = "FileSyncAdapter"; - - public FileSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - - @Override - public synchronized void onPerformSync( - Account account, - Bundle extras, - String authority, - ContentProviderClient provider, - SyncResult syncResult) { - - try { - this.setAccount(account); - this.setContentProvider(provider); - - HttpPropFind query = this.getPropFindQuery(); - query.setEntity(new StringEntity(WebdavUtils.prepareXmlForPropFind())); - TreeNode root = this.fireRequest(query); - - commitToDatabase(root, null); - } catch (OperationCanceledException e) { - e.printStackTrace(); - } catch (AuthenticatorException e) { - syncResult.stats.numAuthExceptions++; - e.printStackTrace(); - } catch (IOException e) { - syncResult.stats.numIoExceptions++; - e.printStackTrace(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - - private void commitToDatabase(TreeNode root, String parentId) throws RemoteException { - for (TreeNode n : root.getChildList()) { - Log.d(TAG, n.toString()); - ContentValues cv = new ContentValues(); - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, n.getProperty(NodeProperty.CONTENT_LENGTH)); - cv.put(ProviderTableMeta.FILE_MODIFIED, n.getProperty(NodeProperty.LAST_MODIFIED_DATE)); - cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, n.getProperty(NodeProperty.RESOURCE_TYPE)); - cv.put(ProviderTableMeta.FILE_PARENT, parentId); - - String name = n.getProperty(NodeProperty.NAME), - path = n.getProperty(NodeProperty.PATH); - Cursor c = this.getContentProvider().query(ProviderTableMeta.CONTENT_URI_FILE, - null, - ProviderTableMeta.FILE_NAME+"=? AND " + ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[]{name, path, this.getAccount().name}, - null); - if (c.moveToFirst()) { - this.getContentProvider().update(ProviderTableMeta.CONTENT_URI, - cv, - ProviderTableMeta._ID+"=?", - new String[]{c.getString(c.getColumnIndex(ProviderTableMeta._ID))}); - Log.d(TAG, "ID of: "+name+":"+c.getString(c.getColumnIndex(ProviderTableMeta._ID))); - } else { - cv.put(ProviderTableMeta.FILE_NAME, n.getProperty(NodeProperty.NAME)); - cv.put(ProviderTableMeta.FILE_PATH, n.getProperty(NodeProperty.PATH)); - cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, this.getAccount().name); - Uri entry = this.getContentProvider().insert(ProviderTableMeta.CONTENT_URI_FILE, cv); - Log.d(TAG, "Inserting new entry " + path + name); - c = this.getContentProvider().query(entry, null, null, null, null); - c.moveToFirst(); - } - if (n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) { - commitToDatabase(n, c.getString(c.getColumnIndex(ProviderTableMeta._ID))); - } - } - // clean removed files - String[] selection = new String[root.getChildList().size()+2]; - selection[0] = this.getAccount().name; - selection[1] = parentId; - String qm = ""; - for (int i = 2; i < selection.length-1; ++i) { - qm += "?,"; - selection[i] = root.getChildList().get(i-2).getProperty(NodeProperty.NAME); - } - if (selection.length >= 3) { - selection[selection.length-1] = root.getChildrenNames()[selection.length-3]; - qm += "?"; - } - for (int i = 0; i < selection.length; ++i) { - Log.d(TAG,selection[i]+""); - } - Log.d(TAG,"Removing files "+ parentId); - this.getContentProvider().delete(ProviderTableMeta.CONTENT_URI, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=? AND " + ProviderTableMeta.FILE_PARENT + (parentId==null?" IS ":"=")+"? AND " + ProviderTableMeta.FILE_NAME + " NOT IN ("+qm+")", - selection); - } + + private final static String TAG = "FileSyncAdapter"; + + /* Commented code for ugly performance tests + private final static int MAX_DELAYS = 100; + private static long[] mResponseDelays = new long[MAX_DELAYS]; + private static long[] mSaveDelays = new long[MAX_DELAYS]; + private int mDelaysIndex = 0; + private int mDelaysCount = 0; + */ + + private long mCurrentSyncTime; + private boolean mCancellation; + private Account mAccount; + + public FileSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + } + + @Override + public synchronized void onPerformSync(Account account, Bundle extras, + String authority, ContentProviderClient provider, + SyncResult syncResult) { + + mCancellation = false; + mAccount = account; + + this.setAccount(mAccount); + this.setContentProvider(provider); + this.setStorageManager(new FileDataStorageManager(mAccount, + getContentProvider())); + + /* Commented code for ugly performance tests + mDelaysIndex = 0; + mDelaysCount = 0; + */ + + + Log.d(TAG, "syncing owncloud account " + mAccount.name); + + sendStickyBroadcast(true, null); // message to signal the start to the UI + + PropFindMethod query; + try { + mCurrentSyncTime = System.currentTimeMillis(); + query = new PropFindMethod(getUri().toString() + "/"); + getClient().executeMethod(query); + MultiStatus resp = null; + resp = query.getResponseBodyAsMultiStatus(); + + if (resp.getResponses().length > 0) { + WebdavEntry we = new WebdavEntry(resp.getResponses()[0], getUri().getPath()); + OCFile file = fillOCFile(we); + file.setParentId(0); + getStorageManager().saveFile(file); + if (!mCancellation) { + fetchData(getUri().toString(), syncResult, file.getFileId()); + } + } + } catch (OperationCanceledException e) { + e.printStackTrace(); + } catch (AuthenticatorException e) { + syncResult.stats.numAuthExceptions++; + e.printStackTrace(); + } catch (IOException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (DavException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (Throwable t) { + // TODO update syncResult + Log.e(TAG, "problem while synchronizing owncloud account " + account.name, t); + t.printStackTrace(); + } + + /* Commented code for ugly performance tests + long sum = 0, mean = 0, max = 0, min = Long.MAX_VALUE; + for (int i=0; i updatedFiles = new Vector(resp.getResponses().length - 1); + for (int i = 1; i < resp.getResponses().length; ++i) { + WebdavEntry we = new WebdavEntry(resp.getResponses()[i], getUri().getPath()); + OCFile file = fillOCFile(we); + file.setParentId(parentId); + if (getStorageManager().getFileByPath(file.getRemotePath()) != null && + getStorageManager().getFileByPath(file.getRemotePath()).keepInSync() && + file.getModificationTimestamp() > getStorageManager().getFileByPath(file.getRemotePath()) + .getModificationTimestamp()) { + Intent intent = new Intent(this.getContext(), FileDownloader.class); + intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount()); + intent.putExtra(FileDownloader.EXTRA_FILE_PATH, file.getRemotePath()); + intent.putExtra(FileDownloader.EXTRA_REMOTE_PATH, file.getRemotePath()); + intent.putExtra(FileDownloader.EXTRA_FILE_SIZE, file.getFileLength()); + file.setKeepInSync(true); + getContext().startService(intent); + } + if (getStorageManager().getFileByPath(file.getRemotePath()) != null) + file.setKeepInSync(getStorageManager().getFileByPath(file.getRemotePath()).keepInSync()); + + //getStorageManager().saveFile(file); + updatedFiles.add(file); + if (parentId == 0) + parentId = file.getFileId(); + } + /* Commented code for ugly performance tests + long saveDelay = System.currentTimeMillis(); + */ + getStorageManager().saveFiles(updatedFiles); // all "at once" ; trying to get a best performance in database update + /* Commented code for ugly performance tests + saveDelay = System.currentTimeMillis() - saveDelay; + Log.e(TAG, "syncing: SAVE TIME for " + uri + " contents, " + mSaveDelays[mDelaysIndex] + "ms"); + */ + + // removal of obsolete files + Vector files = getStorageManager().getDirectoryContent( + getStorageManager().getFileById(parentId)); + OCFile file; + for (int i=0; i < files.size(); ) { + file = files.get(i); + if (file.getLastSyncDate() != mCurrentSyncTime && file.getLastSyncDate() != 0) { + getStorageManager().removeFile(file); + files.remove(i); + } else { + i++; + } + } + + // synchronized folder -> notice to UI + sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath()); + + // recursive fetch + for (int i=0; i < files.size() && !mCancellation; i++) { + OCFile newFile = files.get(i); + if (newFile.getMimetype().equals("DIR")) { + fetchData(getUri().toString() + WebdavUtils.encodePath(newFile.getRemotePath()), syncResult, newFile.getFileId()); + } + } + if (mCancellation) Log.d(TAG, "Leaving " + uri + " because cancellation request"); + + /* Commented code for ugly performance tests + mResponseDelays[mDelaysIndex] = responseDelay; + mSaveDelays[mDelaysIndex] = saveDelay; + mDelaysCount++; + mDelaysIndex++; + if (mDelaysIndex >= MAX_DELAYS) + mDelaysIndex = 0; + */ + + + + } catch (OperationCanceledException e) { + e.printStackTrace(); + } catch (AuthenticatorException e) { + syncResult.stats.numAuthExceptions++; + e.printStackTrace(); + } catch (IOException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (DavException e) { + syncResult.stats.numIoExceptions++; + e.printStackTrace(); + } catch (Throwable t) { + // TODO update syncResult + Log.e(TAG, "problem while synchronizing owncloud account " + mAccount.name, t); + t.printStackTrace(); + } + } + + private OCFile fillOCFile(WebdavEntry we) { + OCFile file = new OCFile(we.decodedPath()); + file.setCreationTimestamp(we.createTimestamp()); + file.setFileLength(we.contentLength()); + file.setMimetype(we.contentType()); + file.setModificationTimestamp(we.modifiedTimesamp()); + file.setLastSyncDate(mCurrentSyncTime); + return file; + } + + + private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) { + Intent i = new Intent(FileSyncService.SYNC_MESSAGE); + i.putExtra(FileSyncService.IN_PROGRESS, inProgress); + i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name); + if (dirRemotePath != null) { + i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath); + } + getContext().sendStickyBroadcast(i); + } + + /** + * Called by system SyncManager when a synchronization is required to be cancelled. + * + * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder + * fetched will be still saved in the database. See onPerformSync implementation. + */ + @Override + public void onSyncCanceled() { + Log.d(TAG, "Synchronization of " + mAccount.name + " has been requested to cancell"); + mCancellation = true; + super.onSyncCanceled(); + } + }