java.lang.Object
org.gcube.informationsystem.resourceregistry.contexts.ContextRepository

public class ContextRepository extends Object
Single data-access layer for Context entities that coordinates the Redis cache and the OrientDB database.

Read strategy: Redis-first with database fallback. Redis is checked first for performance; on a miss the authoritative OrientDB source is queried via ContextManagement.

Write strategy: The database write is delegated to ContextManagement; afterwards the appropriate Redis cache entry is invalidated or updated so that subsequent reads stay consistent.

This class has zero auth logic. The policy decision (which role the caller holds, whether metadata should be included) is always made externally and passed in as plain parameters. The raw readRaw/allRaw variants return unfiltered data for internal callers (e.g. InstanceEnvironmentRegistry, EntityManagement, RelationManagement, JsonQuery). The filtered read(UUID, int, ContextProjection, ContextLifecycle) variant applies the visibility rules supplied by ContextPolicyEnforcementPoint.

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

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Projection settings computed by the caller (typically the PEP).
  • Constructor Summary

    Constructors
    Constructor
    Description
    Public constructor to instantiate ContextRepository.
  • Method Summary

    Modifier and Type
    Method
    Description
    all(boolean polymorphic, ContextRepository.ContextProjection projection, int limit, int offset, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Returns a paginated, filtered list of all contexts as a PageResult.
    allRawUnbounded(boolean polymorphic, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Returns the raw, unfiltered JSON array of every context matching the given lifecycle, with no pagination cap.
    changeState(UUID uuid, String json)
    Applies the validated tracked fields of a Context merge patch and refreshes either the affected cache entry or the complete cached tree after structural changes.
    create(UUID uuid, String json)
    Creates the context identified by uuid with the provided JSON representation.
    create(UUID uuid, String json, boolean preservePassedMetadata)
    Creates a Context, optionally preserving the metadata object already present in the submitted JSON instead of autofilling it from the current caller and clock.
    create(UUID uuid, String json, boolean preservePassedMetadata, boolean compareAdditionalFields)
    Creates a Context, choosing whether the additional fields take part in the idempotency comparison of a repeated creation.
    void
    delete(UUID uuid)
    Logically deletes the Context identified by uuid and invalidates the complete Context cache so the next read rebuilds it at the new authoritative version.
    org.gcube.com.fasterxml.jackson.databind.node.ObjectNode
    filterContextNode(org.gcube.com.fasterxml.jackson.databind.node.ObjectNode ctx, ContextRepository.ContextProjection projection)
    Applies context visibility projection to a raw context JSON object.
    org.gcube.informationsystem.contexts.reference.entities.Context
    Returns the Context identified by the given path (e.g.
    org.gcube.informationsystem.contexts.reference.entities.Context
    getContextByPath(String path, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Returns the Context identified by the given path — its current path or, failing that, one of its previous paths.
    Map<String,org.gcube.informationsystem.contexts.reference.ContextState>
    Resolves the effectiveState of all descendants (recursive children) for a given context, in a single bulk lookup.
    getDescendantUUIDs(UUID contextUUID)
    Resolves all descendants (recursive children) UUIDs for a given context.
    Resolves the UUID of the parent of the given context by reading its raw JSON representation directly.
    getParentUUID(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Resolves a Context's parent strictly within the requested lifecycle topology.
    Returns the set of previous paths for the given context UUID.
    boolean
    Returns the current status of the cache bypass flag.
    static boolean
    Returns whether a top-level field belongs to the Context representation; any other field is an additional field, read and written by the global managers only.
    query(String jsonQuery, ContextRepository.ContextProjection projection, int limit, int offset, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Executes a JSON query against the Context collection, returning a paginated, role-filtered PageResult.
    read(UUID uuid, int depth, ContextRepository.ContextProjection projection)
    Returns the filtered JSON array for the context identified by uuid, applying the visibility rules described by projection.
    read(UUID uuid, int depth, ContextRepository.ContextProjection projection, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Returns a filtered JSON array for a context read, with optional hierarchical context routing for cemetery-capable reads.
    org.gcube.informationsystem.contexts.reference.entities.Context
    Returns the deserialized Context for the given UUID.
    org.gcube.informationsystem.contexts.reference.entities.Context
    readAsContext(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Returns the deserialized Context for the given UUID within the requested lifecycle topology.
    Returns the full context path (e.g.
    readHistory(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Reads the reverse-chronological audit trail of the Context identified by uuid.
    protected String
    readRaw(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Returns the raw canonical JSON for the context identified by uuid, restricted to the given lifecycle scope.
    resolveContextUUIDByPath(String path, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle)
    Resolves the UUID of a context by path, with optional hierarchical context routing.
    void
    setCacheBypass(boolean bypass)
    Sets the cache bypass flag.
    void
    Warms up the entire context cache by loading all live contexts from the database and saving them to Redis.

    Methods inherited from class java.lang.Object

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

    • ContextRepository

      public ContextRepository()
      Public constructor to instantiate ContextRepository.
  • Method Details

    • setCacheBypass

      public void setCacheBypass(boolean bypass)
      Sets the cache bypass flag. Used exclusively during unit/integration testing to verify data symmetry with and without Redis.
      Parameters:
      bypass - true to bypass the cache, false to enable normal Redis-first behavior
    • isCacheBypass

      public boolean isCacheBypass()
      Returns the current status of the cache bypass flag.
      Returns:
      true if cache is bypassed, false otherwise
    • isRepresentationField

      public static boolean isRepresentationField(String field)
      Returns whether a top-level field belongs to the Context representation; any other field is an additional field, read and written by the global managers only.
      Parameters:
      field - the top-level field name
      Returns:
      true if the field is one of the representation
    • warmUpCache

      public void warmUpCache() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Warms up the entire context cache by loading all live contexts from the database and saving them to Redis.
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if database read or caching fails
    • readRaw

      protected String readRaw(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the raw canonical JSON for the context identified by uuid, restricted to the given lifecycle scope. Redis is checked first (unless lifecycle requires a cemetery-aware read); on a miss the database is queried.
      Parameters:
      uuid - the UUID of the context to read
      lifecycle - the lifecycle scope to read within (LIVE, DELETED, or ALL)
      Returns:
      raw JSON string
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the context cannot be found or read
    • read

      public String read(UUID uuid, int depth, ContextRepository.ContextProjection projection) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the filtered JSON array for the context identified by uuid, applying the visibility rules described by projection.
      Parameters:
      uuid - the UUID of the context to read
      depth - requested traversal depth (0, positive integer, or -1 for unlimited)
      projection - projection settings for the response
      Returns:
      filtered JSON array string
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the root context cannot be found or read
    • read

      public String read(UUID uuid, int depth, ContextRepository.ContextProjection projection, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns a filtered JSON array for a context read, with optional hierarchical context routing for cemetery-capable reads.
      Parameters:
      uuid - the UUID of the context to read
      depth - the depth of descendants to expand
      projection - the visibility projection to apply
      lifecycle - the context lifecycle configuration (LIVE, DELETED, ALL, DEFAULT)
      Returns:
      JSON representation of the requested context hierarchy
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the lookup fails
    • readAsContext

      public org.gcube.informationsystem.contexts.reference.entities.Context readAsContext(UUID uuid) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the deserialized Context for the given UUID. Delegates to readRaw(UUID, ContextLifecycle) (Redis-first, database fallback), falling back to an uncached cemetery-aware (ALL) lookup if the LIVE lookup fails — e.g. when walking the ancestor chain of an already-deleted target Context (see ContextPolicyEnforcementPoint#resolveParentUUIDFromExistingContext(UUID)).
      Parameters:
      uuid - the UUID of the context to read
      Returns:
      deserialized Context
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the context cannot be found or deserialized
    • readAsContext

      public org.gcube.informationsystem.contexts.reference.entities.Context readAsContext(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the deserialized Context for the given UUID within the requested lifecycle topology.
      Parameters:
      uuid - the UUID of the Context to read
      lifecycle - the lifecycle topology in which the Context must exist
      Returns:
      the matching Context
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the Context cannot be found or deserialized
    • allRawUnbounded

      public String allRawUnbounded(boolean polymorphic, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the raw, unfiltered JSON array of every context matching the given lifecycle, with no pagination cap. Intended for internal system-wide consumers that must capture the complete persisted state (e.g. System Dump) — never exposed through a role-filtered REST endpoint.
      Parameters:
      polymorphic - whether to include subclasses of Context
      lifecycle - the lifecycle filter to apply
      Returns:
      raw JSON array string containing every matching context
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if contexts cannot be read
    • all

      public PageResult all(boolean polymorphic, ContextRepository.ContextProjection projection, int limit, int offset, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns a paginated, filtered list of all contexts as a PageResult.

      Uses the "peek +1" strategy: requests limit + 1 items from the backing store and drops the extra item from the returned page when present. Visibility filtering via filterContextNode(ObjectNode, ContextProjection) is applied to each entry before building the response JSON.

      Parameters:
      polymorphic - whether to include subclasses of Context
      projection - projection settings for each context entry
      limit - effective page size (>= 1)
      offset - zero-based start index (>= 0)
      lifecycle - the lifecycle filter to apply
      Returns:
      a PageResult with the page JSON and pagination state
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if contexts cannot be read
    • query

      public PageResult query(String jsonQuery, ContextRepository.ContextProjection projection, int limit, int offset, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.queries.InvalidQueryException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Executes a JSON query against the Context collection, returning a paginated, role-filtered PageResult.

      Unlike all(boolean, ContextProjection, int, int, ContextLifecycle), this always queries the database directly (Redis is a plain UUID-keyed cache, not indexed by arbitrary properties, so it cannot serve an arbitrary JSON query). Uses the same "peek +1" pagination strategy: requests limit + 1 items from ContextManagement.query(String) and drops the extra item from the returned page when present. Complete Context results are filtered via filterContextNode(ObjectNode, ContextProjection); flat _emit projection rows retain their query-defined shape after privacy masking.

      Parameters:
      jsonQuery - the JSON query payload describing the Context search criteria
      projection - projection settings for each context entry
      limit - effective page size (>= 1)
      offset - zero-based start index (>= 0)
      lifecycle - the lifecycle filter to apply (selects the environment opened by ContextManagement)
      Returns:
      a PageResult with the page JSON and pagination state
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.queries.InvalidQueryException - if the query is invalid or syntactically incorrect
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if contexts cannot be read
    • readContextPath

      public String readContextPath(UUID uuid) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the full context path (e.g. /gcube/devsec/devVRE) for the given UUID by reading the context and returning its persistent path field.
      Parameters:
      uuid - the UUID of the context
      Returns:
      the path string, or null if not found
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the path cannot be resolved
    • getContextByPath

      public org.gcube.informationsystem.contexts.reference.entities.Context getContextByPath(String path) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the Context identified by the given path (e.g. /gcube/devsec/devVRE).
      Parameters:
      path - the fully-qualified context path
      Returns:
      the matching Context
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if no context matches the path
    • getContextByPath

      public org.gcube.informationsystem.contexts.reference.entities.Context getContextByPath(String path, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the Context identified by the given path — its current path or, failing that, one of its previous paths. Live contexts are resolved from Redis first; a miss, and any lifecycle reaching the cemetery, is read from the database. A live Context and deleted ones may hold the same path: with ContextLifecycle.ALL a live Context, matched by its current or by a previous path, always wins over a deleted one.
      Parameters:
      path - the fully-qualified context path
      lifecycle - the context lifecycle configuration (LIVE, DELETED, ALL, DEFAULT)
      Returns:
      the matching Context
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if no context matches the path
    • resolveContextUUIDByPath

      public UUID resolveContextUUIDByPath(String path, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Resolves the UUID of a context by path, with optional hierarchical context routing.
      Parameters:
      path - the fully-qualified context path
      lifecycle - the context lifecycle configuration (LIVE, DELETED, ALL, DEFAULT)
      Returns:
      the resolved UUID of the context
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the path cannot be resolved to a context
    • getPreviousPaths

      public Set<String> getPreviousPaths(UUID uuid) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Returns the set of previous paths for the given context UUID.
      Parameters:
      uuid - the context UUID
      Returns:
      the set of previous paths, or an empty set if none
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the lookup fails
    • getDescendantUUIDs

      public Set<String> getDescendantUUIDs(UUID contextUUID) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Resolves all descendants (recursive children) UUIDs for a given context. Delegates to the appropriate cache or database layer to preserve distributed coherence.
      Parameters:
      contextUUID - the parent context UUID
      Returns:
      a set of descendant UUID strings
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the lookup fails
    • getDescendantEffectiveStates

      public Map<String,org.gcube.informationsystem.contexts.reference.ContextState> getDescendantEffectiveStates(UUID contextUUID) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Resolves the effectiveState of all descendants (recursive children) for a given context, in a single bulk lookup. Mirrors getDescendantUUIDs(UUID) exactly (same cache-first, DB-fallback strategy) but keeps each descendant's effectiveState instead of discarding it.
      Parameters:
      contextUUID - the parent context UUID
      Returns:
      a map of descendant UUID string to its effectiveState
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the lookup fails
    • create

      public ContextCreationResult create(UUID uuid, String json) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Creates the context identified by uuid with the provided JSON representation.

      To adhere strictly to HTTP PUT idempotency:

      • If the context does not exist, a new context is created and registered.
      • If the context already exists, the incoming representation is compared with the existing one. If their persisted creation fields are identical, the existing representation is returned (no-op). Otherwise, a AlreadyPresentException (409 Conflict) is thrown.
      Parameters:
      uuid - the UUID of the context to create
      json - the JSON representation of the context
      Returns:
      the ContextCreationResult wrapping the resulting context JSON (from the database) and whether a brand new Context was registered
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the operation fails, or if a different representation already exists
    • create

      public ContextCreationResult create(UUID uuid, String json, boolean preservePassedMetadata) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Creates a Context, optionally preserving the metadata object already present in the submitted JSON instead of autofilling it from the current caller and clock. Used exclusively by System Restore to reproduce the original audit trail of a dumped Context.
      Parameters:
      uuid - the UUID of the context to create
      json - the JSON representation of the context
      preservePassedMetadata - true to preserve submitted metadata, false to autofill
      Returns:
      the ContextCreationResult wrapping the resulting context JSON (from the database) and whether a brand new Context was registered
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the operation fails, or if a different representation already exists
    • create

      public ContextCreationResult create(UUID uuid, String json, boolean preservePassedMetadata, boolean compareAdditionalFields) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Creates a Context, choosing whether the additional fields take part in the idempotency comparison of a repeated creation. They do for a caller that reads and writes them; for any other caller the stored ones are ignored by the comparison and left untouched.
      Parameters:
      uuid - the UUID of the context to create
      json - the JSON representation of the context
      preservePassedMetadata - true to preserve submitted metadata, false to autofill
      compareAdditionalFields - whether the additional fields are part of the idempotency comparison
      Returns:
      the ContextCreationResult wrapping the resulting context JSON (from the database) and whether a brand new Context was registered
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the operation fails, or if a different representation already exists
    • readHistory

      public String readHistory(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Reads the reverse-chronological audit trail of the Context identified by uuid.
      Parameters:
      uuid - the UUID of the context
      lifecycle - the context lifecycle configuration (LIVE, DELETED, ALL, DEFAULT)
      Returns:
      JSON array string of history events, newest first
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the operation fails
    • getParentUUID

      public UUID getParentUUID(UUID uuid) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Resolves the UUID of the parent of the given context by reading its raw JSON representation directly. Context.getParent() cannot be used for this: the information-system-model annotates it @JsonGetter-only (serialization side) with an explicit @JsonIgnore on setParent(UUID), so it is never populated by ElementMapper.unmarshal(java.lang.Class<El>, java.io.Reader) regardless of what the source JSON contains.

      Tries the cached LIVE lookup first (the common case, e.g. resolving the InstanceEnvironment parent chain for a still-live Context during a normal delete). Falls back to an uncached cemetery-aware (ALL) lookup only if that fails, so that the same resolution also works when the target Context is already in the cemetery (e.g. purging an already-deleted Context, whose own InstanceEnvironment teardown still needs to resolve its parent chain).

      Parameters:
      uuid - the UUID of the context whose parent to resolve
      Returns:
      the parent's UUID, or null if the context has no parent
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the context cannot be read
    • getParentUUID

      public UUID getParentUUID(UUID uuid, org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Resolves a Context's parent strictly within the requested lifecycle topology.
      Parameters:
      uuid - the UUID of the Context whose parent to resolve
      lifecycle - the lifecycle topology in which the target must exist
      Returns:
      the parent's UUID, or null when the target is a Root Context
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the target cannot be read in that topology
    • changeState

      public String changeState(UUID uuid, String json) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Applies the validated tracked fields of a Context merge patch and refreshes either the affected cache entry or the complete cached tree after structural changes.
      Parameters:
      uuid - the UUID of the context whose state is being changed
      json - the validated JSON merge patch containing only tracked fields
      Returns:
      the resulting context JSON (from the database)
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the operation fails
    • delete

      public void delete(UUID uuid) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException
      Logically deletes the Context identified by uuid and invalidates the complete Context cache so the next read rebuilds it at the new authoritative version.
      Parameters:
      uuid - the UUID of the live Context to move to the cemetery
      Throws:
      org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException - if the operation fails
    • filterContextNode

      public org.gcube.com.fasterxml.jackson.databind.node.ObjectNode filterContextNode(org.gcube.com.fasterxml.jackson.databind.node.ObjectNode ctx, ContextRepository.ContextProjection projection)
      Applies context visibility projection to a raw context JSON object.

      Policy:

      • history is always hidden in standard REST responses.
      • state/effectiveState are always preserved.
      • Non-privileged responses remove additional custom properties.
      • Metadata is removed when not requested, or privacy-masked for non-privileged users when requested.
      Parameters:
      ctx - the context JSON node to filter
      projection - the projection settings to apply
      Returns:
      the filtered context JSON node