OriginIndexerModule.java
- package gov.usgs.earthquake.origin;
- import java.io.IOException;
- import java.math.BigDecimal;
- import java.util.Map;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javax.json.JsonObject;
- import gov.usgs.earthquake.geoserve.GeoservePlacesService;
- import gov.usgs.earthquake.geoserve.GeoserveRegionsService;
- import gov.usgs.earthquake.indexer.DefaultIndexerModule;
- import gov.usgs.earthquake.indexer.IndexerModule;
- import gov.usgs.earthquake.indexer.ProductSummary;
- import gov.usgs.earthquake.product.Product;
- import gov.usgs.util.Config;
- import gov.usgs.util.StringUtils;
- /**
- * Class for summarizing "origin" type products during the indexing process.
- * Specifically this implementation uses a GeoservePlacesService to augment the
- * properties on the product to include a "title" property if one is not already
- * present.
- *
- * This module may be configured with the following properties: `endpointUrl`
- * `connectTimeout`, and `readTimeout`.
- */
- public class OriginIndexerModule extends DefaultIndexerModule {
- private static final Logger LOGGER = Logger.getLogger(OriginIndexerModule.class.getName());
- private GeoservePlacesService geoservePlaces;
- private GeoserveRegionsService geoserveRegions;
- /** Property for places endpoint url */
- public static final String PLACES_ENDPOINT_URL_PROPERTY = "placesEndpointUrl";
- /** property for regions endpoint url */
- public static final String REGIONS_ENDPOINT_URL_PROPERTY = "regionsEndpointUrl";
- /** property for connectTimeout */
- public static final String CONNECT_TIMEOUT_PROPERTY = "connectTimeout";
- /** Properties for readTimeout */
- public static final String READ_TIMEOUT_PROPERTY = "readTimeout";
- /** Property for Geoserve distance threshold */
- public static final String GEOSERVE_DISTANCE_THRESHOLD_PROPERTY = "geoserveDistanceThreshold";
- /**
- * Distance threshold (in km), determines whether to use fe region
- * or nearest place in the event title
- */
- public static final int DEFAULT_GEOSERVE_DISTANCE_THRESHOLD = 300;
- private int distanceThreshold;
- /**
- * Empty constructor
- * Do nothing, must be configured through bootstrapping before use
- */
- public OriginIndexerModule() {
- }
- /**
- * Constructor
- * @param geoservePlaces GeoservePlacesService
- * @param geoserveRegions GeoserveRegionsService
- */
- public OriginIndexerModule(
- final GeoservePlacesService geoservePlaces,
- final GeoserveRegionsService geoserveRegions
- ) {
- this.setPlacesService(geoservePlaces);
- this.setRegionsService(geoserveRegions);
- }
- /**
- * @return The places service currently being used to return nearby places
- */
- public GeoservePlacesService getPlacesService() {
- return this.geoservePlaces;
- }
- /**
- * @return The regions service currently being used to return fe regions
- */
- public GeoserveRegionsService getRegionsService() {
- return this.geoserveRegions;
- }
- /**
- * @return The distance threshold currently being used to default to FE region
- */
- public int getDistanceThreshold() {
- return this.distanceThreshold;
- }
- @Override
- public ProductSummary getProductSummary(Product product) throws Exception {
- ProductSummary summary = super.getProductSummary(product);
- BigDecimal latitude = summary.getEventLatitude();
- BigDecimal longitude = summary.getEventLongitude();
- // Defer to existing title property if set...
- Map<String, String> summaryProperties = summary.getProperties();
- String title = summaryProperties.get("title");
- if (title == null && latitude != null && longitude != null) {
- try {
- title = this.getEventTitle(latitude, longitude);
- summaryProperties.put("title", StringUtils.encodeAsUtf8(title));
- } catch (Exception ex) {
- LOGGER
- .warning(String.format("[%s] %s for product %s", this.getName(), ex.getMessage(), product.getId().toString()));
- // Do nothing, value-added failed. Move on.
- }
- }
- return summary;
- }
- @Override
- public int getSupportLevel(Product product) {
- int supportLevel = IndexerModule.LEVEL_UNSUPPORTED;
- String type = getBaseProductType(product.getId().getType());
- if ("origin".equals(type) && !"DELETE".equalsIgnoreCase(product.getStatus())) {
- supportLevel = IndexerModule.LEVEL_SUPPORTED;
- }
- return supportLevel;
- }
- /**
- * Set the GeoservePlacesService to be used for subsequent calls to GeoServe places
- * endpoint.
- *
- * @param geoservePlaces The GeoservePlacesService to use
- */
- public void setPlacesService(GeoservePlacesService geoservePlaces) {
- this.geoservePlaces = geoservePlaces;
- }
- /**
- * Set the geoserveRegions to be used for subsequent calls to GeoServe regions
- * endpoint.
- *
- * @param geoserveRegions The GeoserveRegions to use
- */
- public void setRegionsService(GeoserveRegionsService geoserveRegions) {
- this.geoserveRegions = geoserveRegions;
- }
- /**
- * Set the distance threshold to prefer fe region over nearst place
- * in the event title
- *
- * @param threshold The distance threshold to use
- */
- public void setDistanceThreshold(int threshold) {
- this.distanceThreshold = threshold;
- }
- @Override
- public void configure(Config config) throws Exception {
- // Distance threshold (in km)
- this.distanceThreshold = Integer.parseInt(
- config.getProperty(
- GEOSERVE_DISTANCE_THRESHOLD_PROPERTY,
- Integer.toString(DEFAULT_GEOSERVE_DISTANCE_THRESHOLD)
- )
- );
- // Geoserve Places Endpoint configuration
- String placesEndpointUrl = config.getProperty(
- PLACES_ENDPOINT_URL_PROPERTY,
- GeoservePlacesService.DEFAULT_ENDPOINT_URL
- );
- int placesEndpointConnectTimeout = Integer.parseInt(
- config.getProperty(
- CONNECT_TIMEOUT_PROPERTY,
- Integer.toString(GeoservePlacesService.DEFAULT_CONNECT_TIMEOUT)
- )
- );
- int placesEndpointReadTimeout = Integer.parseInt(
- config.getProperty(
- READ_TIMEOUT_PROPERTY,
- Integer.toString(GeoservePlacesService.DEFAULT_READ_TIMEOUT)
- )
- );
- LOGGER.config(
- String.format("[%s] GeoservePlacesService(%s, %d, %d)",
- this.getName(),
- placesEndpointUrl,
- placesEndpointConnectTimeout,
- placesEndpointReadTimeout
- )
- );
- this.setPlacesService(
- new GeoservePlacesService(
- placesEndpointUrl,
- placesEndpointConnectTimeout,
- placesEndpointReadTimeout
- )
- );
- // Geoserve Regions Endpoint configuration
- String regionsEndpointUrl = config.getProperty(
- REGIONS_ENDPOINT_URL_PROPERTY,
- GeoserveRegionsService.DEFAULT_ENDPOINT_URL
- );
- int regionsEndpointConnectTimeout = Integer.parseInt(
- config.getProperty(
- CONNECT_TIMEOUT_PROPERTY,
- Integer.toString(GeoserveRegionsService.DEFAULT_CONNECT_TIMEOUT)
- )
- );
- int regionsEndpointReadTimeout = Integer.parseInt(
- config.getProperty(
- READ_TIMEOUT_PROPERTY,
- Integer.toString(GeoserveRegionsService.DEFAULT_READ_TIMEOUT)
- )
- );
- LOGGER.config(
- String.format("[%s] GeoserveRegionsService(%s, %d, %d)",
- this.getName(),
- regionsEndpointUrl,
- regionsEndpointConnectTimeout,
- regionsEndpointReadTimeout
- )
- );
- this.setRegionsService(
- new GeoserveRegionsService(
- regionsEndpointUrl,
- regionsEndpointConnectTimeout,
- regionsEndpointReadTimeout
- )
- );
- }
- /**
- * Get the event title based on the name and location of the nearest
- * place, or if the nearest place is outside of the distance threshold
- * return the fe region name
- *
- * @param latitude event latitude in degrees
- * @param longitude event longitude in degrees
- *
- * @return {String} event name
- *
- * @throws IOException if IO error occurs
- */
- public String getEventTitle(BigDecimal latitude, BigDecimal longitude) throws Exception, IOException {
- StringBuffer messages = new StringBuffer();
- String message = null;
- try {
- final JsonObject feature = this.geoservePlaces.getNearestPlace(
- latitude,
- longitude,
- this.distanceThreshold
- );
- if (feature != null) {
- return this.formatEventTitle(feature);
- } else {
- message = "Places service returned no places within distance threshold";
- messages.append(message + ". ");
- LOGGER.log(Level.INFO, "[" + this.getName() + "] " + message);
- }
- } catch (Exception e) {
- message = "Failed to get nearest place from geoserve places service";
- messages.append(message + ". ");
- messages.append(e.getMessage() + ". ");
- LOGGER.log(Level.INFO, "[" + this.getName() + "] " + message);
- }
- try {
- return this.geoserveRegions.getFeRegionName(latitude, longitude);
- } catch (Exception e) {
- message = "Failed to get FE region name";
- messages.append(message + ". ");
- messages.append(e.getMessage() + ". ");
- LOGGER.log(Level.INFO, "[" + this.getName() + "] .");
- }
- // If we get this far, things failed spectacularly, report the error
- Exception e = new Exception(messages.toString());
- e.fillInStackTrace();
- throw e;
- }
- /**
- * Takes properties from feature and formats them into a string
- * @param feature feature to format
- * @return string with distance, direction, name, and admin
- */
- public String formatEventTitle(JsonObject feature) {
- JsonObject properties = feature.getJsonObject("properties");
- String name = properties.getString("name");
- String country = properties.getString("country_code").toLowerCase();
- String admin = properties.getString("country_name");
- int distance = properties.getInt("distance");
- double azimuth = properties.getJsonNumber("azimuth").doubleValue();
- String direction = azimuthToDirection(azimuth);
- if ("us".equals(country)) {
- admin = properties.getString("admin1_name");
- }
- return String.format("%d km %s of %s, %s", distance, direction, name, admin);
- }
- /**
- * Converts a decimal degree azimuth to a canonical compass direction
- *
- * @param azimuth The degrees azimuth to be converted
- *
- * @return {String} The canonical compass direction for the given input azimuth
- */
- public String azimuthToDirection(double azimuth) {
- double fullwind = 22.5;
- String[] directions = { "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW",
- "NNW", "N" };
- // Invert azimuth for proper directivity
- // Maybe not needed in the future.
- azimuth += 180.0;
- // adjust azimuth if negative
- while (azimuth < 0.0) {
- azimuth = azimuth + 360.0;
- }
- return directions[(int) Math.round((azimuth % 360.0) / fullwind)];
- }
- public static void main(String[] args) throws Exception {
- BigDecimal latitude = new BigDecimal("0.0");
- BigDecimal longitude = new BigDecimal("0.0");
- int maxradiuskm = DEFAULT_GEOSERVE_DISTANCE_THRESHOLD;
- final OriginIndexerModule module = new OriginIndexerModule(
- new GeoservePlacesService(),
- new GeoserveRegionsService()
- );
- module.setName("TestModule");
- for (String arg : args) {
- if (arg.startsWith("--latitude=")) {
- latitude = new BigDecimal(arg.replace("--latitude=", ""));
- } else if (arg.startsWith("--longitude=")) {
- longitude = new BigDecimal(arg.replace("--longitude=", ""));
- } else if (arg.startsWith("--maxradiuskm=")) {
- maxradiuskm = Integer.parseInt(arg.replace("--maxradiuskm=", ""));
- }
- }
- module.setDistanceThreshold(maxradiuskm);
- System.out.printf("Title[%s, %s] = `%s`\n",
- latitude.doubleValue(),
- longitude.doubleValue(),
- module.getEventTitle(latitude, longitude));
- }
- }