mobile/android/base/sync/JSONRecordFetcher.java

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 package org.mozilla.gecko.sync;
michael@0 6
michael@0 7 import java.util.concurrent.CountDownLatch;
michael@0 8 import java.util.concurrent.TimeUnit;
michael@0 9
michael@0 10 import org.mozilla.gecko.background.common.log.Logger;
michael@0 11 import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
michael@0 12 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
michael@0 13 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
michael@0 14 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
michael@0 15 import org.mozilla.gecko.sync.net.SyncStorageResponse;
michael@0 16
michael@0 17 /**
michael@0 18 * An object which fetches a chunk of JSON from a URI, using certain credentials,
michael@0 19 * and informs its delegate of the result.
michael@0 20 */
michael@0 21 public class JSONRecordFetcher {
michael@0 22 private static final long DEFAULT_AWAIT_TIMEOUT_MSEC = 2 * 60 * 1000; // Two minutes.
michael@0 23 private static final String LOG_TAG = "JSONRecordFetcher";
michael@0 24
michael@0 25 protected final AuthHeaderProvider authHeaderProvider;
michael@0 26 protected final String uri;
michael@0 27 protected JSONRecordFetchDelegate delegate;
michael@0 28
michael@0 29 public JSONRecordFetcher(final String uri, final AuthHeaderProvider authHeaderProvider) {
michael@0 30 if (uri == null) {
michael@0 31 throw new IllegalArgumentException("uri must not be null");
michael@0 32 }
michael@0 33 this.uri = uri;
michael@0 34 this.authHeaderProvider = authHeaderProvider;
michael@0 35 }
michael@0 36
michael@0 37 protected String getURI() {
michael@0 38 return this.uri;
michael@0 39 }
michael@0 40
michael@0 41 private class JSONFetchHandler implements SyncStorageRequestDelegate {
michael@0 42
michael@0 43 // SyncStorageRequestDelegate methods for fetching.
michael@0 44 @Override
michael@0 45 public AuthHeaderProvider getAuthHeaderProvider() {
michael@0 46 return authHeaderProvider;
michael@0 47 }
michael@0 48
michael@0 49 public String ifUnmodifiedSince() {
michael@0 50 return null;
michael@0 51 }
michael@0 52
michael@0 53 public void handleRequestSuccess(SyncStorageResponse response) {
michael@0 54 if (response.wasSuccessful()) {
michael@0 55 try {
michael@0 56 delegate.handleSuccess(response.jsonObjectBody());
michael@0 57 } catch (Exception e) {
michael@0 58 handleRequestError(e);
michael@0 59 }
michael@0 60 return;
michael@0 61 }
michael@0 62 handleRequestFailure(response);
michael@0 63 }
michael@0 64
michael@0 65 @Override
michael@0 66 public void handleRequestFailure(SyncStorageResponse response) {
michael@0 67 delegate.handleFailure(response);
michael@0 68 }
michael@0 69
michael@0 70 @Override
michael@0 71 public void handleRequestError(Exception ex) {
michael@0 72 delegate.handleError(ex);
michael@0 73 }
michael@0 74 }
michael@0 75
michael@0 76 public void fetch(final JSONRecordFetchDelegate delegate) {
michael@0 77 this.delegate = delegate;
michael@0 78 try {
michael@0 79 final SyncStorageRecordRequest r = new SyncStorageRecordRequest(this.getURI());
michael@0 80 r.delegate = new JSONFetchHandler();
michael@0 81 r.get();
michael@0 82 } catch (Exception e) {
michael@0 83 delegate.handleError(e);
michael@0 84 }
michael@0 85 }
michael@0 86
michael@0 87 private class LatchedJSONRecordFetchDelegate implements JSONRecordFetchDelegate {
michael@0 88 public ExtendedJSONObject body = null;
michael@0 89 public Exception exception = null;
michael@0 90 private CountDownLatch latch;
michael@0 91
michael@0 92 public LatchedJSONRecordFetchDelegate(CountDownLatch latch) {
michael@0 93 this.latch = latch;
michael@0 94 }
michael@0 95
michael@0 96 @Override
michael@0 97 public void handleFailure(SyncStorageResponse response) {
michael@0 98 this.exception = new HTTPFailureException(response);
michael@0 99 latch.countDown();
michael@0 100 }
michael@0 101
michael@0 102 @Override
michael@0 103 public void handleError(Exception e) {
michael@0 104 this.exception = e;
michael@0 105 latch.countDown();
michael@0 106 }
michael@0 107
michael@0 108 @Override
michael@0 109 public void handleSuccess(ExtendedJSONObject body) {
michael@0 110 this.body = body;
michael@0 111 latch.countDown();
michael@0 112 }
michael@0 113 }
michael@0 114
michael@0 115 /**
michael@0 116 * Fetch the info record, blocking until it returns.
michael@0 117 * @return the info record.
michael@0 118 */
michael@0 119 public ExtendedJSONObject fetchBlocking() throws HTTPFailureException, Exception {
michael@0 120 CountDownLatch latch = new CountDownLatch(1);
michael@0 121 LatchedJSONRecordFetchDelegate delegate = new LatchedJSONRecordFetchDelegate(latch);
michael@0 122 this.delegate = delegate;
michael@0 123 this.fetch(delegate);
michael@0 124
michael@0 125 // Sanity wait: the resource itself will time out and throw after two
michael@0 126 // minutes, so we just want to avoid coding errors causing us to block
michael@0 127 // endlessly.
michael@0 128 if (!latch.await(DEFAULT_AWAIT_TIMEOUT_MSEC, TimeUnit.MILLISECONDS)) {
michael@0 129 Logger.warn(LOG_TAG, "Interrupted fetching info record.");
michael@0 130 throw new InterruptedException("info fetch timed out.");
michael@0 131 }
michael@0 132
michael@0 133 if (delegate.body != null) {
michael@0 134 return delegate.body;
michael@0 135 }
michael@0 136
michael@0 137 if (delegate.exception != null) {
michael@0 138 throw delegate.exception;
michael@0 139 }
michael@0 140
michael@0 141 throw new Exception("Unknown error.");
michael@0 142 }
michael@0 143 }

mercurial