Skip to content

Commit f7f7c62

Browse files
Merge branch 'mrschmidt/bundle/reader' into mrschmidt/bundle/localstore
2 parents bf05d41 + 0dd9887 commit f7f7c62

File tree

7 files changed

+52
-57
lines changed

7 files changed

+52
-57
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/bundle/BundleDocument.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import com.google.firebase.firestore.model.DocumentKey;
1919

2020
/** A document that was saved to a bundle. */
21-
public class BundleDocument extends BundleElement {
21+
public class BundleDocument implements BundleElement {
2222
private Document document;
2323

2424
public BundleDocument(Document document) {

firebase-firestore/src/main/java/com/google/firebase/firestore/bundle/BundleElement.java

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,4 @@
1414

1515
package com.google.firebase.firestore.bundle;
1616

17-
import org.json.JSONException;
18-
import org.json.JSONObject;
19-
20-
public abstract class BundleElement {
21-
22-
public static BundleElement fromJson(BundleSerializer serializer, String json)
23-
throws JSONException {
24-
JSONObject object = new JSONObject(json);
25-
26-
if (object.has("metadata")) {
27-
return serializer.decodeBundleMetadata(object.getJSONObject("metadata"));
28-
} else if (object.has("namedQuery")) {
29-
return serializer.decodeNamedQuery(object.getJSONObject("namedQuery"));
30-
} else if (object.has("documentMetadata")) {
31-
return serializer.decodeBundledDocumentMetadata(object.getJSONObject("documentMetadata"));
32-
} else if (object.has("document")) {
33-
return serializer.decodeDocument(object.getJSONObject("document"));
34-
} else {
35-
throw new IllegalArgumentException("Cannot decode unknown Bundle element: " + json);
36-
}
37-
}
38-
39-
protected BundleElement() {}
40-
}
17+
public interface BundleElement {}

firebase-firestore/src/main/java/com/google/firebase/firestore/bundle/BundleMetadata.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import com.google.firebase.firestore.model.SnapshotVersion;
1818

1919
/** Represents a Firestore bundle saved by the SDK in its local storage. */
20-
public class BundleMetadata extends BundleElement {
20+
public class BundleMetadata implements BundleElement {
2121
private final String bundleId;
2222
private final int version;
2323
private final SnapshotVersion createTime;

firebase-firestore/src/main/java/com/google/firebase/firestore/bundle/BundleReader.java

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@
1919
import java.io.InputStream;
2020
import java.io.InputStreamReader;
2121
import java.nio.CharBuffer;
22+
import java.nio.charset.Charset;
2223
import org.json.JSONException;
24+
import org.json.JSONObject;
2325

2426
/**
2527
* Reads the length-prefixed JSON stream for Bundles.
2628
*
2729
* <p>The class takes a bundle stream and presents abstractions to read bundled elements out of the
2830
* underlying content.
2931
*/
30-
public class BundleReader extends BundleElement {
32+
public class BundleReader {
3133
/** The capacity for the internal char buffer. */
3234
protected static final int BUFFER_CAPACITY = 1024;
3335

@@ -40,8 +42,10 @@ public class BundleReader extends BundleElement {
4042

4143
public BundleReader(BundleSerializer serializer, InputStream data) {
4244
this.serializer = serializer;
43-
dataReader = new InputStreamReader(data);
45+
dataReader = new InputStreamReader(data, Charset.forName("UTF-8"));
4446
buffer = CharBuffer.allocate(BUFFER_CAPACITY);
47+
48+
buffer.flip(); // Start the buffer in "reading mode"
4549
}
4650

4751
/** Returns the metadata element from the bundle. */
@@ -91,23 +95,23 @@ public void close() throws IOException {
9195
*/
9296
@Nullable
9397
private BundleElement readNextElement() throws IOException, JSONException {
94-
int length = readLength();
95-
if (length == -1) {
98+
String lengthPrefix = readLengthPrefix();
99+
if (lengthPrefix == null) {
96100
return null;
97101
}
98102

99-
String json = readJsonString(length);
100-
bytesRead += (int) (Math.log10(length) + 1) + length;
101-
return BundleElement.fromJson(serializer, json);
103+
String json = readJsonString(Integer.parseInt(lengthPrefix));
104+
bytesRead += lengthPrefix.length() + json.length();
105+
return decodeBundleElement(json);
102106
}
103107

104108
/**
105109
* Reads the length prefix from the beginning of the internal buffer until the first '{'. Returns
106110
* the integer-decoded length.
107111
*
108-
* <p>If it reached the end of the stream, returns -1.
112+
* <p>If it reached the end of the stream, returns null.
109113
*/
110-
private int readLength() throws IOException {
114+
private @Nullable String readLengthPrefix() throws IOException {
111115
int nextOpenBracket;
112116

113117
while ((nextOpenBracket = indexOfOpenBracket()) == -1) {
@@ -119,7 +123,7 @@ private int readLength() throws IOException {
119123
// We broke out of the loop because underlying stream is closed, and there happens to be no
120124
// more data to process.
121125
if (buffer.remaining() == 0) {
122-
return -1;
126+
return null;
123127
}
124128

125129
// We broke out of the loop because underlying stream is closed, but still cannot find an
@@ -130,14 +134,14 @@ private int readLength() throws IOException {
130134

131135
char[] c = new char[nextOpenBracket];
132136
buffer.get(c);
133-
return Integer.parseInt(new String(c));
137+
return new String(c);
134138
}
135139

136140
/** Returns the index of the first open bracket, or -1 if none is found. */
137141
private int indexOfOpenBracket() {
138142
buffer.mark();
139143
try {
140-
for (int i = 0; i < buffer.limit(); ++i) {
144+
for (int i = 0; i < buffer.remaining(); ++i) {
141145
if (buffer.get() == '{') {
142146
return i;
143147
}
@@ -155,20 +159,22 @@ private int indexOfOpenBracket() {
155159
* <p>Returns a string decoded from the read bytes.
156160
*/
157161
private String readJsonString(int length) throws IOException {
158-
char[] c = new char[length];
162+
StringBuilder json = new StringBuilder();
159163

160-
int read = Math.min(length, buffer.remaining());
161-
buffer.get(c, 0, read);
162-
163-
while (read < length) {
164+
int remaining = length;
165+
while (remaining > 0) {
164166
if (!pullMoreData()) {
165167
raiseError("Reached the end of bundle when more data was expected.");
166168
}
167-
int toRead = Math.min(length, buffer.remaining());
168-
buffer.get(c, read, toRead);
169-
read += toRead;
169+
170+
int read = Math.min(remaining, buffer.remaining());
171+
json.append(buffer, 0, read);
172+
buffer.position(buffer.position() + read);
173+
174+
remaining -= read;
170175
}
171-
return new String(c);
176+
177+
return json.toString();
172178
}
173179

174180
/**
@@ -179,17 +185,29 @@ private String readJsonString(int length) throws IOException {
179185
private boolean pullMoreData() throws IOException {
180186
if (buffer.remaining() == 0) {
181187
buffer.compact();
188+
dataReader.read(buffer);
189+
buffer.flip();
182190
}
183-
184-
int read;
185-
do {
186-
read = dataReader.read(buffer);
187-
} while (read > 0);
188-
buffer.flip();
189-
190191
return buffer.remaining() > 0;
191192
}
192193

194+
/** Converts a JSON-encoded bundle element into its model class. */
195+
private BundleElement decodeBundleElement(String json) throws JSONException {
196+
JSONObject object = new JSONObject(json);
197+
198+
if (object.has("metadata")) {
199+
return serializer.decodeBundleMetadata(object.getJSONObject("metadata"));
200+
} else if (object.has("namedQuery")) {
201+
return serializer.decodeNamedQuery(object.getJSONObject("namedQuery"));
202+
} else if (object.has("documentMetadata")) {
203+
return serializer.decodeBundledDocumentMetadata(object.getJSONObject("documentMetadata"));
204+
} else if (object.has("document")) {
205+
return serializer.decodeDocument(object.getJSONObject("document"));
206+
} else {
207+
throw new IllegalArgumentException("Cannot decode unknown Bundle element: " + json);
208+
}
209+
}
210+
193211
/** Closes the underlying stream and raises an IllegalArgumentException. */
194212
private void raiseError(String message) throws IOException {
195213
close();

firebase-firestore/src/main/java/com/google/firebase/firestore/bundle/BundledDocumentMetadata.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
// TODO(bundles): Figure out whether we need this class (it is not needed in Web).
2222

2323
/** Metadata describing a Firestore document saved in the bundle. */
24-
public class BundledDocumentMetadata extends BundleElement {
24+
public class BundledDocumentMetadata implements BundleElement {
2525
private final DocumentKey key;
2626
private final SnapshotVersion readTime;
2727
private final boolean exists;

firebase-firestore/src/main/java/com/google/firebase/firestore/bundle/BundledQuery.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import com.google.firebase.firestore.core.Target;
1919

2020
/** A bundled query represents a query target and its limit. */
21-
public class BundledQuery extends BundleElement {
21+
public class BundledQuery implements BundleElement {
2222
private final Target target;
2323
private final Query.LimitType limitType;
2424

firebase-firestore/src/main/java/com/google/firebase/firestore/bundle/NamedQuery.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import com.google.firebase.firestore.model.SnapshotVersion;
1818

1919
/** Represents a named query saved by the SDK in its local storage. */
20-
public class NamedQuery extends BundleElement {
20+
public class NamedQuery implements BundleElement {
2121
private final String name;
2222
private final BundledQuery bundledQuery;
2323
private final SnapshotVersion readTime;

0 commit comments

Comments
 (0)