EditConnection.java [src/edit] Revision: default  Date:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package edit;

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.ReadContext;
import csip.utils.Client;
import csip.Config;
import csip.SessionLogger;
import csip.api.server.ServiceException;
import csip.utils.TTLCache;
import java.io.IOException;
import java.util.logging.Level;
import org.apache.http.client.HttpResponseException;

/**
 * Rest service access to Queries (Ecological Dynamics Interpretive Tool).
 * (https://edit.jornada.nmsu.edu/resources/esd)
 *
 * @author od
 */
public class EditConnection {

  // Queries cache
  static final int EDIT_CACHE_SIZE
      = Config.getInt("edit.cache.size", 64);

  String EDIT_CACHE_TTL
      = Config.getString("edit.cache.ttl", "PT30M");

  // Queries service timeout in sec.
  static final int EDIT_TIMEOUT
      = Config.getInt("edit.con.timeout", 5);

  static final String EDIT_URL
      = Config.getString("edit.url", "https://edit.jornada.nmsu.edu");

  // %s (053C) MLRA id
  // e.g. "/services/downloads/esd/053C/class-list.json"
  static final String EDIT_CATALOGS
      = Config.getString("edit.catalogs", "/catalogs/esd/%s/%s");

  // %s (053C) MLRA id
  // e.g. "/services/downloads/esd/053C/class-list.json"
  static final String EDIT_CLASSLIST
      = Config.getString("edit.classlist", "/services/downloads/esd/%s/class-list.json");

  // %s (053C) MLRA id, %s (R053CY010SD) EcoclassID
  // e.g. "/services/models/esd/053C/R053CY010SD/states.json"
  static final String EDIT_STATES_TRANS
      = Config.getString("edit.statestrans", "/services/models/esd/%s/%s/states.json");

  // %s (053C) MLRA id, %s (R053CY010SD) EcoclassID
  // e.g. "/services/plant-community-tables/esd/053C/R053CY010SD/1/1/1/annual-production.json"
  static final String EDIT_PCANNUALPROD
      = Config.getString("edit.pcannualprod", "/services/models/esd/%s/%s/plant-community-tables.json?table=annual%%20production");

  // %s (053C) MLRA id, %s (R053CY010SD) EcoclassID
//      "/services/models/esd/%s/%s/plant-community-tables.json?table=annual%%20production");
  static final String EDIT_PLANTCOMPOSITION
      = Config.getString("edit.plantcomposition", "/services/plant-community-tables/esd/%s/%s/1/1/1/rangeland-plant-composition.json");

  static final String EDIT_SYNONYMS
      = Config.getString("edit.synonyms", "/services/downloads/esd/class-synonym-list.json");

  static final Configuration CONF = Configuration.defaultConfiguration()
      .addOptions(Option.SUPPRESS_EXCEPTIONS);

  // <url> -> <response>
  private static final TTLCache<String, ReadContext> cache = new TTLCache<>()
      .withSize(EDIT_CACHE_SIZE);
  
  SessionLogger log;


  public EditConnection(SessionLogger log) {
    this.log = log;
  }


  public EditConnection() {
    this(null);
  }


  synchronized ReadContext callEdit(String url) throws Exception {
    ReadContext resp = cache.get(url);
    if (resp != null) {
      if (log != null && log.isLoggable(Level.INFO))
        log.info("GET from Cache: " + url + ": " + resp);

      return resp;
    }
    try ( Client c = new Client(EDIT_TIMEOUT)) {
      try {
        String r = c.doGET(url);
        String err = JsonPath.using(CONF).parse(r).read("$.error.message");
        if (err != null)
          throw new Exception("Error calling '" + url + "': " + r);

        resp = JsonPath.parse(r);
        long untilEoD = TTLCache.untilEndOfDay();
        cache.put(url, resp, EDIT_CACHE_TTL, untilEoD);
        if (log != null && log.isLoggable(Level.INFO))
          log.info("GET from Edit: " + url + ": " + resp);

        return resp;
      } catch (IOException E) {
        if (E.getCause() instanceof HttpResponseException) {
          HttpResponseException E1 = (HttpResponseException) E.getCause();
          if (E1.getStatusCode() == 404) {
            if (log != null && log.isLoggable(Level.WARNING))
              log.warning("Got a 404 for: " + url + " from EDIT. Proceeding with empty data: '{}'.");

            return JsonPath.using(CONF).parse("{}");
          }
          throw new ServiceException("http error " + E1.getStatusCode() + " for " + url);
        }
        throw E;
      }
    }
  }


  public ReadContext fetchEcoClassList(String ecId) throws Exception {
    return callEdit(String.format(EDIT_URL + EDIT_CLASSLIST, Utils.getMLRA(ecId)));
  }


  public ReadContext fetchEcoSystemStates(String ecId) throws Exception {
    return callEdit(String.format(EDIT_URL + EDIT_STATES_TRANS, Utils.getMLRA(ecId), ecId));
  }


  public ReadContext fetchAnnualProd(String ecId) throws Exception {
    return callEdit(String.format(EDIT_URL + EDIT_PCANNUALPROD, Utils.getMLRA(ecId), ecId));
  }


  public ReadContext fetchPlantComposition(String ecId) throws Exception {
    return callEdit(String.format(EDIT_URL + EDIT_PLANTCOMPOSITION, Utils.getMLRA(ecId), ecId));
  }


  public ReadContext fetchAllSynonyms() throws Exception {
    return callEdit(EDIT_URL + EDIT_SYNONYMS);
  }

}