java.lang.Object
org.gcube.informationsystem.resourceregistry.contexts.redis.RedisContextCache

public class RedisContextCache extends Object
Redis-backed context cache for stateless multi-instance deployments.

Stores one canonical JSON representation per context (including the computed Context.PATH field) together with structural index keys that enable UUID→path and path→UUID lookups and tree reconstruction without a local JVM cache.

All operations degrade gracefully: if Redis is unavailable every method either returns null / an empty collection or falls through to the supplied fallback, allowing callers to read directly from the database.

Key TTL: Equal to ContextCache.expiringTimeout (default 6 h). The entire context key space is invalidated on every write via invalidateAll() so stale data never persists longer than one TTL period even if an explicit invalidation is missed.

Every complete snapshot also carries a format-qualified durable Context version from OrientDB. Reads reject a missing, differently formatted, or stale version, so incompatible data or data retained by Redis across an outage cannot become visible after the service format or database state changes.

Author:
Luca Frosini (ISTI - CNR)
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static interface 
    Provider interface for warm up tasks.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    addNewContextToCache(UUID uuid, String name, UUID parentUuid)
    Adds a newly-created context to the Redis cache without a full invalidation.
    org.gcube.informationsystem.dag.Dag<org.gcube.informationsystem.contexts.reference.entities.Context>
    Builds a Dag-backed tree of contexts from the data currently held in Redis (single-parent only -- setAllowMultipleInheritance(false) -- since a context always has exactly one parent).
    List<org.gcube.informationsystem.contexts.reference.entities.Context>
    Returns the list of unmarshalled Context objects from Redis.
    Returns the raw JSON strings for all contexts in insertion order.
    Returns the singleton instance of RedisContextCache.
    Convenience overload that parses the string representation of the UUID.
    Returns the computed path string for the given context UUID (e.g.
    Returns the raw canonical JSON of the live context the given path resolves to: the one whose current path it is or, failing that, the one keeping it among its previous paths — a current path always wins.
    Convenience overload that parses the string representation of the UUID.
    Returns the raw canonical JSON string for the given context UUID as stored in Redis (includes the injected path field).
    Returns the UUID of the context identified by the given path (e.g.
    Returns the UUID of the context that keeps the given path among its previous paths.
    void
    Performs a targeted invalidation of all Redis keys for the given context UUID.
    void
    Deletes all ctx:* keys from Redis using a SCAN loop.
    boolean
    Returns true when Redis is reachable and the connection is open.
    boolean
    Returns true if the cache list is empty or unavailable.
    static void
    Registers a custom RedisContextCache.CacheWarmUpProvider for this cache.
    void
    removeChildFromParentJson(UUID parentUuid, UUID childUuid)
    Removes a deleted child context from the parent's cached JSON children array.
    void
    saveAll(List<org.gcube.informationsystem.contexts.reference.entities.Context> contexts)
    Persists the complete list of contexts to Redis.
    void
    saveAll(List<org.gcube.informationsystem.contexts.reference.entities.Context> contexts, long contextVersion)
    Convenience overload for callers that only have Context POJOs at hand (e.g.
    void
    saveAll(org.gcube.com.fasterxml.jackson.databind.node.ArrayNode contexts, long contextVersion)
    Persists a complete Context snapshot given as raw JSON object nodes, and publishes its authoritative version last.
    void
    updateContextJson(UUID uuid, String contextJsonWithoutPath)
    Updates only the canonical JSON stored at ctx:uuid:{uuid}, preserving the existing path that was injected at write time.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • registerWarmUpProvider

      public static void registerWarmUpProvider(RedisContextCache.CacheWarmUpProvider provider)
      Registers a custom RedisContextCache.CacheWarmUpProvider for this cache.
      Parameters:
      provider - the custom provider to register
    • isEmpty

      public boolean isEmpty()
      Returns true if the cache list is empty or unavailable.
      Returns:
      true if the cache is empty or Redis is down, false otherwise
    • getInstance

      public static RedisContextCache getInstance()
      Returns the singleton instance of RedisContextCache.
      Returns:
      the singleton instance
    • isAvailable

      public boolean isAvailable()
      Returns true when Redis is reachable and the connection is open.
      Returns:
      true if Redis cache is available, false otherwise
    • saveAll

      public void saveAll(List<org.gcube.informationsystem.contexts.reference.entities.Context> contexts)
      Persists the complete list of contexts to Redis. For each context this method:
      1. Serialises the context to JSON via ElementMapper.
      2. Reads the already-available Context.PATH field from the JSON payload and validates it before writing index keys.
      3. Writes all required index keys (uuid, path, fname, parent, children, and the shared list ZSET).

      All keys are given a TTL equal to ContextCache.expiringTimeout.

      If Redis is unavailable this method is a no-op.

      Parameters:
      contexts - ordered list of contexts as returned by ContextManagement.allFromDatabase()
    • saveAll

      public void saveAll(List<org.gcube.informationsystem.contexts.reference.entities.Context> contexts, long contextVersion)
      Convenience overload for callers that only have Context POJOs at hand (e.g. hand-built test fixtures). Marshals each one to JSON and delegates to the canonical saveAll(ArrayNode, long).

      Production code populating the cache from a real database read should prefer saveAll(ArrayNode, long) directly with the already-serialized payload (see ContextRepository#warmUpCache()), rather than round-tripping through this POJO overload: unmarshalling into Context/ContextImpl and marshalling back widens the parent/children summaries to every model-level field (e.g. history), since the model's getParent()/getChildren() only guard against infinite recursion, not against re-exposing fields the original serializer deliberately omitted from those nested summaries.

      Parameters:
      contexts - the complete Context snapshot
      contextVersion - the authoritative version represented by the snapshot
    • saveAll

      public void saveAll(org.gcube.com.fasterxml.jackson.databind.node.ArrayNode contexts, long contextVersion)
      Persists a complete Context snapshot given as raw JSON object nodes, and publishes its authoritative version last. This is the canonical write path: each context's JSON node is stored exactly as its serializer produced it (e.g. ContextManagement's allow-listed parent/children summaries), with no JSON→POJO→JSON round trip that could reintroduce a field the summary deliberately omits.
      Parameters:
      contexts - the complete Context snapshot, one JSON object node per Context
      contextVersion - the authoritative version represented by the snapshot
    • getAllRaw

      public List<String> getAllRaw()
      Returns the raw JSON strings for all contexts in insertion order. Each JSON string includes the path field injected at write time.
      Returns:
      ordered list of raw JSON strings, or null if Redis is unavailable
    • getAll

      public List<org.gcube.informationsystem.contexts.reference.entities.Context> getAll() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the list of unmarshalled Context objects from Redis.
      Returns:
      ordered list of Context objects, or null if Redis is unavailable
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - on deserialization errors
    • getRawByUUID

      public String getRawByUUID(UUID uuid)
      Returns the raw canonical JSON string for the given context UUID as stored in Redis (includes the injected path field).
      Parameters:
      uuid - the UUID of the context to read
      Returns:
      the raw JSON string, or null if not present or Redis is unavailable
    • getRawByUUID

      public String getRawByUUID(String uuidStr)
      Convenience overload that parses the string representation of the UUID.
      Parameters:
      uuidStr - the UUID string
      Returns:
      the raw JSON string, or null if not present or Redis is unavailable
    • getPathByUUID

      public String getPathByUUID(UUID uuid)
      Returns the computed path string for the given context UUID (e.g. /gcube/devsec/devVRE).
      Parameters:
      uuid - the UUID of the context
      Returns:
      the path string, or null if not found or Redis is unavailable
    • getPathByUUID

      public String getPathByUUID(String uuidStr)
      Convenience overload that parses the string representation of the UUID.
      Parameters:
      uuidStr - the UUID string
      Returns:
      the path string, or null if not found or Redis is unavailable
    • getUUIDByPath

      public UUID getUUIDByPath(String path)
      Returns the UUID of the context identified by the given path (e.g. /gcube/devsec/devVRE).
      Parameters:
      path - the fully-qualified context path
      Returns:
      the resolved UUID, or null if not found or Redis is unavailable
    • getRawByPath

      public String getRawByPath(String path)
      Returns the raw canonical JSON of the live context the given path resolves to: the one whose current path it is or, failing that, the one keeping it among its previous paths — a current path always wins. The cache is validated once for the whole lookup.
      Parameters:
      path - the path to resolve
      Returns:
      the raw JSON string, or null if not found or the cache must not be trusted
    • getUUIDByPreviousPath

      public UUID getUUIDByPreviousPath(String path)
      Returns the UUID of the context that keeps the given path among its previous paths. Callers look the current path up first (getUUIDByPath(String)): a current path always wins over a previous one.
      Parameters:
      path - the previous path
      Returns:
      the resolved UUID, or null if not found or Redis is unavailable
    • buildContextsTree

      public org.gcube.informationsystem.dag.Dag<org.gcube.informationsystem.contexts.reference.entities.Context> buildContextsTree() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Builds a Dag-backed tree of contexts from the data currently held in Redis (single-parent only -- setAllowMultipleInheritance(false) -- since a context always has exactly one parent). Constructed on-demand each time this method is called; no JVM-level cache is maintained.
      Returns:
      the contexts tree, or null if Redis is unavailable or empty
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - on deserialization errors
    • updateContextJson

      public void updateContextJson(UUID uuid, String contextJsonWithoutPath)
      Updates only the canonical JSON stored at ctx:uuid:{uuid}, preserving the existing path that was injected at write time.

      Use this for operations that change a context's content (e.g. state or metadata) but do NOT affect the tree structure or path of any context.

      If the context's path is not found in Redis (e.g. after a restart before the first warm-up), falls back to invalidateAll().

      Parameters:
      uuid - the UUID of the context whose JSON should be refreshed
      contextJsonWithoutPath - serialized context JSON (without Context.PATH injected)
    • invalidateAll

      public void invalidateAll()
      Deletes all ctx:* keys from Redis using a SCAN loop. Called after every context write (create / update / delete / changeState) to ensure subsequent reads reflect the latest DB state.
    • invalidate

      public void invalidate(UUID uuid)
      Performs a targeted invalidation of all Redis keys for the given context UUID. Also removes the context from its parent's children set and from the ZSET.
      Parameters:
      uuid - the UUID of the context to invalidate
    • addNewContextToCache

      public void addNewContextToCache(UUID uuid, String name, UUID parentUuid)
      Adds a newly-created context to the Redis cache without a full invalidation.

      Writes all lookup keys for the new context (ctx:path, ctx:fname, ctx:parent, membership in ctx:children of its parent, and entry in ctx:list). The parent's canonical JSON blob (ctx:uuid:{parentUuid}) is deleted so that the next readAsString(parentUuid) falls back to the database and reflects the new child.

      The new context's own JSON blob (ctx:uuid:{uuid}) is intentionally not written here. getAllRaw() and getAll() detect the missing blob and trigger a full cache reload on the first all() call after the creation, so the response is always consistent.

      If the parent's path is not in the cache (cold cache), this method falls back to a full invalidateAll() so the cache remains coherent.

      Parameters:
      uuid - UUID of the newly-created context
      name - simple name of the new context (e.g. "D4Science")
      parentUuid - UUID of its parent context, or null for a root context
    • removeChildFromParentJson

      public void removeChildFromParentJson(UUID parentUuid, UUID childUuid)
      Removes a deleted child context from the parent's cached JSON children array. Call this after invalidate(UUID) when deleting a leaf context. The parent's JSON is updated in-place inside Redis; no database read is needed.
      Parameters:
      parentUuid - UUID of the parent context whose JSON must be patched
      childUuid - UUID of the child context that was just deleted