122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray/* 322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * Copyright (C) 2010 Google Inc. 422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * 522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * Licensed under the Apache License, Version 2.0 (the "License"); 622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * you may not use this file except in compliance with the License. 722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * You may obtain a copy of the License at 822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * 922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * http://www.apache.org/licenses/LICENSE-2.0 1022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * 1122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * Unless required by applicable law or agreed to in writing, software 1222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * distributed under the License is distributed on an "AS IS" BASIS, 1322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * See the License for the specific language governing permissions and 1522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * limitations under the License. 1622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray */ 1722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 18ab49d110ea5f54b41b1a5780ba579c183f0c0a2bNicolas Geoffray// This file is a copy of caliper's InterleavedReader.java 19ab49d110ea5f54b41b1a5780ba579c183f0c0a2bNicolas Geoffray// (from code.google.com, last change Sep 9 2011) 20ab49d110ea5f54b41b1a5780ba579c183f0c0a2bNicolas Geoffray// with Android specific changes marked with "BEGIN android-changed". 21ab49d110ea5f54b41b1a5780ba579c183f0c0a2bNicolas Geoffray 2222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffraypackage vogar.monitor; 2322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 2422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffrayimport com.google.gson.JsonParser; 2522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 2622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffrayimport java.io.BufferedReader; 2722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffrayimport java.io.Closeable; 2822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffrayimport java.io.IOException; 2922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffrayimport java.io.Reader; 3022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 3122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray/** 3222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * Reads a stream containing inline JSON objects. Each JSON object is prefixed 3322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * by a marker string and suffixed by a newline character. 3422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray */ 3522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffraypublic final class InterleavedReader implements Closeable { 3622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 3722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray /** 3822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * The length of the scratch buffer to search for markers in. Also acts as an 3922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * upper bound on the length of returned strings. Not used as an I/O buffer. 4022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray */ 4122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray private static final int BUFFER_LENGTH = 80; 4222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 4322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray private final String marker; 4422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray private final BufferedReader reader; 4522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray private final JsonParser jsonParser = new JsonParser(); 4622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 4722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray public static final String DEFAULT_MARKER = "//ZxJ/"; 4822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 4922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray public InterleavedReader(Reader reader) { 5022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray this(DEFAULT_MARKER, reader); 5122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 5222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 5322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray public InterleavedReader(String marker, Reader reader) { 5422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray if (marker.length() > BUFFER_LENGTH) { 5522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray throw new IllegalArgumentException("marker.length() > BUFFER_LENGTH"); 5622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 5722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray this.marker = marker; 5822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray this.reader = reader instanceof BufferedReader 5922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray ? (BufferedReader) reader 6022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray : new BufferedReader(reader); 6122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 6222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 6322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray /** 6422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * Returns the next value in the stream: either a String, a JsonElement, or 6522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * null to indicate the end of the stream. Callers should use instanceof to 6622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * inspect the return type. 6722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray */ 6822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray public Object read() throws IOException { 6922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray char[] buffer = new char[BUFFER_LENGTH]; 70ab49d110ea5f54b41b1a5780ba579c183f0c0a2bNicolas Geoffray // BEGIN android-changed: 7122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // Double the lookahead size. This is a safety measure in the presence of 7222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // new lines, where the line feed character is being skipped. The lookahead 7322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // check in the BufferedReader class does not take these skipped characters 7422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // into account. 7522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray reader.mark(BUFFER_LENGTH << 1); 76ab49d110ea5f54b41b1a5780ba579c183f0c0a2bNicolas Geoffray // END android-changed. 7722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray int count = 0; 7822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray int textEnd; 7922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 8022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray while (true) { 8122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray int r = reader.read(buffer, count, buffer.length - count); 8222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 8322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray if (r == -1) { 8422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // the input is exhausted; return the remaining characters 8522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray textEnd = count; 8622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray break; 8722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 8822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 8922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray count += r; 9022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray int possibleMarker = findPossibleMarker(buffer, count); 9122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 9222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray if (possibleMarker != 0) { 9322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // return the characters that precede the marker 9422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray textEnd = possibleMarker; 9522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray break; 9622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 9722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 9822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray if (count < marker.length()) { 9922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // the buffer contains only the prefix of a marker so we must read more 10022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray continue; 10122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 10222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 10322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // we've read a marker so return the value that follows 10422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray reader.reset(); 10522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray String json = reader.readLine().substring(marker.length()); 10622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray return jsonParser.parse(json); 10722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 10822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 10922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray if (count == 0) { 11022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray return null; 11122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 11222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 11322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray // return characters 11422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray reader.reset(); 11522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray count = reader.read(buffer, 0, textEnd); 11622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray return new String(buffer, 0, count); 11722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 11822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 11922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray @Override public void close() throws IOException { 12022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray reader.close(); 12122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 12222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray 12322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray /** 12422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * Returns the index of marker in {@code chars}, stopping at {@code limit}. 12522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * Should the chars end with a prefix of marker, the offset of that prefix 12622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray * is returned. 12722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray */ 12822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray int findPossibleMarker(char[] chars, int limit) { 12922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray search: 13022567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray for (int i = 0; true; i++) { 13122567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray for (int m = 0; m < marker.length() && i + m < limit; m++) { 13222567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray if (chars[i + m] != marker.charAt(m)) { 13322567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray continue search; 13422567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 13522567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 13622567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray return i; 13722567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 13822567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray } 13922567545969abcbd17dcf715fe5aa74d4ef253d5Nicolas Geoffray} 140