ExternalPreferredListener.java

package gov.usgs.earthquake.indexer;

import java.util.HashMap;
import java.util.Map;

import gov.usgs.earthquake.product.Product;

/**
 * (Experimental) Notify external processes when preferred product change within events.
 *
 * @author jmfee
 *
 */
public class ExternalPreferredListener extends ExternalIndexerListener {

	/** Argument for Preferred action */
	public static final String PREFERRED_ACTION_ARGUMENT = "--preferred-action=";

	/**
	 * Types of preferred product actions.
	 */
	public static enum PreferredAction {
		/** Preferred added product enum */
		PREFERRED_ADDED,
		/** Preferred changed product enum */
		PREFERRED_CHANGED,
		/** Preferred removed product enum */
		PREFERRED_REMOVED
	};

	/**
	 * Skip parent class processing, except autoArchiving.
	 */
	@Override
	public boolean accept(final IndexerEvent event) {
		return false;
	}

	/**
	 * Handle indexer events.
	 */
	@Override
	public void onIndexerEvent(final IndexerEvent event) throws Exception {
		for (IndexerChange change : event.getIndexerChanges()) {
			if (!accept(event, change)) {
				// ignoreArchive, processOnlyWhenEventChanged checks
				continue;
			}

			Map<ProductSummary, PreferredAction> changes = getIndexerChangePreferredActions(change);
			for (ProductSummary changedProduct : changes.keySet()) {
				if (!accept(changedProduct.getId())) {
					continue;
				}

				Event changedEvent = change.getNewEvent();
				if (changedEvent == null) {
					// event archived...
					changedEvent = change.getOriginalEvent();
				}

				String command = getProductSummaryCommand(changedEvent, changedProduct);

				// indexer action
				command = command + " " +
						ExternalIndexerListener.EVENT_ACTION_ARGUMENT +
						change.getType().toString();

				// preferred product action
				command = command + " " +
						PREFERRED_ACTION_ARGUMENT +
						changes.get(changedProduct).toString();

				// pass product content as input to command
				Product product = null;
				try {
					// this product is not necessarily the product that triggered the change.
					product = storeProduct(event.getIndexer().getProductStorage().getProduct(changedProduct.getId()));
				} catch (Exception e) {
					// ignore, just leave null
				}

				runProductCommand(command, product);
			}
		}

		super.onIndexerEvent(event);
	}

	/**
	 * Compare preferred products before/after IndexerChange was applied.
	 *
	 * @param change indexer change to evaluate.
	 * @return map of preferred products that were changed.
	 */
	public static Map<ProductSummary, PreferredAction> getIndexerChangePreferredActions(final IndexerChange change) {
		Map<ProductSummary, PreferredAction> changes = new HashMap<ProductSummary, PreferredAction>();

		// only event types
		IndexerChange.IndexerChangeType changeType = change.getType();
		if (changeType != IndexerChange.EVENT_ADDED &&
				changeType != IndexerChange.EVENT_DELETED &&
				changeType != IndexerChange.EVENT_MERGED &&
				changeType != IndexerChange.EVENT_SPLIT &&
				changeType != IndexerChange.EVENT_UPDATED) {
			return changes;
		}

		Map<String, ProductSummary> newProducts = getPreferredProducts(change.getNewEvent());
		Map<String, ProductSummary> originalProducts = getPreferredProducts(change.getOriginalEvent());

		// check all currently preferred products
		for (String type : newProducts.keySet()) {
			ProductSummary newProduct = newProducts.get(type);
			ProductSummary originalProduct = originalProducts.get(type);

			if (originalProduct == null) {
				// no product of this type previously existed
				changes.put(newProduct,
						PreferredAction.PREFERRED_ADDED);
			} else if (!newProduct.getId().equals(originalProduct.getId())) {
				// different from previous preferred product of same type
				changes.put(newProduct,
						PreferredAction.PREFERRED_CHANGED);
			}
		}

		for (String type : originalProducts.keySet()) {
			if (newProducts.get(type) == null) {
				// no product of this type exists anymore
				changes.put(originalProducts.get(type),
						PreferredAction.PREFERRED_REMOVED);
			}
		}

		return changes;
	}

	/**
	 * Get a map of preferred products from an event.
	 *
	 * @param event the event.
	 * @return preferred products, or empty hashmap if event is null.
	 */
	public static Map<String, ProductSummary> getPreferredProducts(final Event event) {
		if (event == null) {
			return new HashMap<String, ProductSummary>();
		}
		return event.getPreferredProducts();
	}

}