001package org.hl7.fhir.validation.cli.services;
002
003import java.util.Set;
004import java.util.UUID;
005import java.util.concurrent.TimeUnit;
006
007import org.apache.commons.collections4.map.PassiveExpiringMap;
008import org.hl7.fhir.validation.ValidationEngine;
009
010/**
011 * SessionCache for storing and retrieving ValidationEngine instances, so callers do not have to re-instantiate a new
012 * instance for each validation request.
013 */
014public class SessionCache {
015
016  protected static final long TIME_TO_LIVE = 60;
017  protected static final TimeUnit TIME_UNIT = TimeUnit.MINUTES;
018
019  private final PassiveExpiringMap<String, ValidationEngine> cachedSessions;
020
021  public SessionCache() {
022    cachedSessions = new PassiveExpiringMap<>(TIME_TO_LIVE, TIME_UNIT);
023  }
024
025  /**
026   * @param sessionLength the constant amount of time an entry is available before it expires. A negative value results
027   *                      in entries that NEVER expire. A zero value results in entries that ALWAYS expire.
028   * @param sessionLengthUnit the unit of time for the timeToLive parameter, must not be null
029   */
030  public SessionCache(long sessionLength, TimeUnit sessionLengthUnit) {
031    cachedSessions = new PassiveExpiringMap<>(sessionLength, sessionLengthUnit);
032  }
033
034  /**
035   * Stores the initialized {@link ValidationEngine} in the cache. Returns the session id that will be associated with
036   * this instance.
037   * @param validationEngine {@link ValidationEngine}
038   * @return The {@link String} id associated with the stored instance.
039   */
040  public String cacheSession(ValidationEngine validationEngine) {
041    String generatedId = generateID();
042    cachedSessions.put(generatedId, validationEngine);
043    return generatedId;
044  }
045
046  /**
047   * Stores the initialized {@link ValidationEngine} in the cache with the passed in id as the key. If a null key is
048   * passed in, a new key is generated and returned.
049   * @param sessionId The {@link String} key to associate with this stored {@link ValidationEngine}
050   * @param validationEngine The {@link ValidationEngine} instance to cache.
051   * @return The {@link String} id that will be associated with the stored {@link ValidationEngine}
052   */
053  public String cacheSession(String sessionId, ValidationEngine validationEngine) {
054    if(sessionId == null) {
055      sessionId = cacheSession(validationEngine);
056    } else {
057      cachedSessions.put(sessionId, validationEngine);
058    }
059    return sessionId;
060  }
061
062  /**
063   * When called, this actively checks the cache for expired entries and removes
064   * them.
065   */
066  public void removeExpiredSessions() {
067    /*
068    The PassiveExpiringMap will remove entries when accessing the mapped value
069    for a key, OR when invoking methods that involve accessing the entire map
070    contents. So, we call keySet below to force removal of all expired entries.
071    * */
072    cachedSessions.keySet();
073  }
074
075  /**
076   * Checks if the passed in {@link String} id exists in the set of stored session id.
077   * @param sessionId The {@link String} id to search for.
078   * @return {@link Boolean#TRUE} if such id exists.
079   */
080  public boolean sessionExists(String sessionId) {
081    return cachedSessions.containsKey(sessionId);
082  }
083
084  /**
085   * Returns the stored {@link ValidationEngine} associated with the passed in session id, if one such instance exists.
086   * @param sessionId The {@link String} session id.
087   * @return The {@link ValidationEngine} associated with the passed in id, or null if none exists.
088   */
089  public ValidationEngine fetchSessionValidatorEngine(String sessionId) {
090    return cachedSessions.get(sessionId);
091  }
092
093  /**
094   * Returns the set of stored session ids.
095   * @return {@link Set} of session ids.
096   */
097  public Set<String> getSessionIds() {
098    return cachedSessions.keySet();
099  }
100
101  /**
102   * Session ids generated internally are UUID {@link String}.
103   * @return A new {@link String} session id.
104   */
105  private String generateID() {
106    return UUID.randomUUID().toString();
107  }
108}