/**
   * Returns true if key is valid. Uses cache of keys so doesn't have to access database each time.
   * If key not in cache then will reread keys from database in case it was just added. But won't do
   * so more than every few seconds since more frequent access could allow an app with a bad key to
   * cause the db to be queried to often putting an unneeded burden on the db.
   *
   * <p>Synchronized because can have simultaneous access and using a cache.
   *
   * @param key The key to investigate
   * @return True if key is valid
   */
  public synchronized boolean isKeyValid(String key) {
    try {
      // If key is already in cache return true
      if (apiKeyCache.get(key) != null) return true;

      // Want to make sure a user doesn't overwhelm the system by
      // repeatedly trying to use an invalid key. So if the cache was
      // just updated a few x seconds ago then don't update it again
      // right now. Simply return false.
      if (System.currentTimeMillis()
          < lastTimeKeysReadIntoCache + lastTimeKeysReadLimitSec.getValue() * Time.MS_PER_SEC)
        return false;
      lastTimeKeysReadIntoCache = System.currentTimeMillis();

      // Key wasn't in cache so update the cache in case it was added
      apiKeyCache.clear();
      for (ApiKey apiKey : getApiKeys()) {
        apiKeyCache.put(apiKey.getKey(), apiKey);
      }

      return apiKeyCache.get(key) != null;
    } catch (Exception e) {
      logger.error("Problem checking key \"{}\" to see if valid.", key, e);
      return false;
    }
  }
  /**
   * Generates the new ApiKey and stores it in the db.
   *
   * @param applicationName
   * @param applicationUrl
   * @param email
   * @param phone
   * @param description
   * @return The new ApiKey or null if there was a problem such as the key
   * @throws IllegalArgumentException
   * @throws HibernateException
   */
  public ApiKey generateApiKey(
      String applicationName, String applicationUrl, String email, String phone, String description)
      throws IllegalArgumentException, HibernateException {
    // Make sure don't already have key for this application name
    List<ApiKey> currentApiKeys = getApiKeys();
    for (ApiKey currentApiKey : currentApiKeys) {
      if (currentApiKey.getApplicationName().equals(applicationName)) {
        // Already have a key for that application so return null
        logger.error("Already have key for application name \"{}\"", applicationName);
        throw new IllegalArgumentException(
            "Already have key for " + "application name \"" + applicationName + "\"");
      }
    }

    // Determine what the key should be
    String key = generateKey(applicationName);

    // Create the new ApiKey
    ApiKey newApiKey = new ApiKey(applicationName, key, applicationUrl, email, phone, description);

    // Store new ApiKey in database
    newApiKey.storeApiKey(dbName);

    // Return the new key
    return newApiKey;
  }
  /**
   * Deletes the ApiKey from the database
   *
   * @param key
   */
  public void deleteKey(String key) {
    List<ApiKey> apiKeys = getApiKeys();
    for (ApiKey apiKey : apiKeys) {
      if (apiKey.getKey().equals(key)) {
        // Found the right key. Delete from database
        apiKey.deleteApiKey(dbName);

        // Also delete key from the cache
        apiKeyCache.remove(key);

        // Found the key so done here
        return;
      }
    }

    // That key not found in database so report error
    logger.error("Could not delete key {} because it was not in database", key);
  }
 /**
  * Gets the API keys from the database. Gets the session for db access. The session is specified
  * by parameters in CoreConfig including CoreConfig.getAgencyId() for the name of the database
  * (such as "web") and CoreConfig.getDbHost(), CoreConfig.getDbUserName(), and
  * CoreConfig.getDbPassword(). The db host, user name, and password can also be set in the
  * hibernate.cfg.xml file if the parameter transitime.hibernate.configFile in the CoreConfig is
  * set.
  *
  * @return
  */
 public List<ApiKey> getApiKeys() {
   Session session = HibernateUtils.getSession(DbSetupConfig.getDbName());
   return ApiKey.getApiKeys(session);
 }