IOUtil.java

package gov.usgs.earthquake.product.io;

import gov.usgs.util.StreamUtils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipException;

/**
 * Class with main method for converting from one product format to another.
 */
public class IOUtil {

  /** Argument for input file */
  public static final String INFILE_ARGUMENT = "--infile=";
  /** Argument for input format */
  public static final String INFORMAT_ARGUMENT = "--informat=";

  /** Argument for output file */
  public static final String OUTFILE_ARGUMENT = "--outfile=";
  /** Argument for output format */
  public static final String OUTFORMAT_ARGUMENT = "--outformat=";

  /** Zip format */
  public static final String ZIP_FORMAT = "zip";
  /** XML format */
  public static final String XML_FORMAT = "xml";
  /** Directory format */
  public static final String DIRECTORY_FORMAT = "directory";
  /** Binary format */
  public static final String BINARY_FORMAT = "binary";

  /**
   * Returns a ProductHandler based on the output format
   *
   * @param outformat Output format
   * @param outfile   Output file
   * @return a Product Handler
   * @throws IOException if IO error occurs
   */
  public static ProductHandler getProductHandler(final String outformat, final File outfile) throws IOException {
    ProductHandler out = null;
    if (outformat.equals(XML_FORMAT)) {
      out = new XmlProductHandler(StreamUtils.getOutputStream(outfile));
    } else if (outformat.equals(ZIP_FORMAT)) {
      out = new ZipProductHandler(StreamUtils.getOutputStream(outfile));
    } else if (outformat.equals(DIRECTORY_FORMAT)) {
      out = new DirectoryProductHandler(outfile);
    } else if (outformat.equals(BINARY_FORMAT)) {
      out = new BinaryProductHandler(StreamUtils.getOutputStream(outfile));
    } else {
      throw new IllegalArgumentException("unknown product format '" + outformat + "'");
    }
    return out;
  }

  /**
   * Returns a product source based on input format
   *
   * @param informat input file format
   * @param infile   input file
   * @return a Productsource
   * @throws IllegalArgumentException if informat argument error
   * @throws IOException              if error occurs
   */
  public static ProductSource getProductSource(final String informat, final File infile)
      throws IllegalArgumentException, IOException {
    ProductSource in = null;
    if (informat.equals(XML_FORMAT)) {
      in = new XmlProductSource(StreamUtils.getInputStream(infile));
    } else if (informat.equals(ZIP_FORMAT)) {
      in = new ZipProductSource(infile);
    } else if (informat.equals(DIRECTORY_FORMAT)) {
      in = new DirectoryProductSource(infile);
    } else if (informat.equals(BINARY_FORMAT)) {
      in = new BinaryProductSource(StreamUtils.getInputStream(infile));
    } else {
      throw new IllegalArgumentException("unknown product format '" + informat + "'");
    }
    return in;
  }

  /**
   * Auto detect an Xml or Binary product source, that is optionally deflated.
   *
   * @param in input stream containing optionally deflated xml or binary product
   *           stream.
   * @return ProductSource object.
   * @throws IOException if neither binary or xml product source is in stream.
   */
  public static ProductSource autoDetectProductSource(final InputStream in) throws IOException {
    BufferedInputStream bufferedIn = autoDetectDeflate(in);
    int ch = -1;

    bufferedIn.mark(1024);
    // peek at first character in stream
    ch = bufferedIn.read();
    bufferedIn.reset();

    ProductSource productSource = null;
    // determine product format based on first character in stream
    if (((char) ch) == '<') {
      // xml format
      productSource = new XmlProductSource(bufferedIn);
    } else {
      // binary format
      productSource = new BinaryProductSource(bufferedIn);
    }

    return productSource;
  }

  /**
   * Auto detect an optionally deflated stream.
   *
   * @param in input stream containing optionally deflated xml or binary product
   *           stream.
   * @return ProductSource object.
   * @throws IOException if neither binary or xml product source is in stream.
   */
  public static BufferedInputStream autoDetectDeflate(final InputStream in) throws IOException {
    // stream used to read product
    BufferedInputStream bufferedIn = new BufferedInputStream(in);

    // detect whether incoming stream is compressed
    bufferedIn.mark(1024);
    try {
      InflaterInputStream iis = new InflaterInputStream(bufferedIn);
      iis.read();
      // must be a deflated stream, reset for reading
      bufferedIn.reset();
      bufferedIn = new BufferedInputStream(new InflaterInputStream(bufferedIn));
    } catch (ZipException ze) {
      // not a deflated stream
      bufferedIn.reset();
    }

    return bufferedIn;
  }

  /**
   * Access into IOUtil Takes arguments, gets product source and handler Streams
   * source to handler
   *
   * @param args CLI args for infile, informat, outfile, outformat
   * @throws Exception if error occurs
   */
  public static void main(final String[] args) throws Exception {
    File infile = null;
    File outfile = null;
    String informat = null;
    String outformat = null;

    // parse arguments
    for (String arg : args) {
      if (arg.startsWith(INFILE_ARGUMENT)) {
        infile = new File(arg.replace(INFILE_ARGUMENT, ""));
      } else if (arg.startsWith(OUTFILE_ARGUMENT)) {
        outfile = new File(arg.replace(OUTFILE_ARGUMENT, ""));
      } else if (arg.startsWith(INFORMAT_ARGUMENT)) {
        informat = arg.replace(INFORMAT_ARGUMENT, "");
      } else if (arg.startsWith(OUTFORMAT_ARGUMENT)) {
        outformat = arg.replace(OUTFORMAT_ARGUMENT, "");
      }
    }

    if (infile == null || informat == null) {
      printUsage();
      System.exit(1);
    }

    if (outfile == null || outformat == null) {
      printUsage();
      System.exit(1);
    }

    ProductSource in = getProductSource(informat, infile);
    ProductHandler out = getProductHandler(outformat, outfile);
    in.streamTo(out);
  }

  /** CLI usage */
  public static void printUsage() {
    System.err.println(
        "IOUtil --infile=FILE --informat=(xml|directory|zip|binary) --outfile=FILE --outformat=(xml|directory|zip|binary)");
  }

}