Class ClarityAPICache

java.lang.Object
org.cruk.clarity.api.cache.ClarityAPICache

public class ClarityAPICache extends Object
A cache optionally deployed around a ClarityAPI bean as an aspect. Looks to see what objects have already been fetched or created and, if they are in the cache, doesn't go back to the server for them. Creates, updates and deletes are passed through immediately.

The "stateful" Artifact class produces some problems. There is more than one way these could be handled, where an Artifact's state (specifically its QC flag) will be different for different number of its "state" URI parameter. This implementation uses a "latest available" strategy, where if the state requested for an Artifact is earlier than the one in the cache, the cached version is returned. If a later state is requested, it is fetched and replaces the one in the cache. This strategy may not be suitable for all cases and future refinements will allow different strategies to be selected.

  • Field Details

    • logger

      protected Logger logger
      Logger.
    • api

      protected ClarityAPI api
      The API this aspect will call through to.
    • apiCacheControl

      protected ClarityAPIInternal apiCacheControl
      The API again, but via its internal interface.
    • cacheManager

      protected CacheManager cacheManager
      The cache manager.
    • latestVersionsResetAspect

      protected LatestVersionsResetAspect latestVersionsResetAspect
      The aspect that resets API version behaviour.
    • behaviour

      protected CacheStatefulBehaviour behaviour
      The behaviour for dealing with stateful entities.
  • Constructor Details

    • ClarityAPICache

      public ClarityAPICache()
      Empty constructor.
  • Method Details

    • setClarityAPI

      @Autowired @Qualifier("clarityAPI") public void setClarityAPI(ClarityAPI api)
      Sets the API being used.
      Parameters:
      api - The ClarityAPI bean.
    • setInternalClarityAPI

      @Autowired @Qualifier("clarityAPI") public void setInternalClarityAPI(ClarityAPIInternal internalApi)
      Set the internal interface access to the API.
      Parameters:
      internalApi - The API bean, but through its internal interface.
    • setCacheManager

      @Autowired @Qualifier("clarityCacheManager") public void setCacheManager(CacheManager cacheManager)
      Set the Ehcache cache manager.
      Parameters:
      cacheManager - The cache manager.
    • setLatestVersionsResetAspect

      @Autowired public void setLatestVersionsResetAspect(LatestVersionsResetAspect latestVersionsResetAspect)
      Set a reference to the aspect that resets the API's behaviour around stateful entities.
      Parameters:
      latestVersionsResetAspect - The version resetting aspect.
      See Also:
    • setStatefulBehaviour

      public void setStatefulBehaviour(CacheStatefulBehaviour behaviour)
      Set the behaviour for dealing with stateful objects. Note that changing this behaviour during operation clears the cache.
      Parameters:
      behaviour - The desired behaviour.
      Since:
      2.22
    • clear

      public void clear()
      Clears the cache of all cached entities.
    • cancelStatefulOverride

      public void cancelStatefulOverride(JoinPoint jp)
      Makes sure the effects of ClarityAPI.overrideStateful() is reset after a call. The API itself has its own wrapper to clear this after a call, but if the cache intercepts the call and doesn't call through to the API (because the objects are already in the cache) we need to make sure the behaviour reverts to respecting the state version anyway.

      If one considers this, it might not be necessary because when the API is instructed to fetch the most recent, the call will always pass through the cache. This is a belt and braces method.

      Parameters:
      jp - The join point.
      See Also:
    • retrieve

      public Object retrieve(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.retrieve methods. Fetches the object requested, either from the cache or from the API.
      Parameters:
      pjp - The join point object.
      Returns:
      The object retrieved.
      Throws:
      Throwable - if there is an error.
      See Also:
    • loadById

      public Object loadById(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.load methods taking an id and a class. Fetches the object requested, either from the cache or from the API.
      Parameters:
      pjp - The join point object.
      Returns:
      The object retrieved.
      Throws:
      Throwable - if there is an error.
      See Also:
    • loadByLink

      public Object loadByLink(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.load methods taking a LimsLink. Fetches the object requested, either from the cache or from the API.
      Parameters:
      pjp - The join point object.
      Returns:
      The object retrieved.
      Throws:
      Throwable - if there is an error.
      See Also:
    • getFromWrapper

      protected <E extends Locatable> E getFromWrapper(org.cruk.clarity.api.cache.CacheElementWrapper wrapper)
      Get the object from its cache wrapper. In its own method to suppress unchecked warnings.
      Type Parameters:
      E - The type of object held in the cache element.
      Parameters:
      wrapper - The cache Element.
      Returns:
      The object in the cache element.
    • loadOrRetrieve

      protected Object loadOrRetrieve(ProceedingJoinPoint pjp, String uri, Class<?> entityClass) throws Throwable
      Fetch an object from the cache or, if it's not yet been seen, from the API and store the result in the cache for future use.

      Special consideration has to be made for objects that have a "state" parameter to their URIs. See the class description for more details.

      Parameters:
      pjp - The join point object.
      uri - The URI of the object to fetch.
      entityClass - The type of object to fetch.
      Returns:
      The object retrieved.
      Throws:
      Throwable - if there is an error.
    • loadAll

      public <E extends Locatable> List<E> loadAll(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.loadAll method. Examines the cache for objects already loaded and only fetches those that are not already seen (or, for stateful objects, those whose requested state is later than that in the cache).
      Type Parameters:
      E - The type of LIMS entity referred to.
      Parameters:
      pjp - The join point object.
      Returns:
      The list of entities retrieved.
      Throws:
      Throwable - if there is an error.
      See Also:
    • reload

      public void reload(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.reload method. Force a reload from the API of an object by fetching again and updating its cache entry.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • create

      public void create(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.create method. Create the object through the API and, if it can be cached, record it in the cache.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • createAll

      public void createAll(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.createAll method. Create the objects through the API and, if they can be cached, record them in the cache.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • update

      public void update(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.update method. Update the object through the API and, if it can be cached, update the record in the cache.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • updateAll

      public void updateAll(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.updateAll method. Update the objects through the API and, if they can be cached, update their records in the cache.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • delete

      public void delete(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.delete method. Delete the object through the API and, if it can be cached, remove it from the cache.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • deleteAll

      public void deleteAll(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.deleteAll method. Delete the objects through the API and, if they can be cached, remove their records from the cache.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • runSomething

      public Locatable runSomething(ProceedingJoinPoint pjp) throws Throwable
      Join point for the methods that take an object in to perform an operation and return an object as a result (not necessarily object passed in). For example, ClarityAPI.executeProcess and ClarityAPI.beginProcessStep.

      Run the operation and store the resulting object in the cache (if cacheable).

      Parameters:
      pjp - The join point object.
      Returns:
      The object created by the operation.
      Throws:
      Throwable - if there is an error.
      See Also:
    • uploadFile

      public ClarityFile uploadFile(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.uploadFile method. Call through to the API to do the work and store the resulting ClarityFile object in the cache.
      Parameters:
      pjp - The join point object.
      Returns:
      The file record in the Clarity LIMS.
      Throws:
      Throwable - if there is an error.
      See Also:
    • deleteAndRemoveFile

      public void deleteAndRemoveFile(ProceedingJoinPoint pjp) throws Throwable
      Join point for the ClarityAPI.deleteAndRemoveFile method. Call through to the API to do the work and remove the ClarityFile object from the cache.
      Parameters:
      pjp - The join point object.
      Throws:
      Throwable - if there is an error.
      See Also:
    • toUriString

      protected String toUriString(Class<?> entityClass, String... ids)
      Assemble a URI for an object's id and class.

      Uses the reference to the ClarityAPI to obtain the current server address.

      This method essentially replicates ClarityAPIImpl.limsIdToUri(String, Class) but is looser on the class object it accepts for entityClass and doesn't create the URI object for the identifier.

      Parameters:
      entityClass - The class of the entity.
      ids - The LIMS id(s) of the entity.
      Returns:
      A URI in string form for the entity.
    • isCacheable

      public boolean isCacheable(Collection<?> entities)
      Test whether a collection of entities is cacheable. Finds the first non-null item in the list an tests its ClarityEntity annotation. Assumes the collection is homogeneous in its content.
      Parameters:
      entities - The collection to test.
      Returns:
      true if the first non-null item is the list is cacheable, false otherwise (including for a null or empty list).
      See Also:
    • isCacheable

      public boolean isCacheable(Object thing)
      Test whether an entity is cacheable. If the object given is not null, examine its ClarityEntity annotation for its "cacheable" attribute and return that value.
      Parameters:
      thing - The object to test.
      Returns:
      true if thing is not null, is annotated with the ClarityEntity annotation, and that annotation has its "cacheable" attribute set to true; false otherwise.
      See Also:
    • isCacheable

      public boolean isCacheable(Class<?> entityClass)
      Test whether entities of a class are cacheable. Tests whether the given class is annotated with the ClarityEntity annotation and, if so, its "cacheable" attribute is set.
      Parameters:
      entityClass - The class to test.
      Returns:
      true if entityClass is annotated with the ClarityEntity annotation, and that annotation has its "cacheable" attribute set to true; false otherwise.
      See Also:
    • isStateful

      public boolean isStateful(Collection<?> entities)
      Test whether a collection of entities is stateful. Finds the first non-null item in the list an tests its ClarityEntity annotation. Assumes the collection is homogeneous in its content.
      Parameters:
      entities - The collection to test.
      Returns:
      true if the first non-null item is the list is stateful, false otherwise (including for a null or empty list).
      See Also:
    • isStateful

      public boolean isStateful(Object thing)
      Test whether an entity is stateful. If the object given is not null, examine its ClarityEntity annotation for its "stateful" attribute and return that value.
      Parameters:
      thing - The object to test.
      Returns:
      true if thing is not null, is annotated with the ClarityEntity annotation, and that annotation has its "stateful" attribute set to true; false otherwise.
      See Also:
    • isStateful

      public boolean isStateful(Class<?> entityClass)
      Test whether entities of a class are stateful. Tests whether the given class is annotated with the ClarityEntity annotation and, if so, its "stateful" attribute is set.
      Parameters:
      entityClass - The class to test.
      Returns:
      true if entityClass is annotated with the ClarityEntity annotation, and that annotation has its "stateful" attribute set to true; false otherwise.
      See Also:
    • versionFromLocatable

      public long versionFromLocatable(Locatable thing)
      Extract the state value from the given object's URI, if such an entity can have a state value.
      Parameters:
      thing - The entity to extract the state for.
      Returns:
      The state number, or NO_STATE_VALUE if either the object is not a stateful object or there is no state information in the object's URI.
    • versionFromUri

      public long versionFromUri(URI uri)
      Extract the state value from a URI.
      Parameters:
      uri - The URI to dissect for a state value.
      Returns:
      The state number, or NO_STATE_VALUE if there is no state information in the URI.
    • versionFromUri

      public long versionFromUri(String uri)
      Extract the state value from a string version of a URI.
      Parameters:
      uri - The URI string to dissect for a state value.
      Returns:
      The state number, or NO_STATE_VALUE if there is no state information in the URI.
    • keyFromLocatable

      public String keyFromLocatable(Locatable thing)
      Extract the cache key value from the given object's URI. This is the full path of the entity, less any query string.
      Parameters:
      thing - The entity to extract the key for.
      Returns:
      The cache key value.
    • keyFromUri

      public String keyFromUri(URI uri)
      Extract the cache key value from the given URI. This is the full path of the entity, less any query string.
      Parameters:
      uri - The URI to extract the key from.
      Returns:
      The cache key value.
    • keyFromUri

      public String keyFromUri(String uri)
      Extract the cache key value from the given URI string. This is the full path of the entity, less any query string.
      Parameters:
      uri - The URI string to extract the key from.
      Returns:
      The cache key value.
    • getBehaviourForCall

      protected CacheStatefulBehaviour getBehaviourForCall()
      Get the type of stateful behaviour to use for the current call. If there is an override that requires the exact version, behave on this call as if the cache were in EXACT operation (for the fetch, not the store). Otherwise return the configured behaviour.
      Returns:
      The cache behaviour to use this time.
    • isFetchLatestVersions

      protected boolean isFetchLatestVersions()
      Convenience method to test whether the latest version of stateful entities is required.
      Returns:
      True if there is an override wanting the latest version set on the API, false if not.