XmlProductHandler.java

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

  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.net.URI;
  8. import java.net.URL;
  9. import java.util.Base64;

  10. import gov.usgs.util.StreamUtils;
  11. import gov.usgs.util.XmlUtils;
  12. import gov.usgs.util.CryptoUtils.Version;
  13. import gov.usgs.earthquake.product.Content;
  14. import gov.usgs.earthquake.product.URLContent;
  15. import gov.usgs.earthquake.product.ProductId;


  16. /**
  17.  * Store a product to an OutputStream using XML.
  18.  */
  19. public class XmlProductHandler implements ProductHandler {

  20.     /** Declaration for XML and version */
  21.     public static final String XML_DECLARATION = "<?xml version=\"1.0\"?>\n";
  22.     /** Namespace for XML product */
  23.     public static final String PRODUCT_XML_NAMESPACE = "http://earthquake.usgs.gov/distribution/product";

  24.     /** Element for product */
  25.     public static final String PRODUCT_ELEMENT = "product";
  26.     /** Product Attribute for id */
  27.     public static final String PRODUCT_ATTRIBUTE_ID = "id";
  28.     /** Product Attribute for updateTime */
  29.     public static final String PRODUCT_ATTRIBUTE_UPDATED = "updateTime";
  30.     /** Product Attribute for status */
  31.     public static final String PRODUCT_ATTRIBUTE_STATUS = "status";
  32.     /** Product Attribute for trackerURL */
  33.     public static final String PRODUCT_ATTRIBUTE_TRACKER_URL = "trackerURL";

  34.     /** Element for property */
  35.     public static final String PROPERTY_ELEMENT = "property";
  36.     /** Property attribute for name */
  37.     public static final String PROPERTY_ATTRIBUTE_NAME = "name";
  38.     /** Property attribute for value */
  39.     public static final String PROPERTY_ATTRIBUTE_VALUE = "value";

  40.     /** Element for link */
  41.     public static final String LINK_ELEMENT = "link";
  42.     /** Link attribute for relation */
  43.     public static final String LINK_ATTRIBUTE_RELATION = "rel";
  44.     /** Link attribute for href */
  45.     public static final String LINK_ATTRIBUTE_HREF = "href";

  46.     /** Element for content */
  47.     public static final String CONTENT_ELEMENT = "content";
  48.     /** Content attribute for path */
  49.     public static final String CONTENT_ATTRIBUTE_PATH = "path";
  50.     /** Content attribute for type */
  51.     public static final String CONTENT_ATTRIBUTE_TYPE = "type";
  52.     /** Content attribute for length */
  53.     public static final String CONTENT_ATTRIBUTE_LENGTH = "length";
  54.     /** Content attribute for modified */
  55.     public static final String CONTENT_ATTRIBUTE_MODIFIED = "modified";
  56.     /** Used with URLContent. */
  57.     public static final String CONTENT_ATTRIBUTE_HREF = "href";
  58.     /** Content attribute for encoded */
  59.     public static final String CONTENT_ATTRIBUTE_ENCODED = "encoded";

  60.     /** Element for signature */
  61.     public static final String SIGNATURE_ELEMENT = "signature";
  62.     /** Signature attribute for version */
  63.     public static final String SIGNATURE_ATTRIBUTE_VERSION = "version";

  64.     /** The OutputStream where xml is written. */
  65.     private OutputStream out;

  66.     /** Controls whether the XML Declaration is output with the XML. */
  67.     private boolean includeDeclaration = true;

  68.     /** Signature version. */
  69.     private Version signatureVersion = Version.SIGNATURE_V1;

  70.     /**
  71.      * Create a new XmlProductHandler object.
  72.      *
  73.      * @param out
  74.      *            the OutputStream where xml will be written.
  75.      */
  76.     public XmlProductHandler(final OutputStream out) {
  77.         this.out = out;
  78.     }

  79.     /**
  80.      * Create a new XmlProductHandler object.
  81.      *
  82.      * @param out
  83.      *            the OutputStream where xml will be written.
  84.      * @param includeDeclaration
  85.      *            whether to include the XML declaration with output
  86.      */
  87.     public XmlProductHandler(final OutputStream out, boolean includeDeclaration) {
  88.         this.out = out;
  89.         this.includeDeclaration = includeDeclaration;
  90.     }

  91.     /**
  92.      * Output the product root element.
  93.      */
  94.     public void onBeginProduct(ProductId id, String status, URL trackerURL)
  95.             throws Exception {
  96.         StringBuffer buf = new StringBuffer();
  97.         if (includeDeclaration) {
  98.             buf.append(XML_DECLARATION);
  99.         }
  100.         buf.append("<").append(PRODUCT_ELEMENT);
  101.         buf.append(" xmlns=\"").append(PRODUCT_XML_NAMESPACE).append("\"");
  102.         buf.append(" ").append(PRODUCT_ATTRIBUTE_ID).append("=\"")
  103.                 .append(XmlUtils.escape(id.toString())).append("\"");
  104.         buf.append(" ").append(PRODUCT_ATTRIBUTE_UPDATED).append("=\"")
  105.                 .append(XmlUtils.formatDate(id.getUpdateTime())).append("\"");
  106.         buf.append(" ").append(PRODUCT_ATTRIBUTE_STATUS).append("=\"")
  107.                 .append(XmlUtils.escape(status)).append("\"");
  108.         if (trackerURL != null) {
  109.             buf.append(" ").append(PRODUCT_ATTRIBUTE_TRACKER_URL).append("=\"")
  110.                     .append(trackerURL.toExternalForm()).append("\"");
  111.         }
  112.         buf.append(">\n");

  113.         out.write(buf.toString().getBytes());
  114.     }

  115.     /**
  116.      * Output a content object as xml.
  117.      */
  118.     public void onContent(ProductId id, String path, Content content)
  119.             throws Exception {
  120.         // open element
  121.         StringBuffer buf = new StringBuffer();
  122.         buf.append("\t<").append(CONTENT_ELEMENT);
  123.         buf.append(" ").append(CONTENT_ATTRIBUTE_PATH).append("=\"")
  124.                 .append(XmlUtils.escape(path)).append("\"");
  125.         buf.append(" ").append(CONTENT_ATTRIBUTE_TYPE).append("=\"")
  126.                 .append(XmlUtils.escape(content.getContentType())).append("\"");
  127.         buf.append(" ").append(CONTENT_ATTRIBUTE_LENGTH).append("=\"")
  128.                 .append(content.getLength()).append("\"");
  129.         buf.append(" ").append(CONTENT_ATTRIBUTE_MODIFIED).append("=\"")
  130.                 .append(XmlUtils.formatDate(content.getLastModified()))
  131.                 .append("\"");

  132.         if (content instanceof URLContent) {
  133.             // URL CONTENT
  134.             buf.append(" ").append(CONTENT_ATTRIBUTE_HREF).append("=\"")
  135.                     .append(((URLContent) content).getURL().toString())
  136.                     .append("\"");

  137.             // close element early, url is alternative to embedded content
  138.             buf.append("/>");
  139.             out.write(buf.toString().getBytes());
  140.             return;
  141.         }

  142.         else {
  143.             // EMBEDDED CONTENT
  144.             buf.append(" ").append(CONTENT_ATTRIBUTE_ENCODED)
  145.                     .append("=\"true\"");

  146.             buf.append(">");
  147.             out.write(buf.toString().getBytes());

  148.             InputStream in = null;
  149.             OutputStream base64out = null;
  150.             try {
  151.                 in = content.getInputStream();
  152.                 base64out = Base64.getEncoder().wrap(
  153.                         new StreamUtils.UnclosableOutputStream(out));
  154.                 // write element content
  155.                 StreamUtils.transferStream(in, base64out);
  156.             } finally {
  157.                 StreamUtils.closeStream(in);
  158.                 StreamUtils.closeStream(base64out);
  159.             }

  160.             // close element
  161.             buf = new StringBuffer();
  162.             buf.append("</").append(CONTENT_ELEMENT).append(">\n");
  163.             out.write(buf.toString().getBytes());
  164.         }
  165.     }

  166.     /**
  167.      * Output the closing product element.
  168.      */
  169.     public void onEndProduct(ProductId id) throws Exception {
  170.         StringBuffer buf = new StringBuffer();
  171.         buf.append("</").append(PRODUCT_ELEMENT).append(">\n");

  172.         out.write(buf.toString().getBytes());
  173.         out.flush();
  174.         out.close();
  175.     }

  176.     /**
  177.      * Output a link element as xml.
  178.      */
  179.     public void onLink(ProductId id, String relation, URI href)
  180.             throws Exception {
  181.         StringBuffer buf = new StringBuffer();
  182.         buf.append("\t<").append(LINK_ELEMENT);
  183.         buf.append(" ").append(LINK_ATTRIBUTE_RELATION).append("=\"")
  184.                 .append(XmlUtils.escape(relation)).append("\"");
  185.         buf.append(" ").append(LINK_ATTRIBUTE_HREF).append("=\"")
  186.                 .append(XmlUtils.escape(href.toString())).append("\"");
  187.         buf.append("/>\n");

  188.         out.write(buf.toString().getBytes());
  189.     }

  190.     /**
  191.      * Output the property element as xml.
  192.      */
  193.     public void onProperty(ProductId id, String name, String value)
  194.             throws Exception {
  195.         StringBuffer buf = new StringBuffer();
  196.         buf.append("\t<").append(PROPERTY_ELEMENT);
  197.         buf.append(" ").append(PROPERTY_ATTRIBUTE_NAME).append("=\"")
  198.                 .append(XmlUtils.escape(name)).append("\"");
  199.         buf.append(" ").append(PROPERTY_ATTRIBUTE_VALUE).append("=\"")
  200.                 .append(XmlUtils.escape(value)).append("\"");
  201.         buf.append("/>\n");

  202.         out.write(buf.toString().getBytes());
  203.     }

  204.     public void onSignatureVersion(ProductId id, Version version) throws Exception {
  205.         // save for output during onSignature
  206.         this.signatureVersion = version;
  207.     }

  208.     /**
  209.      * Output the signature element as xml.
  210.      */
  211.     public void onSignature(ProductId id, String signature) throws Exception {
  212.         if (signature == null) {
  213.             return;
  214.         }

  215.         StringBuffer buf = new StringBuffer();
  216.         buf.append("\t<").append(SIGNATURE_ELEMENT);
  217.         buf.append(" ").append(SIGNATURE_ATTRIBUTE_VERSION).append("=\"")
  218.                 .append(signatureVersion.toString()).append("\"");
  219.         buf.append(">");
  220.         buf.append(signature);
  221.         buf.append("</").append(SIGNATURE_ELEMENT).append(">\n");

  222.         out.write(buf.toString().getBytes());
  223.     }

  224.     /**
  225.      * Free any resources associated with this handler.
  226.      */
  227.     @Override
  228.     public void close() {
  229.         StreamUtils.closeStream(out);
  230.     }


  231. }