ProductArchivePolicy.java

package gov.usgs.earthquake.indexer;

import java.util.Date;
import java.util.logging.Logger;

import gov.usgs.earthquake.distribution.ConfigurationException;
import gov.usgs.util.Config;

/**
 * An archive policy for products, instead of events.
 *
 * Allows removal of superseded products, preserving latest versions. Also
 * allows targeting unassociated products.
 */
public class ProductArchivePolicy extends ArchivePolicy {

  private static final Logger LOGGER = Logger.getLogger(ProductArchivePolicy.class.getName());

  // --------------------------------------------------------------------
  // Names of configurable parameters
  // --------------------------------------------------------------------

  /** Property for archive min product age */
  public static final String ARCHIVE_MIN_PRODUCT_AGE_PROPERTY = "minProductAge";
  /** Property for archive max product age */
  public static final String ARCHIVE_MAX_PRODUCT_AGE_PROPERTY = "maxProductAge";

  /** Property for archive min product time */
  public static final String ARCHIVE_MIN_PRODUCT_TIME_PROPERTY = "minProductTime";
  /** Property for archive max product time */
  public static final String ARCHIVE_MAX_PRODUCT_TIME_PROPERTY = "maxProductTime";

  /** Property for archive product type */
  public static final String ARCHIVE_TYPE_PROPERTY = "productType";
  /** Property for archive product source */
  public static final String ARCHIVE_SOURCE_PROPERTY = "productSource";
  /** Property for archive superseded */
  public static final String ARCHIVE_SUPERSEDED_PROPERTY = "onlySuperseded";
  /** Property for archive unassociated */
  public static final String ARCHIVE_UNASSOCIATED_PROPERTY = "onlyUnassociated";
  /** Property for archive product status */
  public static final String ARCHIVE_STATUS_PROPERTY = "productStatus";

  /** Default state for archive superseded */
  public static final String DEFAULT_ARCHIVE_SUPERSEDED = "true";
  /** Default state for archive unassociated */
  public static final String DEFAULT_ARCHIVE_UNASSOCIATED = "false";
  // --------------------------------------------------------------------
  // Configured parameters.
  // --------------------------------------------------------------------

  /** Configured parameter for min product age */
  protected Long minProductAge = null;
  /** Configured parameter for max product age */
  protected Long maxProductAge = null;
  /** Configured parameter for min product time */
  protected Long minProductTime = null;
  /** Configured parameter for max product time */
  protected Long maxProductTime = null;

  /** Configured parameter for product type */
  protected String productType = null;
  /** Configured parameter for product source */
  protected String productSource = null;
  /** Configured parameter for only superseded */
  protected boolean onlySuperseded = true;
  /** Configured parameter for only unassociated */
  protected boolean onlyUnassociated = false;
  /** Configured parameter for product status */
  protected String productStatus = null;

  @SuppressWarnings("deprecation")
  @Override
  public void configure(Config config) throws Exception {
    super.configure(config);

    minProductAge = parseLong(config, ARCHIVE_MIN_PRODUCT_AGE_PROPERTY);
    maxProductAge = parseLong(config, ARCHIVE_MAX_PRODUCT_AGE_PROPERTY);

    minProductTime = parseDateOrLong(config, ARCHIVE_MIN_PRODUCT_TIME_PROPERTY);
    maxProductTime = parseDateOrLong(config, ARCHIVE_MAX_PRODUCT_TIME_PROPERTY);

    if (minProductAge != null && maxProductTime != null) {
      LOGGER.config("Both minProductAge and maxProductTime were specified. "
          + "Ignoring minProductAge. Only maxProductTime will be used.");
    }
    if (maxProductAge != null && minProductTime != null) {
      LOGGER.config("Both maxProductAge and minProductTime were specified. "
          + "Ignoring maxProductAge. Only minProductTime will be used.");
    }

    if ((minAge != null || maxAge != null)
        && (minProductAge != null || maxProductAge != null || minProductTime != null || maxProductTime != null)) {
      /*
       * Do we need to log in addition to throwing the exception?
       * LOGGER.severe("Configuration mismatch. Can not specify both " +
       * "minAge/maxAge (legacy) properties as well as " +
       * "minEventAge/maxEventAge.");
       */
      ConfigurationException ce = new ConfigurationException("Configuration mismatch. Can not specify both "
          + "minAge/maxAge (legacy) properties as well as " + "minProductAge/maxProductAge.");
      ce.fillInStackTrace();
      throw ce;
    }

    if ((minProductAge != null && maxProductAge != null) && (minProductAge > maxProductAge)) {

      ConfigurationException ce = new ConfigurationException(
          "Configuration mismatch. minProductAge " + "greater than maxProductAge.");
      ce.fillInStackTrace();
      throw ce;
    }

    if ((minProductTime != null && maxProductTime != null) && (minProductTime > maxProductTime)) {

      ConfigurationException ce = new ConfigurationException(
          "Configuration mismatch. minProductTime " + "greater than maxProductTime.");
      ce.fillInStackTrace();
      throw ce;
    }

    productType = config.getProperty(ARCHIVE_TYPE_PROPERTY);
    productSource = config.getProperty(ARCHIVE_SOURCE_PROPERTY);
    onlySuperseded = Boolean.valueOf(config.getProperty(ARCHIVE_SUPERSEDED_PROPERTY, DEFAULT_ARCHIVE_SUPERSEDED));
    onlyUnassociated = Boolean.valueOf(config.getProperty(ARCHIVE_UNASSOCIATED_PROPERTY, DEFAULT_ARCHIVE_UNASSOCIATED));

    productStatus = config.getProperty(ARCHIVE_STATUS_PROPERTY);
  }

  @SuppressWarnings("deprecation")
  @Override
  public ProductIndexQuery getIndexQuery() {
    ProductIndexQuery productIndexQuery = super.getIndexQuery();
    Date now = new Date();

    // Order of minAge, minProductAge, minProductTime is important here.
    // Preference order is minProductTime > minProductAge > minAge
    // Similar for max* properties.

    if (minAge != null) {
      // min age corresponds to minimum product created time
      productIndexQuery.setMinProductUpdateTime(new Date(now.getTime() - minAge.longValue()));
      productIndexQuery.setMinEventTime(null);
    }
    if (maxAge != null) {
      // max age corresponds to maximum product created time
      productIndexQuery.setMaxProductUpdateTime(new Date(now.getTime() - maxAge.longValue()));
      productIndexQuery.setMaxEventTime(null);
    }

    // See ASCII art in ArchivePolicy.getIndexQuery if you are confused by
    // maxAge --> minTime differences.

    if (maxProductAge != null) {
      productIndexQuery.setMinProductUpdateTime(new Date(now.getTime() - maxProductAge.longValue()));
    }
    if (minProductAge != null) {
      productIndexQuery.setMaxProductUpdateTime(new Date(now.getTime() - minProductAge.longValue()));
    }

    if (minProductTime != null) {
      productIndexQuery.setMinProductUpdateTime(new Date(minProductTime.longValue()));
    }
    if (maxProductTime != null) {
      productIndexQuery.setMaxProductUpdateTime(new Date(maxProductTime.longValue()));
    }

    // search for products of a specific type
    productIndexQuery.setProductType(productType);
    // search for products from a specific source
    productIndexQuery.setProductSource(productSource);

    if (onlySuperseded) {
      // remove only old versions of products (keep the latest)
      productIndexQuery.setResultType(ProductIndexQuery.RESULT_TYPE_SUPERSEDED);
    } else {
      // otherwise include all products
      productIndexQuery.setResultType(ProductIndexQuery.RESULT_TYPE_ALL);
    }

    productIndexQuery.setProductStatus(productStatus);

    // this archive policy searches products, so this shouldn't matter, but
    // just to be safe in case the default changes
    productIndexQuery.setEventSearchType(ProductIndexQuery.SEARCH_EVENT_PRODUCTS);

    return productIndexQuery;
  }

  @Override
  public boolean isValidPolicy() {
    boolean valid = super.isValidPolicy();
    return valid || (minProductAge != null || maxProductAge != null || minProductTime != null || maxProductTime != null
        || productType != null || productSource != null || productStatus != null);
  }

  /** @return minProductAge */
  public Long getMinProductAge() {
    return minProductAge;
  }

  /** @param minProductAge to set */
  public void setMinProductAge(Long minProductAge) {
    this.minProductAge = minProductAge;
  }

  /** @return maxProductAge */
  public Long getMaxProductAge() {
    return maxProductAge;
  }

  /** @param maxProductAge to set */
  public void setMaxProductAge(Long maxProductAge) {
    this.maxProductAge = maxProductAge;
  }

  /** @return minProductTime */
  public Long getMinProductTime() {
    return minProductTime;
  }

  /** @param minProductTime to set */
  public void setMinProductTime(Long minProductTime) {
    this.minProductTime = minProductTime;
  }

  /** @return maxProductTime */
  public Long getMaxProductTime() {
    return maxProductTime;
  }

  /** @param maxProductTime to set */
  public void setMaxProductTime(Long maxProductTime) {
    this.maxProductTime = maxProductTime;
  }

  /** @return productType */
  public String getProductType() {
    return productType;
  }

  /** @param productType to set */
  public void setProductType(String productType) {
    this.productType = productType;
  }

  /** @return productSource */
  public String getProductSource() {
    return productSource;
  }

  /** @param productSource to set */
  public void setProductSource(String productSource) {
    this.productSource = productSource;
  }

  /** @return onlySuperseded */
  public boolean isOnlySuperseded() {
    return onlySuperseded;
  }

  /** @param onlySuperseded to set */
  public void setOnlySuperseded(boolean onlySuperseded) {
    this.onlySuperseded = onlySuperseded;
  }

  /** @return onlyUnassociated */
  public boolean isOnlyUnassociated() {
    return onlyUnassociated;
  }

  /** @param onlyUnassociated to set */
  public void setOnlyUnassociated(boolean onlyUnassociated) {
    this.onlyUnassociated = onlyUnassociated;
  }

  /** @return productStatus */
  public String getProductStatus() {
    return productStatus;
  }

  /** @param productStatus to set */
  public void setProductStatus(String productStatus) {
    this.productStatus = productStatus;
  }
}