Updating synchronization for providing SSL warning when necessary; step 1: refactorin...
authorDavid A. Velasco <dvelasco@solidgear.es>
Mon, 22 Oct 2012 13:11:59 +0000 (15:11 +0200)
committerDavid A. Velasco <dvelasco@solidgear.es>
Mon, 22 Oct 2012 13:11:59 +0000 (15:11 +0200)
src/com/owncloud/android/network/CertificateCombinedException.java
src/com/owncloud/android/operations/RemoteOperationResult.java
src/com/owncloud/android/operations/SynchronizeFolderOperation.java [new file with mode: 0644]
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/syncadapter/FileSyncService.java

index fad7a6f..27427dd 100644 (file)
@@ -45,7 +45,7 @@ import javax.net.ssl.SSLPeerUnverifiedException;
  */
 public class CertificateCombinedException extends RuntimeException {
 
-    /** Generated */
+    /** Generated - to refresh every time the class changes */
     private static final long serialVersionUID = -8875782030758554999L;
     
     private X509Certificate mServerCert = null;
index 0618b86..1415228 100644 (file)
@@ -19,6 +19,7 @@
 package com.owncloud.android.operations;
 
 import java.io.IOException;
+import java.io.Serializable;
 import java.net.MalformedURLException;
 import java.net.SocketException;
 import java.net.SocketTimeoutException;
@@ -40,13 +41,18 @@ import com.owncloud.android.network.CertificateCombinedException;
  * 
  * @author David A. Velasco
  */
-public class RemoteOperationResult {
+public class RemoteOperationResult implements Serializable {
+    
+    /** Generated - to refresh every time the class changes */
+    private static final long serialVersionUID = -7805531062432602444L;
+
     
     public enum ResultCode { 
         OK,
         OK_SSL,
         OK_NO_SSL,
         UNHANDLED_HTTP_CODE,
+        UNAUTHORIZED,        
         FILE_NOT_FOUND, 
         INSTANCE_NOT_CONFIGURED, 
         UNKNOWN_ERROR, 
@@ -81,6 +87,9 @@ public class RemoteOperationResult {
             
         } else if (httpCode > 0) {
             switch (httpCode) {
+                case HttpStatus.SC_UNAUTHORIZED:
+                    mCode = ResultCode.UNAUTHORIZED;
+                    break;
                 case HttpStatus.SC_NOT_FOUND:
                     mCode = ResultCode.FILE_NOT_FOUND;
                     break;
diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java
new file mode 100644 (file)
index 0000000..36b9b22
--- /dev/null
@@ -0,0 +1,193 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.operations;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.http.HttpStatus;
+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.content.Intent;
+import android.util.Log;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavEntry;
+import eu.alefzero.webdav.WebdavUtils;
+
+
+/**
+ * Remote operation performing the synchronization a the contents of a remote folder with the local database
+ * 
+ * @author David A. Velasco
+ */
+public class SynchronizeFolderOperation extends RemoteOperation {
+
+    private static final String TAG = SynchronizeFolderOperation.class.getCanonicalName();
+
+    /** Remote folder to synchronize */
+    private String mRemotePath;
+    
+    /** Timestamp for the synchronization in progress */
+    private long mCurrentSyncTime;
+    
+    /** Id of the folder to synchronize in the local database */
+    private long mParentId;
+    
+    /** Access to the local database */
+    private FileDataStorageManager mStorageManager;
+    
+    /** Account where the file to synchronize belongs */
+    private Account mAccount;
+    
+    
+    SynchronizeFolderOperation(String remotePath, long currentSyncTime, long parentId, FileDataStorageManager storageManager, Account account) {
+        mRemotePath = remotePath;
+        mCurrentSyncTime = currentSyncTime;
+        mParentId = parentId;
+        mStorageManager = storageManager;
+        mAccount = account;
+    }
+    
+    
+    @Override
+    protected RemoteOperationResult run(WebdavClient client) {
+        RemoteOperationResult result = null;
+        
+        // code before in FileSyncAdapter.fetchData
+        PropFindMethod query = null;
+        Vector<OCFile> children = null;
+        try {
+            Log.d(TAG, "Fetching files in " + mRemotePath);
+            
+            // remote request 
+            query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
+            int status = client.executeMethod(query);
+            
+            if (isSuccess(status)) { 
+                
+                MultiStatus resp = query.getResponseBodyAsMultiStatus();
+            
+                // reading files
+                List<OCFile> updatedFiles = new Vector<OCFile>(resp.getResponses().length - 1);
+                for (int i = 1; i < resp.getResponses().length; ++i) {
+                    WebdavEntry we = new WebdavEntry(resp.getResponses()[i], client.getBaseUri().getPath());
+                    OCFile file = fillOCFile(we);
+                    file.setParentId(mParentId);
+                    OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath());
+                    if (oldFile != null) {
+                        if (oldFile.keepInSync() && file.getModificationTimestamp() > oldFile.getModificationTimestamp()) {
+                            requestContentDownload();
+                        }
+                        file.setKeepInSync(oldFile.keepInSync());
+                    }
+                
+                    updatedFiles.add(file);
+                }
+                
+                
+                // save updated files in local database; all at once, trying to get a best performance in database update (not a big deal, indeed)
+                mStorageManager.saveFiles(updatedFiles);
+
+                
+                // removal of obsolete files
+                children = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId));
+                OCFile file;
+                String currentSavePath = FileDownloader.getSavePath(mAccount.name);
+                for (int i=0; i < children.size(); ) {
+                    file = children.get(i);
+                    if (file.getLastSyncDate() != mCurrentSyncTime) {
+                        Log.d(TAG, "removing file: " + file);
+                        mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath)));
+                        children.remove(i);
+                    } else {
+                        i++;
+                    }
+                }
+                
+            } else if (status == HttpStatus.SC_UNAUTHORIZED) {
+                syncResult.stats.numAuthExceptions++;
+                
+            } else {
+                // TODO something smart with syncResult? OR NOT
+            }
+            
+            result = new RemoteOperationResult(isSuccess(status), status);
+            Log.i(TAG, "Synchronization of " + mRemotePath + ": " + result.getLogMessage());
+            
+            
+        } catch (IOException e) {
+            syncResult.stats.numIoExceptions++;
+            logException(e, uri);
+            
+        } catch (DavException e) {
+            syncResult.stats.numParseExceptions++;
+            logException(e, uri);
+            
+        } catch (Exception e) {
+            // TODO something smart with syncresult
+            mRightSync = false;
+            logException(e, uri);
+
+        } finally {
+            if (query != null)
+                query.releaseConnection();  // let the connection available for other methods
+
+            // synchronized folder -> notice to UI
+            sendStickyBroadcast(true, getStorageManager().getFileById(parentId).getRemotePath());
+        }
+        
+        
+        return result;
+    }
+    
+    
+    public boolean isSuccess(int status) {
+        return (status == HttpStatus.SC_MULTI_STATUS); // TODO check other possible OK codes; doc doesn't help
+    }
+
+
+    private void requestContentDownload() {
+        Intent intent = new Intent(this.getContext(), FileDownloader.class);
+        intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount());
+        intent.putExtra(FileDownloader.EXTRA_FILE, file);
+        file.setKeepInSync(true);
+        getContext().startService(intent);
+    }
+
+
+    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;
+    }
+    
+}
index 5b398c0..db9d87d 100644 (file)
@@ -34,6 +34,7 @@ import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.datamodel.FileDataStorageManager;\r
 import com.owncloud.android.datamodel.OCFile;\r
 import com.owncloud.android.files.services.FileDownloader;\r
+import com.owncloud.android.operations.RemoteOperationResult;\r
 import com.owncloud.android.utils.OwnCloudVersion;\r
 \r
 import android.accounts.Account;\r
@@ -97,7 +98,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
 \r
         Log.d(TAG, "syncing owncloud account " + account.name);\r
 \r
-        sendStickyBroadcast(true, null);  // message to signal the start to the UI\r
+        sendStickyBroadcast(true, null, null);  // message to signal the start to the UI\r
         \r
         updateOCVersion();\r
 \r
@@ -315,13 +316,16 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
     }\r
     \r
     \r
-    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) {\r
+    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {\r
         Intent i = new Intent(FileSyncService.SYNC_MESSAGE);\r
         i.putExtra(FileSyncService.IN_PROGRESS, inProgress);\r
         i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);\r
         if (dirRemotePath != null) {\r
             i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);\r
         }\r
+        if (result != null) {\r
+            i.putExtra(FileSyncService.SYNC_RESULT, result);\r
+        }\r
         getContext().sendStickyBroadcast(i);\r
     }\r
     \r
index 74c7fa6..cb2f720 100644 (file)
@@ -32,6 +32,7 @@ public class FileSyncService extends Service {
     public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH";\r
     public static final String IN_PROGRESS = "SYNC_IN_PROGRESS";\r
     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
+    public static final String SYNC_RESULT = "SYNC_RESULT";\r
 \r
     /*\r
      * {@inheritDoc}\r