ANSSRegionsFactory.java
- package gov.usgs.earthquake.geoserve;
- import java.io.File;
- import java.io.InputStream;
- import java.io.IOException;
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javax.json.Json;
- import javax.json.JsonObject;
- import gov.usgs.earthquake.qdm.Regions;
- import gov.usgs.util.FileUtils;
- import gov.usgs.util.StreamUtils;
- import gov.usgs.util.XmlUtils;
- /**
- * Class to manage ANSS Authoritative Region updates.
- *
- * Simplest usage:
- * ANSSRegionsFactory.getFactory().getRegions()
- *
- * Regions are not fetched until {@link #startup()}
- * (or {@link #fetchRegions()}) is called.
- */
- public class ANSSRegionsFactory {
- /** logging object */
- public static final Logger LOGGER = Logger.getLogger(ANSSRegionsFactory.class.getName());
- /** milliseconds per day */
- public static final long MILLISECONDS_PER_DAY = 86400000L;
- /** path to write regions.json */
- public static final String DEFAULT_REGIONS_JSON = "regions.json";
- /** global factory object */
- private static ANSSRegionsFactory SINGLETON;
- /** service used to load regions */
- private GeoserveLayersService geoserveLayersService;
- /** path to local regions file */
- private File localRegions = new File(DEFAULT_REGIONS_JSON);
- /** the current regions object */
- private Regions regions;
- /** shutdown hook registered by startup */
- private Thread shutdownHook;
- /** timer used to auto fetch region updates */
- private Timer updateTimer = new Timer();
- /**
- * Use default GeoserveLayersService.
- */
- public ANSSRegionsFactory () {
- this(new GeoserveLayersService());
- }
- /**
- * Use custom GeoserveLayersService.
- * @param geoserveLayersService to use
- */
- public ANSSRegionsFactory (final GeoserveLayersService geoserveLayersService) {
- this.geoserveLayersService = geoserveLayersService;
- }
- /**
- * Get the global ANSSRegionsFactory,
- * creating and starting if needed.
- * @return ANSSRegionsFactory
- */
- public static synchronized ANSSRegionsFactory getFactory() {
- return getFactory(true);
- }
- /**
- * @param startup if Factory should be created and started, if needed
- * @return ANSSRegionsFactory
- */
- public static synchronized ANSSRegionsFactory getFactory(final boolean startup) {
- if (SINGLETON == null) {
- SINGLETON = new ANSSRegionsFactory();
- if (startup) {
- SINGLETON.startup();
- }
- }
- return SINGLETON;
- }
- /**
- * Set the global ANSSRegionsFactory,
- * shutting down any existing factory if needed.
- * @param factory to set
- */
- public static synchronized void setFactory(final ANSSRegionsFactory factory) {
- if (SINGLETON != null) {
- SINGLETON.shutdown();
- }
- SINGLETON = factory;
- }
- /**
- * Download regions from geoserve.
- *
- * Writes out to "regions.json" in current working directory and,
- * if unable to update, reads in local copy.
- */
- public void fetchRegions () {
- try {
- // try loading from geoserve
- this.regions = loadFromGeoserve();
- } catch (Exception e) {
- LOGGER.log(Level.WARNING,
- "Error fetching ANSS Regions from geoserve",
- e);
- try {
- if (this.regions == null) {
- // fall back to local cache
- this.regions = loadFromFile();
- }
- } catch (Exception e2) {
- LOGGER.log(Level.WARNING,
- "Error fetching ANSS Regions from local file",
- e);
- }
- }
- }
- /**
- * Read regions from local regions file.
- * @return Regions
- * @throws IOException if error occurs
- */
- protected Regions loadFromFile() throws IOException {
- try (InputStream in = StreamUtils.getInputStream(this.localRegions)) {
- JsonObject json = Json.createReader(in).readObject();
- Regions regions = new RegionsJSON().parseRegions(json);
- // regions loaded
- LOGGER.fine("Loaded ANSS Authoritative Regions from "
- + this.localRegions
- + ", last modified=" + XmlUtils.formatDate(
- new Date(this.localRegions.lastModified())));
- return regions;
- }
- }
- /**
- * Read regions from geoserve service.
- * @return Regions
- * @throws IOException if error occurs
- */
- protected Regions loadFromGeoserve() throws IOException {
- LOGGER.fine("Fetching ANSS Authoritative Regions from Geoserve");
- JsonObject json = this.geoserveLayersService.getLayer("anss");
- Regions regions = new RegionsJSON().parseRegions(json);
- LOGGER.finer("Loaded ANSS Authoritative Regions from Geoserve");
- try {
- saveToFile(this.localRegions, json);
- } catch (IOException e) {
- // log for now, since saving is value added
- LOGGER.log(Level.INFO, "Error saving local regions", e);
- }
- return regions;
- }
- /**
- * Store json to local regions file.
- *
- * @param regionsFile to store to
- * @param json json response to store locally.
- * @throws IOException if IO error occurs
- */
- protected void saveToFile(final File regionsFile, final JsonObject json) throws IOException {
- LOGGER.fine("Storing ANSS Authoritative Regions to " + regionsFile);
- // save regions if needed later
- FileUtils.writeFileThenMove(
- new File(regionsFile.toString() + ".temp"),
- regionsFile,
- json.toString().getBytes());
- LOGGER.finer("Stored ANSS Regions to " + regionsFile);
- }
- /**
- * Start updating regions.
- */
- public void startup() {
- if (this.shutdownHook != null) {
- // already started
- return;
- }
- // do initial fetch
- fetchRegions();
- // schedule periodic fetch
- long now = new Date().getTime();
- long nextMidnight = MILLISECONDS_PER_DAY - (now % MILLISECONDS_PER_DAY);
- updateTimer.scheduleAtFixedRate(
- new TimerTask() {
- @Override
- public void run() {
- fetchRegions();
- }
- },
- // firstt time at midnight
- nextMidnight,
- // once per day
- MILLISECONDS_PER_DAY);
- // register shutdown hook
- this.shutdownHook = new Thread(() -> {
- // stop periodic fetch
- this.updateTimer.cancel();
- });
- Runtime.getRuntime().addShutdownHook(this.shutdownHook);
- }
- /**
- * Stop updating regions.
- */
- public void shutdown() {
- if (this.shutdownHook == null) {
- // not started or already stopped
- return;
- }
- // stop periodic fetch
- this.updateTimer.cancel();
- // remove shutdown hook
- Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
- this.shutdownHook = null;
- }
- /**
- * Get the service.
- * @return geoserveLayersService
- */
- public GeoserveLayersService getGeoserveLayersService() {
- return this.geoserveLayersService;
- }
- /**
- * Set the service.
- * @param service GeoserveLayersService to set
- */
- public void setGeoserveLayersService(final GeoserveLayersService service) {
- this.geoserveLayersService = service;
- }
- /**
- * Get the local regions file.
- * @return localRegions
- */
- public File getLocalRegions() {
- return this.localRegions;
- }
- /**
- * Set the local regions file.
- * @param localRegions file to set
- */
- public void setLocalRegions(final File localRegions) {
- this.localRegions = localRegions;
- }
- /**
- * Get the most recently fetched Regions.
- * @return regions
- */
- public Regions getRegions () {
- return this.regions;
- }
- }