ZipProductHandler.java

  1. /*
  2.  * ZipProductHandler
  3.  */
  4. package gov.usgs.earthquake.product.io;

  5. import gov.usgs.earthquake.product.Content;
  6. import gov.usgs.earthquake.product.Product;
  7. import gov.usgs.earthquake.product.ProductId;

  8. import gov.usgs.util.StreamUtils;

  9. import java.io.OutputStream;

  10. import java.util.Map;
  11. import java.util.HashMap;
  12. import java.util.Iterator;

  13. import java.util.zip.ZipOutputStream;
  14. import java.util.zip.ZipEntry;

  15. /**
  16.  * Store a product to an OutputStream using ZIP.
  17.  *
  18.  * Accumulates entire product the same as ObjectProductOutput, then onEndProduct
  19.  * outputs a zip file containing "product.xml" as the first entry and all
  20.  * product content as other entries.
  21.  *
  22.  * Because the zip file is not written until after all content has been
  23.  * "received", all product content may result in in-memory buffering. This is
  24.  * not the case when dealing with File-backed products. If this is a concern,
  25.  * users are encouraged to use the Xml Input and Output classes, which always
  26.  * use streams and never buffer content.
  27.  */
  28. public class ZipProductHandler extends ObjectProductHandler {

  29.     /** The entry filename used for product metadata. */
  30.     public static final String PRODUCT_XML_ZIP_ENTRYNAME = "product.xml";

  31.     /** The output stream where zip content is written. */
  32.     private OutputStream out;

  33.     /**
  34.      * Construct a new ZipProductHandler object.
  35.      *
  36.      * @param out
  37.      *            the output stream where zip content is written.
  38.      */
  39.     public ZipProductHandler(final OutputStream out) {
  40.         this.out = out;
  41.     }

  42.     /**
  43.      * Creates and outputs the zip stream.
  44.      */
  45.     public void onEndProduct(ProductId id) throws Exception {
  46.         super.onEndProduct(id);
  47.         Product product = getProduct();

  48.         // separate all contents that will be zip entries from product
  49.         Map<String, Content> contents = new HashMap<String, Content>(
  50.                 product.getContents());
  51.         product.getContents().clear();

  52.         // check for inline content that won't have a zip entry
  53.         Content inlineContent = contents.get("");
  54.         if (inlineContent != null) {
  55.             product.getContents().put("", inlineContent);
  56.         }

  57.         // write zip stream
  58.         ZipOutputStream zos = null;
  59.         try {
  60.             zos = new ZipOutputStream(out);

  61.             // product xml entry
  62.             ZipEntry entry = new ZipEntry(PRODUCT_XML_ZIP_ENTRYNAME);
  63.             entry.setTime(product.getId().getUpdateTime().getTime());
  64.             zos.putNextEntry(entry);
  65.             new ObjectProductSource(product).streamTo(new XmlProductHandler(
  66.                     new StreamUtils.UnclosableOutputStream(zos)));
  67.             // zos.closeEntry();

  68.             // all other content entries
  69.             Iterator<String> paths = contents.keySet().iterator();
  70.             while (paths.hasNext()) {
  71.                 String path = paths.next();
  72.                 if ("".equals(path)) {
  73.                     // inline content doesn't get separate entry
  74.                     continue;
  75.                 }
  76.                 Content content = contents.get(path);
  77.                 entry = new ZipEntry(path);
  78.                 entry.setTime(content.getLastModified().getTime());
  79.                 entry.setComment(content.getContentType());
  80.                 Long length = content.getLength();
  81.                 if (length != null && length > 0) {
  82.                     entry.setSize(content.getLength());
  83.                 }
  84.                 zos.putNextEntry(entry);
  85.                 StreamUtils.transferStream(content.getInputStream(),
  86.                         new StreamUtils.UnclosableOutputStream(zos));
  87.                 // zos.closeEntry();
  88.             }
  89.         } finally {
  90.             // done
  91.             zos.finish();
  92.             zos.flush();
  93.             StreamUtils.closeStream(zos);
  94.         }
  95.     }


  96.     /**
  97.      * Free any resources associated with this handler.
  98.      */
  99.     @Override
  100.     public void close() {
  101.         StreamUtils.closeStream(out);
  102.     }

  103. }