BinaryProductHandler.java

  1. package gov.usgs.earthquake.product.io;

  2. import gov.usgs.earthquake.product.ByteContent;
  3. import gov.usgs.earthquake.product.Content;
  4. import gov.usgs.earthquake.product.ProductId;
  5. import gov.usgs.earthquake.product.ProductSignature;
  6. import gov.usgs.util.StreamUtils;
  7. import gov.usgs.util.CryptoUtils.Version;

  8. import java.io.InputStream;
  9. import java.io.OutputStream;
  10. import java.net.URI;
  11. import java.util.List;
  12. import java.util.Map;

  13. /**
  14.  * Generator of binary format for product data.
  15.  *
  16.  * Binary representation of data types:
  17.  * <dl>
  18.  * <dt>Integer</dt>
  19.  * <dd>4-bytes</dd>
  20.  * <dt>Long</dt>
  21.  * <dd>8-bytes</dd>
  22.  * <dt>Date</dt>
  23.  * <dd>Long (Date.getTime())</dd>
  24.  * <dt>byte[]</dt>
  25.  * <dd>Integer length, raw bytes</dd>
  26.  * <dt>String</dt>
  27.  * <dd>byte[] (String.getBytes(StandardCharsets.UTF_8))</dd>
  28.  * <dt>URL/URI</dt>
  29.  * <dd>String (URL.toString())</dd>
  30.  * </dl>
  31.  *
  32.  *
  33.  * Product is stored in this order:
  34.  *
  35.  * <ol>
  36.  *
  37.  * <li>Header, exactly 1
  38.  * <ol>
  39.  * <li>"BEGINPRODUCT" (string)</li>
  40.  * <li>ProductId (String)</li>
  41.  * <li>Status (String)</li>
  42.  * </ol>
  43.  * </li>
  44.  *
  45.  * <li>Properties, 0 to many:
  46.  * <ol>
  47.  * <li>"PROPERTY" (String)</li>
  48.  * <li>name (String)</li>
  49.  * <li>value (String)</li>
  50.  * </ol>
  51.  * </li>
  52.  *
  53.  * <li>Links, 0 to many:
  54.  * <ol>
  55.  * <li>"LINK" (String)</li>
  56.  * <li>relation (String)</li>
  57.  * <li>href (URI)</li>
  58.  * </ol>
  59.  * </li>
  60.  *
  61.  * <li>Contents, 0 to many:
  62.  * <ol>
  63.  * <li>"CONTENT" (String)</li>
  64.  * <li>path (String)</li>
  65.  * <li>contentType (String)</li>
  66.  * <li>lastModified (Date)</li>
  67.  * <li>length (Long)</li>
  68.  * <li>raw bytes</li>
  69.  * </ol>
  70.  * </li>
  71.  *
  72.  * <li>Signature Version, 0 or 1. <em>Note, only sent when version !=
  73.  * SIGNATURE_V1 for backward compatibility</em>
  74.  * <ol>
  75.  * <li>"SIGNATUREVERSION" (String)</li>
  76.  * <li>version (String)</li>
  77.  * </ol>
  78.  * </li>
  79.  *
  80.  * <li>Signature, 0 or 1:
  81.  * <ol>
  82.  * <li>"SIGNATURE" (String)</li>
  83.  * <li>signature (String)</li>
  84.  * </ol>
  85.  * </li>
  86.  *
  87.  * <li>Footer, exactly 1:
  88.  * <ol>
  89.  * <li>"ENDPRODUCT" (String)</li>
  90.  * </ol>
  91.  * </li>
  92.  *
  93.  * </ol>
  94.  */
  95. public class BinaryProductHandler implements ProductHandler {

  96.   /** HEADER - BEGINPRODUCT */
  97.   public static final String HEADER = "BEGINPRODUCT";
  98.   /** PROPERTY */
  99.   public static final String PROPERTY = "PROPERTY";
  100.   /** LINK */
  101.   public static final String LINK = "LINK";
  102.   /** CONTENT */
  103.   public static final String CONTENT = "CONTENT";
  104.   /** SIGNATURE VERSION */
  105.   public static final String SIGNATUREVERSION = "SIGNATUREVERSION";
  106.   /** SIGNATURE */
  107.   public static final String SIGNATURE = "SIGNATURE";
  108.   /** SIGNATURE HISTORY */
  109.   public static final String SIGNATUREHISTORY = "SIGNATUREHISTORY";
  110.   /** map entry for SIGNATURE HISTORY list */
  111.   public static final String SIGNATUREHISTORYENTRY = "SIGNATUREHISTORYENTRY";
  112.   /** End of SIGNATURE HISTORY list */
  113.   public static final String ENDSIGNATUREHISTORY = "ENDSIGNATUREHISTORY";
  114.   /** ENDPRODUCT */
  115.   public static final String FOOTER = "ENDPRODUCT";

  116.   private OutputStream out;
  117.   private BinaryIO io;

  118.   /**
  119.    * Constructor. Sets up a new BinaryIO
  120.    *
  121.    * @param out an OutputStream
  122.    */
  123.   public BinaryProductHandler(final OutputStream out) {
  124.     this.out = out;
  125.     this.io = new BinaryIO();
  126.   }

  127.   @Override
  128.   public void onBeginProduct(ProductId id, String status) throws Exception {
  129.     io.writeString(HEADER, out);
  130.     io.writeString(id.toString(), out);
  131.     io.writeString(status, out);
  132.   }

  133.   @Override
  134.   public void onProperty(ProductId id, String name, String value) throws Exception {
  135.     io.writeString(PROPERTY, out);
  136.     io.writeString(name, out);
  137.     io.writeString(value, out);
  138.   }

  139.   @Override
  140.   public void onLink(ProductId id, String relation, URI href) throws Exception {
  141.     io.writeString(LINK, out);
  142.     io.writeString(relation, out);
  143.     io.writeString(href.toString(), out);
  144.   }

  145.   @Override
  146.   public void onContent(ProductId id, String path, Content content) throws Exception {
  147.     if (content.getLength() == null || content.getLength() < 0) {
  148.       // binary io only handles streams with length, convert to content
  149.       // with length
  150.       content = new ByteContent(content);
  151.     }

  152.     io.writeString(CONTENT, out);
  153.     io.writeString(path, out);

  154.     io.writeString(content.getContentType(), out);
  155.     io.writeDate(content.getLastModified(), out);
  156.     InputStream contentInputStream = content.getInputStream();
  157.     try {
  158.       io.writeStream(content.getLength().longValue(), contentInputStream, out);
  159.     } finally {
  160.       StreamUtils.closeStream(contentInputStream);
  161.     }
  162.   }

  163.   @Override
  164.   public void onSignatureVersion(ProductId id, Version version) throws Exception {
  165.     if (version != Version.SIGNATURE_V1) {
  166.       io.writeString(SIGNATUREVERSION, out);
  167.       io.writeString(version.toString(), out);
  168.     }
  169.   }

  170.   @Override
  171.   public void onSignature(ProductId id, String signature) throws Exception {
  172.     // allow signature to be null
  173.     if (signature == null) {
  174.       return;
  175.     }

  176.     io.writeString(SIGNATURE, out);
  177.     io.writeString(signature, out);
  178.   }

  179.   public void onSignatureHistory(final ProductId id, final List<ProductSignature> signatureHistory)
  180.       throws Exception {
  181.     if (signatureHistory.isEmpty()) {
  182.       return;
  183.     }
  184.     io.writeString(SIGNATUREHISTORY, out);
  185.     for (ProductSignature entry : signatureHistory) {
  186.       io.writeString(SIGNATUREHISTORYENTRY, out);
  187.       io.writeString(entry.getSignature(), out);
  188.       io.writeString(entry.getSignatureVersion().toString(), out);
  189.     }
  190.     io.writeString(ENDSIGNATUREHISTORY, out);
  191.   }

  192.   @Override
  193.   public void onEndProduct(ProductId id) throws Exception {
  194.     io.writeString(FOOTER, out);

  195.     out.flush();
  196.     out.close();
  197.   }

  198.   /**
  199.    * Free any resources associated with this source.
  200.    */
  201.   @Override
  202.   public void close() {
  203.     StreamUtils.closeStream(out);
  204.     out = null;
  205.   }

  206. }