JsonProductSource.java
/*
* JsonProductSource
*/
package gov.usgs.earthquake.product.io;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonReader;
import javax.json.JsonValue;
import gov.usgs.util.StreamUtils;
import gov.usgs.earthquake.product.ByteContent;
import gov.usgs.earthquake.product.Content;
import gov.usgs.earthquake.product.FileContent;
import gov.usgs.earthquake.product.Product;
import gov.usgs.earthquake.product.URLContent;
/**
* Load a product from an InputStream containing Json.
*/
public class JsonProductSource implements ProductSource {
/** The input stream where Json is read. */
private InputStream in;
/** The directory where a product exists. */
private Path directory;
/**
* Create a new JsonProductSource.
*
* @param in the input stream where Json is read.
*/
public JsonProductSource(final InputStream in) {
this.in = in;
this.directory = null;
}
/**
* Create a new JsonProductSource.
*
* @param in the input stream where Json is read.
* @param directory the directory where a product exists.
*/
public JsonProductSource(final InputStream in, final Path directory) {
this.in = in;
this.directory = directory;
}
public JsonObject parseContents(JsonObject contentsObject) throws Exception {
JsonObjectBuilder contentsCopy = Json.createObjectBuilder();
for (String key : contentsObject.keySet()) {
JsonObject content = contentsObject.get(key).asJsonObject();
JsonObjectBuilder contentCopy = Json.createObjectBuilder();
Content inputContent;
if (content.containsKey("bytes") && content.containsKey("url")) {
throw new Error("Keys 'bytes' and 'url' cannot be in the same content json.");
} else if (content.containsKey("bytes")) {
byte[] bytes = content.getString("bytes").getBytes();
ByteContent bytesContent = new ByteContent(bytes);
if ("".equals(key)) {
inputContent = bytesContent;
contentCopy.add("url", "data:" + bytesContent.getContentType() + ";base64,"
+ Base64.getEncoder().encodeToString(StreamUtils.readStream(inputContent.getInputStream())));
} else {
// write bytes that have a path to a file
URLContent urlContent = new URLContent(
new FileContent(bytesContent, directory.resolve(key).toAbsolutePath().toFile()));
inputContent = urlContent;
contentCopy.add("url", urlContent.getURL().toString());
}
} else if (content.containsKey("url") && content.getString("url").startsWith("file:")) {
URI uri = new URI(content.getString("url"));
Path filePath = Paths.get(uri);
File file = filePath.toAbsolutePath().toFile();
FileContent fileContent = new FileContent(file);
inputContent = fileContent;
URLContent urlContent = new URLContent(fileContent);
contentCopy.add("url", urlContent.getURL().toString());
} else if (content.containsKey("url")) {
URLContent urlContent = new URLContent(new URL(content.getString("url")));
inputContent = urlContent;
contentCopy.add("url", urlContent.getURL().toString());
} else {
URLContent urlContent = new URLContent(
new FileContent(directory.resolve(key).toAbsolutePath().toFile()));
inputContent = urlContent;
contentCopy.add("url", urlContent.getURL().toString());
}
contentCopy.add("length", inputContent.getLength());
contentCopy.add("modified", inputContent.getLastModified().toString());
contentCopy.add("sha256", inputContent.getSha256());
contentCopy.add("type", inputContent.getContentType());
contentsCopy.add(key, contentCopy.build());
}
return contentsCopy.build();
}
public Product parseDirectoryJson(JsonObject json) throws Exception {
// if we are reading a json product from a directory
// Example: directory poller / input wedge)
// then we need to prepare the contents that may have simple user input
JsonObjectBuilder jsonCopy = Json.createObjectBuilder();
for (final String key : json.keySet()) {
if (key != "contents") {
jsonCopy.add(key, json.get(key));
}
}
if (json.containsKey("contents")) {
JsonValue contents = json.get("contents");
JsonObject contentsCopy;
// loop through keys and handle files and bytes
if (contents instanceof JsonArray) {
JsonObjectBuilder contentsMap = Json.createObjectBuilder();
for (JsonValue value : contents.asJsonArray()) {
JsonObject content = value.asJsonObject();
contentsMap.add(content.getString("path"), content);
}
contentsCopy = parseContents(contentsMap.build());
} else {
JsonObject contentsObject = contents.asJsonObject();
contentsCopy = parseContents(contentsObject);
}
jsonCopy.add("contents", contentsCopy);
}
if (!json.containsKey("links")) {
JsonArrayBuilder linksArrayBuilder = Json.createArrayBuilder();
jsonCopy.add("links", linksArrayBuilder
.build());
}
Product product = new JsonProduct().getProduct(jsonCopy.build());
return product;
}
/**
* Begin reading the input stream, sending events to out.
*
* @param out the receiving ProductOutput.
*/
public synchronized void streamTo(ProductHandler out) throws Exception {
final Product product;
try (final JsonReader reader = Json.createReader(new InputStreamReader(in))) {
JsonObject json = reader.readObject();
if (directory != null) {
product = parseDirectoryJson(json);
} else {
product = new JsonProduct().getProduct(json);
}
}
final ObjectProductSource source = new ObjectProductSource(product);
source.streamTo(out);
}
/**
* Free any resources associated with this handler.
*/
@Override
public void close() {
StreamUtils.closeStream(in);
}
}