org.eclipse.che.infrastructure.docker.client.JsonMessageReader Maven / Gradle / Ivy
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.infrastructure.docker.client;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonParseException;
import com.google.gson.JsonStreamParser;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackReader;
/**
* Docker daemon sends chunked data in response. One chunk isn't always one JSON object so need to
* read full chunk at once to be able restore JSON object. This reader merges (if needs) few chunks
* until get full JSON object that we can parse. Parameter of this class is class where JSON message
* should be parsed.
*
* @author Alexander Garagatyi
*/
public class JsonMessageReader {
private static final Gson GSON = new Gson();
private final JsonStreamParser streamParser;
private final Class messageClass;
private final PushbackReader reader;
private boolean firstRead = true;
/**
* @param source source of messages in JSON format
* @param messageClass class of the message object where JSON messages should be parsed. Because
* of erasure of generic information in runtime in some cases we can't get parameter class of
* current class.
*/
public JsonMessageReader(InputStream source, Class messageClass) {
// we need to push back only 1 char, read more further
this.reader = new PushbackReader(new InputStreamReader(source), 1);
this.streamParser = new JsonStreamParser(reader);
this.messageClass = messageClass;
}
/**
* Returns message parsed from JSON stream.
*
* @return object of class passed as parameter of constructor or null if stream is empty
* @throws IOException if error occurs on reading stream
*/
public T next() throws IOException {
// on first read we check if this stream is empty with reading of the first byte of stream
// if so we do not call JsonStreamParser.hasNext() because it will throw exception
// if not we return read byte to stream using PushbackInputStream
if (firstRead) {
int firstChar = reader.read();
if (firstChar == -1) {
return null;
} else {
reader.unread(firstChar);
firstRead = false;
}
}
try {
if (streamParser.hasNext()) {
return GSON.fromJson(streamParser.next(), messageClass);
}
} catch (JsonIOException e) {
throw new IOException(e);
} catch (JsonParseException ignore) {
}
return null;
}
}