Class ContextManagement
Context entities.
Owns the low-level graph representation of the context hierarchy (the ChildOf
child-to-parent edge), the persisted derived fields (Context.PATH and
Context.EFFECTIVE_STATE, recomputed on creation, rename, and reparent), the
cemetery move-on-delete mechanics (swapping record-level-security roles between
LiveContextEnvironment and CemeteryContextEnvironment instead of a hard
delete), and the append-only audit history recorded on every state-changing operation.
This class has zero auth logic: role/visibility policy is owned by
ContextPolicyEnforcementPoint,
and Redis caching/fallback orchestration is owned by
ContextRepository.
- Author:
- Luca Frosini (ISTI - CNR)
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycleThe lifecycle filter configuration used to resolve the database environment.protected StringThe name of the Context being managed.protected booleanWhether the last JSON query returned an_emitprojection.protected booleanWhether the delete operation should permanently purge the context instead of moving it to the cemetery.Fields inherited from class org.gcube.informationsystem.resourceregistry.persistence.orientdb.base.EntityElementManagement
IN_PREFIX, OUT_PREFIX, relationManagementsFields inherited from class org.gcube.informationsystem.resourceregistry.persistence.orientdb.base.ElementManagement
accessType, affectedInstances, AT, cachedType, complete, DELETED, DOLLAR, dryRun, element, elementClass, entryPoint, ignoredFields, ignoreKeys, ignoreStartWithKeys, jsonNode, limit, maskMetadata, metadataPolicy, oClass, oDatabaseDocument, offset, operation, polymorphic, preservePassedMetadata, reload, sanityCheckDeferred, self, typeName, UNDERSCORE, updateMode, uuid, workingEnvironment -
Constructor Summary
ConstructorsConstructorDescriptionCreates a new, uninitializedContextManagementinstance.ContextManagement(org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle, com.orientechnologies.orient.core.db.document.ODatabaseDocument oDatabaseDocument) Creates a newContextManagementinstance bound to the specified OrientDB database. -
Method Summary
Modifier and TypeMethodDescriptionApplies only tracked local-state, name, or parent changes and recursively recomputes the effective states and paths of all descendants.protected voidcheckContext(ContextManagement parentContext) Validates that the context is topologically valid and does not violate uniqueness constraints: no sibling with the same name underparentContextand, for a parentless Context, no other live Root, since the Context topology is either empty or a single-root tree.protected voidcheckStateChange(org.gcube.informationsystem.contexts.reference.ContextState newContextstate) Validates whether a context's state transition is legally permissible.create()Initializes the Context version counter before the creation transaction starts.protected org.gcube.com.fasterxml.jackson.databind.JsonNodeAbstract method to create the complete JSON node representation of the element.voiddelete()Deletes the Context from the database (logical delete, moves to cemetery).protected voiddelete(boolean purge) Deletes or purges the Context from the database using a privileged administrative session.Returns the map of instances affected by operations on this context.org.gcube.informationsystem.contexts.reference.entities.ContextgetContextByPath(String path) Returns theContextidentified bypath.com.orientechnologies.orient.core.record.OVertexReturns the OrientDB vertex for the configured UUID, restricted to the currentlifecyclescope.org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycleRetrieves the current context lifecycle configuration.getName()Returns the name of the Context.static StringgetPathFromVertex(com.orientechnologies.orient.core.record.OVertex vertex) Reads a Context's persisted path directly off its OrientDB vertex, falling back to the legacyfullPathproperty name for a not-yet-migrated record.getPreviousPathsFromVertex(com.orientechnologies.orient.core.record.OVertex vertex) Reads a Context's persisted set of previous paths directly off its OrientDB vertex.protected org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextAlreadyPresentExceptiongetSpecificAlreadyPresentException(String message) Converts a generic AlreadyPresentException into a ContextAlreadyPresentException.protected org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundExceptiongetSpecificNotFoundException(org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException e) Converts a generic NotFoundException into a ContextNotFoundException.protected EnvironmentReturns the active LiveContextEnvironment working environment.booleanReports whether the lastquery(String)call returned an_emitprojection rather than complete Context objects.protected voidComputes and persists theContext.PATHandContext.EFFECTIVE_STATEof this context into the vertex.voidpurge()Permanently purges the Context from the database entirely (bypassing the cemetery).Executes a JSON query against the Context collection, returning either matching Context definitions or flat_emitprojection rows.Reads the audit trail of this Context, returning the most recently appended event first.protected com.orientechnologies.orient.core.record.OVertexPersists a new element in the database (subclass hook).protected voidPermanently deletes the context from the active topology and moves its vertex to the historical cemetery (CemeteryContextEnvironment).Retrieves all contexts from the database and returns them as a JSON array string.protected com.orientechnologies.orient.core.record.OVertexTracked Update for a Context (rename/reparent/state-change) is performed exclusively viachangeState(), which additionally enforces the ACTIVE-state and cyclic-reparent guards.voidPerforms runtime validation of mandatory and not-null schema constraints that cannot be enforced directly by OrientDB in distributed mode.voidsetLifecycle(org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) Configures the context lifecycle filter and resets the resolved environment.Methods inherited from class org.gcube.informationsystem.resourceregistry.persistence.orientdb.base.EntityElementManagement
addRelation, addToRelationManagement, createVertex, getBaseRelationManagementMethods inherited from class org.gcube.informationsystem.resourceregistry.persistence.orientdb.base.ElementManagement
addIgnoredFields, all, applyPrivacyMask, applyPrivacyMask, checkERMatch, checkJsonNode, checkUUIDMatch, checkUUIDNotAlreadyInUse, cleanCachedSerialization, concludeTransaction, createOrUpdate, createOrUpdateElementWithResult, exists, getAccessType, getAllProperties, getCachedType, getCurrentODatabaseDocumentFromThreadLocal, getIgnoredFields, getLimit, getMandatoryErrorMessage, getMandatoryErrorMessage, getMetadataPolicy, getOClass, getOffset, getPropertyForJson, getPropertyMap, getTypeName, getUpdateMode, getUUID, internalCreate, internalCreateOrUdate, internalDelete, internalUpdate, isDryRun, isMaskMetadata, isPolymorphic, isPreservePassedMetadata, isReload, isSanityCheckDeferred, read, requireExplicitUUID, retrieveElement, retrieveElementFromAnyContext, serializeAsAffectedInstance, serializeAsEndpointReference, serializeAsJsonNode, serializeSelfAsJsonNode, setAsEntryPoint, setDryRun, setElement, setElementType, setIgnoredFields, setJson, setJsonNode, setLimit, setMaskMetadata, setMetadataPolicy, setOClass, setODatabaseDocument, setOffset, setOperation, setPolymorphic, setPreservePassedMetadata, setProperty, setReload, setRequireExplicitUUID, setSanityCheckDeferred, setUpdateMode, setUUID, setWorkingEnvironment, typeSatified, update, updateProperties
-
Field Details
-
name
The name of the Context being managed. -
lifecycle
protected org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycleThe lifecycle filter configuration used to resolve the database environment. -
purge
protected boolean purgeWhether the delete operation should permanently purge the context instead of moving it to the cemetery. -
projection
protected boolean projectionWhether the last JSON query returned an_emitprojection.
-
-
Constructor Details
-
ContextManagement
public ContextManagement()Creates a new, uninitializedContextManagementinstance. Binds the management class to theAccessType.CONTEXTaccess type. -
ContextManagement
public ContextManagement(org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle, com.orientechnologies.orient.core.db.document.ODatabaseDocument oDatabaseDocument) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException Creates a newContextManagementinstance bound to the specified OrientDB database.- Parameters:
lifecycle- the current lifecycle state manager for contextsoDatabaseDocument- the OrientDB database connection to use- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if the working environment cannot be initialized
-
-
Method Details
-
getLifecycle
public org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle getLifecycle()Retrieves the current context lifecycle configuration.- Returns:
- the active context lifecycle configuration
-
create
public String create() throws org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionInitializes the Context version counter before the creation transaction starts.- Overrides:
createin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- the serialized JSON representation of the created Context
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException- if the Context already existsorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if creation fails
-
setLifecycle
public void setLifecycle(org.gcube.informationsystem.resourceregistry.api.rest.ContextLifecycle lifecycle) Configures the context lifecycle filter and resets the resolved environment.- Parameters:
lifecycle- the context lifecycle configuration to set
-
isProjection
public boolean isProjection()Reports whether the lastquery(String)call returned an_emitprojection rather than complete Context objects.- Returns:
truefor a projection query,falseotherwise
-
getAffectedInstances
Returns the map of instances affected by operations on this context. This operation is not supported on Contexts.- Overrides:
getAffectedInstancesin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- the map of affected instances
-
getName
Returns the name of the Context.- Returns:
- the name of the Context
-
getWorkingEnvironment
protected Environment getWorkingEnvironment() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionReturns the active LiveContextEnvironment working environment.- Specified by:
getWorkingEnvironmentin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- the working environment
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if the environment cannot be resolved
-
getElement
public com.orientechnologies.orient.core.record.OVertex getElement() throws org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException, org.gcube.informationsystem.resourceregistry.api.exceptions.instances.AvailableInAnotherContextException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionReturns the OrientDB vertex for the configured UUID, restricted to the currentlifecyclescope.When the base lookup fails and
lifecycleis notContextLifecycle.ALL, probes whether the vertex actually exists in the opposite environment (LiveContextEnvironmentvsCemeteryContextEnvironment) to distinguish a genuine not-found from a lifecycle-scope mismatch, throwingContextVisibilityExceptionfor the latter.- Overrides:
getElementin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- the resolved
OVertex - Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException- if no context with this UUID exists in any lifecycle scopeorg.gcube.informationsystem.resourceregistry.api.exceptions.instances.AvailableInAnotherContextException- if the context exists but is not visible from the caller's current security contextorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if the lookup or lifecycle probe fails
-
getSpecificNotFoundException
protected org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException getSpecificNotFoundException(org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException e) Converts a generic NotFoundException into a ContextNotFoundException.- Specified by:
getSpecificNotFoundExceptionin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Parameters:
e- the generic exception- Returns:
- the converted ContextNotFoundException
-
getSpecificAlreadyPresentException
protected org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextAlreadyPresentException getSpecificAlreadyPresentException(String message) Converts a generic AlreadyPresentException into a ContextAlreadyPresentException.- Specified by:
getSpecificAlreadyPresentExceptionin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Parameters:
message- the exception message- Returns:
- the converted ContextAlreadyPresentException
-
checkContext
protected void checkContext(ContextManagement parentContext) throws org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException, org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextAlreadyPresentException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException Validates that the context is topologically valid and does not violate uniqueness constraints: no sibling with the same name underparentContextand, for a parentless Context, no other live Root, since the Context topology is either empty or a single-root tree.- Parameters:
parentContext- the parent context, ornullfor a parentless Context- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException- if the parent context does not existorg.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextAlreadyPresentException- if a context with the same name already exists under the parent, or ifparentContextisnulland another live Root existsorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if database lookup fails
-
createCompleteJsonNode
protected org.gcube.com.fasterxml.jackson.databind.JsonNode createCompleteJsonNode() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionDescription copied from class:ElementManagementAbstract method to create the complete JSON node representation of the element.- Specified by:
createCompleteJsonNodein classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- the complete JSON node representing the element and its relationships
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on serialization or mapping error
-
getPathFromVertex
Reads a Context's persisted path directly off its OrientDB vertex, falling back to the legacyfullPathproperty name for a not-yet-migrated record.- Parameters:
vertex- the Context vertex to read, ornull- Returns:
- the persisted path, or
nullifvertexisnullor carries neither property
-
getPreviousPathsFromVertex
public static Set<String> getPreviousPathsFromVertex(com.orientechnologies.orient.core.record.OVertex vertex) Reads a Context's persisted set of previous paths directly off its OrientDB vertex.- Parameters:
vertex- the Context vertex to read, ornull- Returns:
- the persisted previous paths, in insertion order; empty if
vertexisnullor carries none
-
reallyCreate
protected com.orientechnologies.orient.core.record.OVertex reallyCreate() throws org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionDescription copied from class:ElementManagementPersists a new element in the database (subclass hook).- Specified by:
reallyCreatein classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- the persisted OrientDB vertex
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException- if the element already exists in the databaseorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on any database error
-
manageDerivedFields
protected void manageDerivedFields() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionComputes and persists theContext.PATHandContext.EFFECTIVE_STATEof this context into the vertex.Called at:
- Creation time
- Rename time (see #25139)
- Parent change (reparent) time (see #26544)
CemeteryContextEnvironment) without any further path recomputation: the vertex already carries its last knownpath(see #19428).- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if database lookup or property mapping fails
-
checkStateChange
protected void checkStateChange(org.gcube.informationsystem.contexts.reference.ContextState newContextstate) Validates whether a context's state transition is legally permissible.- Parameters:
newContextstate- the target state to transition to- Throws:
jakarta.ws.rs.BadRequestException- if the target state is invalid or forbidden
-
reallyUpdate
protected com.orientechnologies.orient.core.record.OVertex reallyUpdate() throws org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionTracked Update for a Context (rename/reparent/state-change) is performed exclusively viachangeState(), which additionally enforces the ACTIVE-state and cyclic-reparent guards. This generic upsert path is not supported on Contexts.- Specified by:
reallyUpdatein classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- never returns
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException- if the element does not exist in the databaseorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on any database error
-
reallyDelete
protected void reallyDelete() throws org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionPermanently deletes the context from the active topology and moves its vertex to the historical cemetery (CemeteryContextEnvironment).Strict validations:
- The context must not have any child contexts (throws
AlreadyPresentException). - The context must not contain any graph instances (throws
AlreadyPresentException).
Moves the context vertex by denying it in the
LiveContextEnvironmentand allowing it inCemeteryContextEnvironment(swapping RLS security roles).- Specified by:
reallyDeletein classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException- if the context does not exist in the databaseorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if database or topological validation fails
- The context must not have any child contexts (throws
-
delete
protected void delete(boolean purge) throws org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException Deletes or purges the Context from the database using a privileged administrative session.This operation runs in a privileged admin transaction to allow schema/role modifications and bypass any uncommitted transactional lock conflicts on RLS records.
- Parameters:
purge-trueto permanently purge,falseto move to the cemetery- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException- if the context does not existorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on database error
-
delete
public void delete() throws org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionDeletes the Context from the database (logical delete, moves to cemetery).- Overrides:
deletein classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException- if the context does not existorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on database error
-
purge
public void purge() throws org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionPermanently purges the Context from the database entirely (bypassing the cemetery).- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException- if the context does not existorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on database error
-
reallyGetAll
public String reallyGetAll() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionRetrieves all contexts from the database and returns them as a JSON array string.Applies pagination limits and offsets retrieved from the server request info, or overridden via force limits/offsets.
- Specified by:
reallyGetAllin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Returns:
- JSON array string representing all matching contexts
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if database traversal or serialization fails
-
query
public String query(String jsonQuery) 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 either matching Context definitions or flat_emitprojection rows. Full Context visibility filtering remains the caller's responsibility (seeContextRepository#query(...)), while projection aliases for sensitive metadata are masked when configured.Honours the
limit/offsetfields already configured on this instance, and thelifecyclealready configured viasetLifecycle(ContextLifecycle)(which determines which ofLiveContextEnvironment/CemeteryContextEnvironment/ContextEnvironmentis opened viagetWorkingEnvironment()).- Parameters:
jsonQuery- the JSON query payload describing the Context search criteria- Returns:
- JSON array string of matching, unfiltered Context definitions
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.queries.InvalidQueryException- if the query is invalid or syntactically incorrectorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on database or processing failure
-
sanityCheck
public void sanityCheck() throws org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaViolationException, org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionDescription copied from class:ElementManagementPerforms runtime validation of mandatory and not-null schema constraints that cannot be enforced directly by OrientDB in distributed mode.- Overrides:
sanityCheckin classElementManagement<com.orientechnologies.orient.core.record.OVertex,org.gcube.informationsystem.types.reference.entities.EntitySchema> - Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaViolationException- if a schema constraint is violatedorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on database lookup failure
-
changeState
public String changeState() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionApplies only tracked local-state, name, or parent changes and recursively recomputes the effective states and paths of all descendants.Enforces state machine constraints (blocking rename/reparent if state is ACTIVE), the single-root topology, and single ownership of every live path, and registers transition history events.
- Returns:
- the serialized JSON string of the updated context
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if the database transaction or state change validation fails
-
getContextByPath
public org.gcube.informationsystem.contexts.reference.entities.Context getContextByPath(String path) throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException Returns theContextidentified bypath. Opens and closes its own database connection.- Parameters:
path- the fully-qualified context path, e.g./gcube/devsec/devVRE- Returns:
- the matching
Context - Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException- if no context matches the given pathorg.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- on any other error
-
readHistory
public String readHistory() throws org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryExceptionReads the audit trail of this Context, returning the most recently appended event first.- Returns:
- reverse-chronological JSON array string of history events
- Throws:
org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException- if database lookup or JSON serialization fails
-