@SuppressWarnings("unchecked")
  private Sysprop fetchFxRatesJSON() {
    Map<String, Object> map = new HashMap<String, Object>();
    Sysprop s = new Sysprop();
    ObjectReader reader = ParaObjectUtils.getJsonReader(Map.class);

    try {
      CloseableHttpClient http = HttpClients.createDefault();
      HttpGet httpGet = new HttpGet(SERVICE_URL);
      HttpResponse res = http.execute(httpGet);
      HttpEntity entity = res.getEntity();

      if (entity != null && Utils.isJsonType(entity.getContentType().getValue())) {
        JsonNode jsonNode = reader.readTree(entity.getContent());
        if (jsonNode != null) {
          JsonNode rates = jsonNode.get("rates");
          if (rates != null) {
            map = reader.treeToValue(rates, Map.class);
            s.setId(FXRATES_KEY);
            s.setProperties(map);
            //						s.addProperty("fetched", Utils.formatDate("dd MM yyyy HH:mm", Locale.UK));
            dao.create(s);
          }
        }
        EntityUtils.consume(entity);
      }
      logger.debug("Fetched rates from OpenExchange for {}.", new Date().toString());
    } catch (Exception e) {
      logger.error("TimerTask failed: {}", e);
    }
    return s;
  }
  @Override
  public Double convertCurrency(Number amount, String from, String to) {
    if (amount == null || StringUtils.isBlank(from) || StringUtils.isBlank(to)) {
      return 0.0;
    }
    Sysprop s = dao.read(FXRATES_KEY);
    if (s == null) {
      s = fetchFxRatesJSON();
    } else if ((Utils.timestamp() - s.getTimestamp()) > REFRESH_AFTER) {
      // lazy refresh fx rates
      Para.asyncExecute(
          new Runnable() {
            public void run() {
              fetchFxRatesJSON();
            }
          });
    }

    double ratio = 1.0;

    if (s.hasProperty(from) && s.hasProperty(to)) {
      Double f = NumberUtils.toDouble(s.getProperty(from).toString(), 1.0);
      Double t = NumberUtils.toDouble(s.getProperty(to).toString(), 1.0);
      ratio = t / f;
    }
    return amount.doubleValue() * ratio;
  }