DefaultNotificationSender.java

  1. package gov.usgs.earthquake.distribution;

  2. import gov.usgs.earthquake.product.Product;
  3. import gov.usgs.earthquake.product.ProductId;
  4. import gov.usgs.util.Config;

  5. import java.util.Date;
  6. import java.util.Iterator;
  7. import java.util.List;
  8. import java.util.logging.Logger;

  9. /**
  10.  * The base class for all Notification senders.
  11.  *
  12.  * The DefaultNotificationSender references a general need to send notifications. It extends DefaultNotificationListener
  13.  * to allow forwarding of products from any subclass of DefaultNotificationReceiver. *
  14.  */
  15. public class DefaultNotificationSender extends DefaultNotificationListener {

  16.   private static final Logger LOGGER = Logger
  17.           .getLogger(DefaultNotificationSender.class.getName());

  18.   /** Property referencing the server host */
  19.   public static final String SERVER_HOST_PROPERTY = "serverHost";

  20.   /** Property referencing the server port */
  21.   public static final String SERVER_PORT_PROPERTY = "serverPort";

  22.   /** Property referencing product storage object to use */
  23.   public static final String PRODUCT_STORAGE_PROPERTY = "storage";

  24.   /** Property referencing the length of time products should be held in storage*/
  25.   public static final String PRODUCT_STORAGE_MAX_AGE_PROPERTY = "storageage";
  26.   /** property for max age of product in storage. 7000 days? */
  27.   public static final String DEFAULT_PRODUCT_STORAGE_MAX_AGE = "604800000";

  28.   /** Variable for String serverHost */
  29.   protected String serverHost;
  30.   /** Variable for String serverPort */
  31.   protected String serverPort;
  32.   /** Variable for URL productStorage */
  33.   protected URLProductStorage productStorage;
  34.   /** Variable for long productStorageMaxAge */
  35.   protected long productStorageMaxAge;


  36.   /**
  37.    * Configures based on configuration section.
  38.    *
  39.    * @param config
  40.    *            The config
  41.    * @throws Exception if something goes wrong
  42.    */
  43.   public void configure(Config config) throws Exception {
  44.     // let default notification listener configure itself
  45.     super.configure(config);

  46.     if (getNotificationIndex() == null) {
  47.       throw new ConfigurationException("[" + getName()
  48.               + "] 'index' is a required configuration property");
  49.     }

  50.     String productStorageName = config.getProperty(PRODUCT_STORAGE_PROPERTY);
  51.     if (productStorageName == null) {
  52.       throw new ConfigurationException("[" + getName() + "] '" + PRODUCT_STORAGE_PROPERTY + "' is a required property.");
  53.     }
  54.     LOGGER.config("[" + getName() + "] loading product storage '" + productStorageName + "'.");
  55.     this.productStorage = (URLProductStorage) Config.getConfig().getObject(productStorageName);
  56.     if (productStorage == null) {
  57.       throw new ConfigurationException("[" + getName() + "] product storage '" + productStorageName + "' improperly configured.");
  58.     }

  59.     productStorageMaxAge = Long.parseLong(config.getProperty(PRODUCT_STORAGE_MAX_AGE_PROPERTY,DEFAULT_PRODUCT_STORAGE_MAX_AGE));
  60.     LOGGER.config("[" + getName() + "] product storage max age: " + productStorageMaxAge + "ms");

  61.     serverHost = config.getProperty(SERVER_HOST_PROPERTY);
  62.     LOGGER.config("[" + getName() + "] messenger server host: " + serverHost);

  63.     serverPort = config.getProperty(SERVER_PORT_PROPERTY);
  64.     LOGGER.config("[" + getName() + "] messenger server port: " + serverPort);
  65.   }

  66.   /**
  67.    * Called on receipt of a new product. Stores this product and calls sendMessage()
  68.    * Most of this logic was lifted from the pre-08/2019 EIDSNotificationSender class.
  69.    *
  70.    * @param product
  71.    *            a product whose notification was accepted.
  72.    * @throws Exception if something goes wrong
  73.    */
  74.   public void onProduct(final Product product) throws Exception {
  75.     ProductId id = product.getId();

  76.     // store product
  77.     try {
  78.       productStorage.storeProduct(product);
  79.     } catch (ProductAlreadyInStorageException e) {
  80.       // ignore
  81.     }

  82.     // create notification
  83.     // make expiration relative to now
  84.     Date expirationDate = new Date(new Date().getTime()
  85.             + productStorageMaxAge);
  86.     URLNotification notification = new URLNotification(id, expirationDate,
  87.             product.getTrackerURL(), productStorage.getProductURL(id));

  88.     // remove any existing notifications, generally there won't be any
  89.     Iterator<Notification> existing = getNotificationIndex()
  90.             .findNotifications(id).iterator();
  91.     while (existing.hasNext()) {
  92.       getNotificationIndex().removeNotification(existing.next());
  93.     }

  94.     // send notification
  95.     try {
  96.       sendNotification(notification);
  97.     } catch (Exception e) {
  98.       // if fails, try to remove from storage
  99.       productStorage.removeProduct(id);
  100.       throw e;
  101.     }

  102.     // add created notification to index. Used to track which products
  103.     // have been processed, and to delete after expirationDate
  104.     // done after send in case send fails
  105.     getNotificationIndex().addNotification(notification);

  106.     // track that notification was sent
  107.     new ProductTracker(notification.getTrackerURL()).notificationSent(
  108.             this.getName(), notification);
  109.   }

  110.   /**
  111.    * Called just before this listener processes a notification.
  112.    *
  113.    * @param notification
  114.    *            notification about to be processed.
  115.    * @return true to process the notification, false to skip
  116.    * @throws Exception if something goes wrong
  117.    */
  118.   @Override
  119.   protected boolean onBeforeProcessNotification(
  120.           final Notification notification) throws Exception {
  121.     if (!isProcessDuplicates()) {
  122.       // only check if we care
  123.       List<Notification> notifications = getNotificationIndex()
  124.               .findNotifications(notification.getProductId());
  125.       if (notifications.size() > 0) {
  126.         if (productStorage.hasProduct(notification.getProductId())) {
  127.           LOGGER.finer("[" + getName()
  128.                   + "] skipping existing product "
  129.                   + notification.getProductId().toString());
  130.           return false;
  131.         } else {
  132.           LOGGER.finer("["
  133.                   + getName()
  134.                   + "] found notifications, but product missing from storage "
  135.                   + notification.getProductId().toString());
  136.         }
  137.       }
  138.     }

  139.     return true;
  140.   }

  141.   @Override
  142.   protected void onAfterProcessNotification(final Notification notification) {
  143.     // function replaced so notifications not added to index
  144.     // this class responds to the index
  145.   }

  146.   /**
  147.    * Called when a notification expires
  148.    *
  149.    * @param notification
  150.    *                The expired notification
  151.    * @throws Exception if something goes wrong
  152.    */
  153.   @Override
  154.   public void onExpiredNotification(final Notification notification) throws Exception{
  155.     List<Notification> notifications = getNotificationIndex()
  156.             .findNotifications(notification.getProductId());
  157.     if (notifications.size() <= 1) {
  158.       // this is called before removing notification from index.
  159.       productStorage.removeProduct(notification.getProductId());
  160.       LOGGER.finer("[" + getName()
  161.               + "] removed expired product from sender storage "
  162.               + notification.getProductId().toString());
  163.     } else {
  164.       // still have notifications left for product, don't remove
  165.     }
  166.   }

  167.   /**
  168.    * Utility method to do the actual notification sending. Should be overridden by subclasses.
  169.    *
  170.    * @param notification
  171.    *            The notification to send
  172.    * @throws Exception if something goes wrong
  173.    */
  174.   protected void sendNotification(final Notification notification) throws Exception {
  175.     LOGGER.info("[" + getName() + "] sent message " + notification.toString());
  176.   }

  177.   /**
  178.    * Start up storage
  179.    *
  180.    * @throws Exception if something goes wrong
  181.    */
  182.   public void startup() throws Exception{
  183.     productStorage.startup();
  184.     super.startup();
  185.   }

  186.   /**
  187.    * Shut down storage
  188.    *
  189.    * @throws Exception if something goes wrong
  190.    */
  191.   public void shutdown() throws Exception{
  192.     super.shutdown();
  193.     try {
  194.       productStorage.shutdown();
  195.     } catch (Exception e) {
  196.       //do nothing
  197.     }
  198.   }


  199.   /** @return serverHost */
  200.   public String getServerHost() {
  201.     return serverHost;
  202.   }

  203.   /** @param serverHost string to set */
  204.   public void setServerHost(String serverHost) {
  205.     this.serverHost = serverHost;
  206.   }

  207.   /** @return serverPort */
  208.   public String getServerPort() {
  209.     return serverPort;
  210.   }

  211.   /** @param serverPort string to set */
  212.   public void setServerPort(String serverPort) {
  213.     this.serverPort = serverPort;
  214.   }

  215.   /** @return productStorage */
  216.   public URLProductStorage getProductStorage() {
  217.     return productStorage;
  218.   }

  219.   /** @param productStorage URLProductStorage to set */
  220.   public void setProductStorage(URLProductStorage productStorage) {
  221.     this.productStorage = productStorage;
  222.   }

  223.   /** @return productStorageMaxAge */
  224.   public long getProductStorageMaxAge() {
  225.     return productStorageMaxAge;
  226.   }

  227.   /** @param productStorageMaxAge long to set */
  228.   public void setProductStorageMaxAge(long productStorageMaxAge) {
  229.     this.productStorageMaxAge = productStorageMaxAge;
  230.   }
  231. }