1 // Copyright 2011 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.api
.log
;
5 import static com
.google
.common
.io
.BaseEncoding
.base64
;
7 import com
.google
.apphosting
.api
.logservice
.LogServicePb
.LogOffset
;
8 import com
.google
.apphosting
.api
.logservice
.LogServicePb
.LogReadResponse
;
9 import com
.google
.apphosting
.api
.logservice
.LogServicePb
.RequestLog
;
10 import com
.google
.common
.base
.CharMatcher
;
11 import com
.google
.common
.collect
.AbstractIterator
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collections
;
15 import java
.util
.Iterator
;
16 import java
.util
.List
;
19 * An object that is the result of performing a LogService.fetch() operation.
20 * LogQueryResults contain the logs from the user's query. Users of this service
21 * should use the {@link LogQueryResult#iterator} provided by this class to
22 * retrieve their results.
25 public final class LogQueryResult
implements Iterable
<RequestLogs
> {
26 private final List
<RequestLogs
> logs
;
27 private final String cursor
;
28 private final LogQuery query
;
30 protected LogQueryResult(LogReadResponse response
, LogQuery originalQuery
) {
31 logs
= new ArrayList
<RequestLogs
>();
32 for (RequestLog log
: response
.logs()) {
33 String offset
= base64().encode(log
.getOffset().toByteArray());
34 logs
.add(new RequestLogs(log
, offset
));
37 if (response
.hasOffset()) {
38 cursor
= base64().encode(response
.getOffset().toByteArray());
43 query
= originalQuery
.clone();
47 * Returns a LogOffset parsed from the submitted String, which is assumed to
48 * be a Base64-encoded offset produced by this class.
50 * @return A String to parse as a Base64-encoded LogOffset protocol buffer.
52 protected static LogOffset
parseOffset(String offset
) {
53 LogOffset logOffset
= new LogOffset();
56 logOffset
.parseFrom(base64().decode(CharMatcher
.WHITESPACE
.removeFrom(offset
)));
57 if (!parsed
|| !logOffset
.isInitialized()) {
58 throw new IllegalArgumentException();
60 } catch (IllegalArgumentException e
) {
61 throw new IllegalArgumentException("Can not parse provided offset.");
67 * Returns the list of logs internally kept by this class. The main user of
68 * this method is iterator, who needs it to give the user logs as needed.
70 * @return A List of RequestLogs acquired from a fetch() request.
72 private List
<RequestLogs
> getLogs() {
73 return Collections
.unmodifiableList(logs
);
77 * Returns the String version of the database cursor, which can be used to
78 * tell subsequent fetch() requests where to start scanning from. The main
79 * user of this method is iterator, who uses it to ensure that users get all
80 * the logs they requested.
82 * @return A String representing the next location in the database to read
85 private String
getCursor() {
90 * Returns an Iterator that will yield all of the logs the user has requested.
91 * If the user has asked for more logs than a single request can accommodate
92 * (which is LogService.MAX_ITEMS_PER_FETCH), then this iterator grabs
93 * the first batch and returns them until they are exhausted. Once they are
94 * exhausted, a fetch() call is made to get more logs and the process is
95 * repeated until either all of the logs have been read or the user has
96 * stopped asking for more logs.
98 * @return An iterator that provides RequestLogs to the caller.
101 public Iterator
<RequestLogs
> iterator() {
102 return new AbstractIterator
<RequestLogs
>() {
103 List
<RequestLogs
> iterLogs
= logs
;
104 String iterCursor
= cursor
;
106 int lengthLogs
= iterLogs
.size();
109 protected RequestLogs
computeNext() {
110 while (index
>= lengthLogs
) {
111 if (iterCursor
== null) {
115 query
.offset(iterCursor
);
117 LogQueryResult nextResults
= new LogServiceImpl().fetch(query
);
118 iterLogs
= nextResults
.getLogs();
119 iterCursor
= nextResults
.getCursor();
120 lengthLogs
= iterLogs
.size();
124 return iterLogs
.get(index
++);