BinaryProductHandler.java
package gov.usgs.earthquake.product.io;
import gov.usgs.earthquake.product.ByteContent;
import gov.usgs.earthquake.product.Content;
import gov.usgs.earthquake.product.ProductId;
import gov.usgs.util.StreamUtils;
import gov.usgs.util.CryptoUtils.Version;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
/**
* Generator of binary format for product data.
*
* Binary representation of data types:
* <dl>
* <dt>Integer</dt>
* <dd>4-bytes</dd>
* <dt>Long</dt>
* <dd>8-bytes</dd>
* <dt>Date</dt>
* <dd>Long (Date.getTime())</dd>
* <dt>byte[]</dt>
* <dd>Integer length, raw bytes</dd>
* <dt>String</dt>
* <dd>byte[] (String.getBytes(StandardCharsets.UTF_8))</dd>
* <dt>URL/URI</dt>
* <dd>String (URL.toString())</dd>
* </dl>
*
*
* Product is stored in this order:
*
* <ol>
*
* <li>Header, exactly 1
* <ol>
* <li>"BEGINPRODUCT" (string)</li>
* <li>ProductId (String)</li>
* <li>Status (String)</li>
* <li>TrackerURL (URL)</li>
* </ol>
* </li>
*
* <li>Properties, 0 to many:
* <ol>
* <li>"PROPERTY" (String)</li>
* <li>name (String)</li>
* <li>value (String)</li>
* </ol>
* </li>
*
* <li>Links, 0 to many:
* <ol>
* <li>"LINK" (String)</li>
* <li>relation (String)</li>
* <li>href (URI)</li>
* </ol>
* </li>
*
* <li>Contents, 0 to many:
* <ol>
* <li>"CONTENT" (String)</li>
* <li>path (String)</li>
* <li>contentType (String)</li>
* <li>lastModified (Date)</li>
* <li>length (Long)</li>
* <li>raw bytes</li>
* </ol>
* </li>
*
* <li>Signature Version, 0 or 1.
* <em>Note, only sent when version != SIGNATURE_V1 for backward compatibility</em>
* <ol>
* <li>"SIGNATUREVERSION" (String)</li>
* <li>version (String)</li>
* </ol>
* </li>
*
* <li>Signature, 0 or 1:
* <ol>
* <li>"SIGNATURE" (String)</li>
* <li>signature (String)</li>
* </ol>
* </li>
*
* <li>Footer, exactly 1:
* <ol>
* <li>"ENDPRODUCT" (String)</li>
* </ol>
* </li>
*
* </ol>
*/
public class BinaryProductHandler implements ProductHandler {
/** HEADER - BEGINPRODUCT */
public static final String HEADER = "BEGINPRODUCT";
/** PROPERTY */
public static final String PROPERTY = "PROPERTY";
/** LINK */
public static final String LINK = "LINK";
/** CONTENT */
public static final String CONTENT = "CONTENT";
/** SIGNATURE VERSION */
public static final String SIGNATUREVERSION = "SIGNATUREVERSION";
/** SIGNATURE */
public static final String SIGNATURE = "SIGNATURE";
/** ENDPRODUCT */
public static final String FOOTER = "ENDPRODUCT";
private OutputStream out;
private BinaryIO io;
/**
* Constructor. Sets up a new BinaryIO
* @param out an OutputStream
*/
public BinaryProductHandler(final OutputStream out) {
this.out = out;
this.io = new BinaryIO();
}
@Override
public void onBeginProduct(ProductId id, String status, URL trackerURL)
throws Exception {
io.writeString(HEADER, out);
io.writeString(id.toString(), out);
io.writeString(status, out);
// allow trackerURL to be null
if (trackerURL == null) {
io.writeString("null", out);
} else {
io.writeString(trackerURL.toString(), out);
}
}
@Override
public void onProperty(ProductId id, String name, String value)
throws Exception {
io.writeString(PROPERTY, out);
io.writeString(name, out);
io.writeString(value, out);
}
@Override
public void onLink(ProductId id, String relation, URI href)
throws Exception {
io.writeString(LINK, out);
io.writeString(relation, out);
io.writeString(href.toString(), out);
}
@Override
public void onContent(ProductId id, String path, Content content)
throws Exception {
if (content.getLength() == null || content.getLength() < 0) {
// binary io only handles streams with length, convert to content
// with length
content = new ByteContent(content);
}
io.writeString(CONTENT, out);
io.writeString(path, out);
io.writeString(content.getContentType(), out);
io.writeDate(content.getLastModified(), out);
InputStream contentInputStream = content.getInputStream();
try {
io.writeStream(content.getLength().longValue(), contentInputStream, out);
} finally {
StreamUtils.closeStream(contentInputStream);
}
}
@Override
public void onSignatureVersion(ProductId id, Version version) throws Exception {
if (version != Version.SIGNATURE_V1) {
io.writeString(SIGNATUREVERSION, out);
io.writeString(version.toString(), out);
}
}
@Override
public void onSignature(ProductId id, String signature) throws Exception {
// allow signature to be null
if (signature == null) {
return;
}
io.writeString(SIGNATURE, out);
io.writeString(signature, out);
}
@Override
public void onEndProduct(ProductId id) throws Exception {
io.writeString(FOOTER, out);
out.flush();
out.close();
}
/**
* Free any resources associated with this source.
*/
@Override
public void close() {
StreamUtils.closeStream(out);
out = null;
}
}