Browse Source

Updating synchronization for providing SSL warning when necessary; step 1: refactoring based in RemoteOperation (in progress)

David A. Velasco 12 years ago
parent
commit
67eb921007

+ 1 - 1
src/com/owncloud/android/network/CertificateCombinedException.java

@@ -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;

+ 10 - 1
src/com/owncloud/android/operations/RemoteOperationResult.java

@@ -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;

+ 193 - 0
src/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -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;
+    }
+    
+}

+ 6 - 2
src/com/owncloud/android/syncadapter/FileSyncAdapter.java

@@ -34,6 +34,7 @@ import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.operations.RemoteOperationResult;
 import com.owncloud.android.utils.OwnCloudVersion;
 
 import android.accounts.Account;
@@ -97,7 +98,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
 
         Log.d(TAG, "syncing owncloud account " + account.name);
 
-        sendStickyBroadcast(true, null);  // message to signal the start to the UI
+        sendStickyBroadcast(true, null, null);  // message to signal the start to the UI
         
         updateOCVersion();
 
@@ -315,13 +316,16 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
     }
     
     
-    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath) {
+    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {
         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);
         }
+        if (result != null) {
+            i.putExtra(FileSyncService.SYNC_RESULT, result);
+        }
         getContext().sendStickyBroadcast(i);
     }
     

+ 1 - 0
src/com/owncloud/android/syncadapter/FileSyncService.java

@@ -32,6 +32,7 @@ public class FileSyncService extends Service {
     public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH";
     public static final String IN_PROGRESS = "SYNC_IN_PROGRESS";
     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
+    public static final String SYNC_RESULT = "SYNC_RESULT";
 
     /*
      * {@inheritDoc}