Bug 735297 - Documentation for RepositorySession. r=nalexander
authorRichard Newman <rnewman@mozilla.com>
Tue, 13 Mar 2012 15:48:26 -0700
changeset 92299 699d3936575be3417ec820b7861d2cea0099cea4
parent 92298 62c8e6a841e7a9dee186c61b9cb65d20eabaeaea
child 92300 0339a626ec58018cdfc3b279e7a336770dd73eec
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander
bugs735297
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 735297 - Documentation for RepositorySession. r=nalexander
mobile/android/base/sync/repositories/RepositorySession.java
mobile/android/base/sync/setup/SyncAccounts.java
--- a/mobile/android/base/sync/repositories/RepositorySession.java
+++ b/mobile/android/base/sync/repositories/RepositorySession.java
@@ -1,45 +1,11 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android Sync Client.
- *
- * The Initial Developer of the Original Code is
- * the Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Jason Voll <jvoll@mozilla.com>
- * Richard Newman <rnewman@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories;
 
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -48,26 +14,32 @@ import org.mozilla.gecko.sync.repositori
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 /**
- * A RepositorySession is created and used thusly:
+ * A <code>RepositorySession</code> is created and used thusly:
  *
- * * Construct, with a reference to its parent Repository, by calling
- *   Repository.createSession().
- * * Populate with saved information by calling unbundle().
- * * Begin a sync by calling begin().
- * * Perform operations such as fetchSince() and store().
- * * Finish by calling finish(), retrieving and storing the current bundle.
+ *<ul>
+ * <li>Construct, with a reference to its parent {@link Repository}, by calling
+ *   {@link Repository#createSession(RepositorySessionCreationDelegate, android.content.Context)}.</li>
+ * <li>Populate with saved information by calling {@link #unbundle(RepositorySessionBundle)}.</li>
+ * <li>Begin a sync by calling {@link #begin(RepositorySessionBeginDelegate)}. <code>begin()</code>
+ *   is an appropriate place to initialize expensive resources.</li>
+ * <li>Perform operations such as {@link #fetchSince(long, RepositorySessionFetchRecordsDelegate)} and
+ *   {@link #store(Record)}.</li>
+ * <li>Finish by calling {@link #finish(RepositorySessionFinishDelegate)}, retrieving and storing
+ *   the current bundle.</li>
+ *</ul>
  *
- * @author rnewman
+ * If <code>finish()</code> is not called, {@link #abort()} must be called. These calls must
+ * <em>always</em> be paired with <code>begin()</code>.
  *
  */
 public abstract class RepositorySession {
 
   public enum SessionStatus {
     UNSTARTED,
     ACTIVE,
     ABORTED,
@@ -187,16 +159,23 @@ public abstract class RepositorySession 
       throw new InvalidSessionTransitionException(null);
     }
     if (storeWorkQueue.isShutdown()) {
       throw new InvalidSessionTransitionException(null);
     }
     this.transitionFrom(SessionStatus.UNSTARTED, SessionStatus.ACTIVE);
   }
 
+  /**
+   * Start the session. This is an appropriate place to initialize
+   * data access components such as database handles.
+   *
+   * @param delegate
+   * @throws InvalidSessionTransitionException
+   */
   public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
     sharedBegin();
     delegate.deferredBeginDelegate(delegateQueue).onBeginSucceeded(this);
   }
 
   protected RepositorySessionBundle getBundle() {
     return this.getBundle(null);
   }
@@ -223,31 +202,42 @@ public abstract class RepositorySession 
    * Just like finish(), but doesn't do any work that should only be performed
    * at the end of a successful sync, and can be called any time.
    */
   public void abort(RepositorySessionFinishDelegate delegate) {
     this.abort();
     delegate.deferredFinishDelegate(delegateQueue).onFinishSucceeded(this, this.getBundle(null));
   }
 
+  /**
+   * Abnormally terminate the repository session, freeing or closing
+   * any resources that were opened during the lifetime of the session.
+   */
   public void abort() {
     // TODO: do something here.
     this.setStatus(SessionStatus.ABORTED);
     try {
       storeWorkQueue.shutdown();
     } catch (Exception e) {
       Logger.error(LOG_TAG, "Caught exception shutting down store work queue.", e);
     }
     try {
       delegateQueue.shutdown();
     } catch (Exception e) {
       Logger.error(LOG_TAG, "Caught exception shutting down delegate queue.", e);
     }
   }
 
+  /**
+   * End the repository session, freeing or closing any resources
+   * that were opened during the lifetime of the session.
+   *
+   * @param delegate notified of success or failure.
+   * @throws InactiveSessionException
+   */
   public void finish(final RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
     try {
       this.transitionFrom(SessionStatus.ACTIVE, SessionStatus.DONE);
       delegate.deferredFinishDelegate(delegateQueue).onFinishSucceeded(this, this.getBundle(null));
     } catch (InvalidSessionTransitionException e) {
       Logger.error(LOG_TAG, "Tried to finish() an unstarted or already finished session");
       InactiveSessionException ex = new InactiveSessionException(null);
       ex.initCause(e);
--- a/mobile/android/base/sync/setup/SyncAccounts.java
+++ b/mobile/android/base/sync/setup/SyncAccounts.java
@@ -12,46 +12,60 @@ import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.util.Log;
 
+/**
+ * This class contains utilities that are of use to Fennec
+ * and Sync setup activities.
+ *
+ * Do not break these APIs without correcting upstream code!
+ */
 public class SyncAccounts {
 
   private final static String DEFAULT_SERVER = "https://auth.services.mozilla.com/";
   private static final String LOG_TAG = "SyncAccounts";
 
   /**
+   * Returns true if a Sync account is set up.
+   *
+   * Do not call this method from the main thread.
+   */
+  public static boolean syncAccountsExist(Context c) {
+    return AccountManager.get(c).getAccountsByType("org.mozilla.firefox_sync").length > 0;
+  }
+
+  /**
    * This class provides background-thread abstracted access to whether a
    * Firefox Sync account has been set up on this device.
    *
    * Subclass this task and override `onPostExecute` to act on the result.
    */
   public static class AccountsExistTask extends AsyncTask<Context, Void, Boolean> {
     @Override
     protected Boolean doInBackground(Context... params) {
       Context c = params[0];
-      return AccountManager.get(c).getAccountsByType("org.mozilla.firefox_sync").length > 0;
+      return syncAccountsExist(c);
     }
   }
 
-  // TODO: lift this out.
   public static Intent createAccount(Context context,
                                      AccountManager accountManager,
                                      String username,
                                      String syncKey,
                                      String password,
                                      String serverURL) {
 
     final Account account = new Account(username, Constants.ACCOUNTTYPE_SYNC);
     final Bundle userbundle = new Bundle();
-  
+
     // Add sync key and server URL.
     userbundle.putString(Constants.OPTION_SYNCKEY, syncKey);
     if (serverURL != null) {
       Logger.info(LOG_TAG, "Setting explicit server URL: " + serverURL);
       userbundle.putString(Constants.OPTION_SERVER, serverURL);
     } else {
       userbundle.putString(Constants.OPTION_SERVER, DEFAULT_SERVER);
     }
@@ -66,41 +80,41 @@ public class SyncAccounts {
                 "Unable to create account. " +
                 "If you have more than one version of " +
                 "Firefox/Beta/Aurora/Nightly/Fennec installed, that's why.",
                 e);
       } else {
         Log.e("FirefoxSync", "Unable to create account.", e);
       }
     }
-  
+
     Logger.debug(LOG_TAG, "Account: " + account + " added successfully? " + result);
     if (!result) {
       Logger.error(LOG_TAG, "Failed to add account!");
     }
-  
+
     // Set components to sync (default: all).
     ContentResolver.setMasterSyncAutomatically(true);
-  
+
     String authority = BrowserContract.AUTHORITY;
     Logger.debug(LOG_TAG, "Setting authority " + authority + " to sync automatically.");
     ContentResolver.setSyncAutomatically(account, authority, true);
     ContentResolver.setIsSyncable(account, authority, 1);
-  
+
     // TODO: add other ContentProviders as needed (e.g. passwords)
     // TODO: for each, also add to res/xml to make visible in account settings
     Logger.debug(LOG_TAG, "Finished setting syncables.");
-  
+
     // TODO: correctly implement Sync Options.
     Logger.info(LOG_TAG, "Clearing preferences for this account.");
     try {
       Utils.getSharedPreferences(context, username, serverURL).edit().clear().commit();
     } catch (Exception e) {
       Logger.error(LOG_TAG, "Could not clear prefs path!", e);
     }
-  
+
     final Intent intent = new Intent();
     intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, username);
     intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNTTYPE_SYNC);
     intent.putExtra(AccountManager.KEY_AUTHTOKEN, Constants.ACCOUNTTYPE_SYNC);
     return intent;
   }
 }