ZipProductSource.java

package gov.usgs.earthquake.product.io;

import gov.usgs.earthquake.product.InputStreamContent;
import gov.usgs.earthquake.product.Product;
import gov.usgs.earthquake.product.ProductId;

import java.io.File;
import java.util.Date;
import java.util.Enumeration;

import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;

/**
 * Load a product from an InputStream containing ZIP.
 *
 * ZipProductSource reads an input stream containing a product zip file.
 *
 * This zip file's first entry must be a product xml file containing all product
 * metadata and inline content.
 */
public class ZipProductSource implements ProductSource {

  /** The input stream where zip content is read. */
  private File zip;

  /**
   * Construct a new ZipProductSource.
   *
   * @param zip the input stream where zip content is read.
   */
  public ZipProductSource(final File zip) {
    this.zip = zip;
  }

  /**
   * Parse the zip stream and send product to product output.
   *
   * @param out ProductOutput that will receive the product.
   */
  public void streamTo(ProductHandler out) throws Exception {
    ZipFile zis = null;

    try {
      zis = new ZipFile(this.zip);

      Enumeration<? extends ZipEntry> entries = zis.entries();
      ZipEntry entry = entries.nextElement();

      if (!entry.getName().equals(ZipProductHandler.PRODUCT_XML_ZIP_ENTRYNAME)) {
        throw new Exception(
            "Unexpected first entry " + entry.getName() + ", expected " + ZipProductHandler.PRODUCT_XML_ZIP_ENTRYNAME);
      }

      Product product = ObjectProductHandler.getProduct(new XmlProductSource(zis.getInputStream(entry)));
      ProductId id = product.getId();

      // send all except signature and end product, until after all
      // contents
      new ObjectProductSource(product) {
        public void sendSignature(final ProductHandler out) throws Exception {
          // do nothing
        }

        public void sendEndProduct(final ProductHandler out) throws Exception {
          // do nothing
        }
      }.streamTo(out);

      // send other contents
      while (entries.hasMoreElements()) {
        entry = entries.nextElement();
        InputStreamContent content = new InputStreamContent(zis.getInputStream(entry));
        content.setLength(entry.getSize());
        content.setLastModified(new Date(entry.getTime()));
        content.setContentType(entry.getComment());
        out.onContent(id, entry.getName(), content);
      }

      // finish sending product
      out.onSignature(id, product.getSignature());
      out.onEndProduct(id);
    } finally {
      try {
        zis.close();
      } catch (Exception ignore) {
      }
    }
  }

  /**
   * Free any resources associated with this handler.
   */
  @Override
  public void close() {
    this.zip = null;
  }

}