/*
* Copyright (c) 2014, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (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.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.server.internal.remote;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* An {@link InputStream} based implementation of {@link ResponseStream}. Each line must contain
* exactly one complete JSON object.
*
* @coverage dart.server.remote
*/
public class ByteResponseStream implements ResponseStream {
private class LinesReaderThread extends Thread {
public LinesReaderThread() {
setName("ByteResponseStream.LinesReaderThread");
setDaemon(true);
}
@Override
public void run() {
while (true) {
String line;
try {
line = reader.readLine();
} catch (IOException e) {
line = null;
}
// check for EOF
if (line == null) {
lineQueue.add(EOF_LINE);
if (onStreamEndRunnable != null) {
onStreamEndRunnable.run();
}
return;
}
// debug output
if (debugStream != null) {
debugStream.println(System.currentTimeMillis() + " <= " + line);
}
// ignore non-JSON (debug) lines
if (!line.startsWith("{")) {
continue;
}
// add a JSON line
lineQueue.add(line);
}
}
}
public static final String EOF_LINE = "EOF line";
/**
* The {@link BufferedReader} to read JSON strings from.
*/
private final BufferedReader reader;
/**
* The {@link DebugPrintStream} to print all lines to.
*/
private final DebugPrintStream debugStream;
private final Runnable onStreamEndRunnable;
/**
* The queue of lines.
*/
private final BlockingQueue<String> lineQueue = new LinkedBlockingQueue<String>();
/**
* Initializes a newly created response stream.
*
* @param stream the byte stream to read JSON strings from
* @param debugStream the {@link PrintStream} to print all lines to, may be {@code null}
*/
public ByteResponseStream(InputStream stream, DebugPrintStream debugStream, Runnable onStreamEndRunnable) {
reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
this.debugStream = debugStream;
this.onStreamEndRunnable = onStreamEndRunnable;
new LinesReaderThread().start();
}
@Override
public void lastRequestProcessed() {
}
@Override
public JsonObject take() throws Exception {
String line = lineQueue.take();
if (line == EOF_LINE) {
lineQueue.add(line);
return null;
}
try {
return (JsonObject) new JsonParser().parse(line);
} catch (JsonSyntaxException e) {
// Include the line in the message so that we can better diagnose the problem
throw new JsonSyntaxException("Parse server message failed: " + line, e);
}
}
}