diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala index c2fc589bd2..6caf269adc 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala @@ -71,6 +71,16 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon */ private val OntologyCacheKey = "ontologyCacheData" + /** + * The in-memory cache of ontologies. + * + * @param ontologies a map of ontology IRIs to ontologies. + * @param subClassOfRelations a map of subclasses to their base classes. + * @param superClassOfRelations a map of base classes to their subclasses. + * @param subPropertyOfRelations a map of subproperties to their base proeprties. + * @param guiAttributeDefinitions a map of salsah-gui:Guielement individuals to their GUI attribute definitions. + * @param standoffProperties a set of standoff properties. + */ private case class OntologyCacheData(ontologies: Map[SmartIri, ReadOntologyV2], subClassOfRelations: Map[SmartIri, Set[SmartIri]], superClassOfRelations: Map[SmartIri, Set[SmartIri]], @@ -2618,7 +2628,10 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon classes = ontology.classes - internalClassIri ) - updatedSubClassOfRelations = cacheData.subClassOfRelations - internalClassIri + updatedSubClassOfRelations = (cacheData.subClassOfRelations - internalClassIri).map { + case (subClass, baseClasses) => subClass -> (baseClasses - internalClassIri) + } + updatedSuperClassOfRelations = calculateSuperClassOfRelations(updatedSubClassOfRelations) _ = storeCacheData(cacheData.copy( @@ -2736,7 +2749,9 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon properties = ontology.properties -- propertiesToRemoveFromCache ) - updatedSubPropertyOfRelations = cacheData.subPropertyOfRelations -- propertiesToRemoveFromCache + updatedSubPropertyOfRelations = (cacheData.subPropertyOfRelations -- propertiesToRemoveFromCache).map { + case (subProperty, baseProperties) => subProperty -> (baseProperties -- propertiesToRemoveFromCache) + } _ = storeCacheData(cacheData.copy( ontologies = cacheData.ontologies + (internalOntologyIri -> updatedOntology), @@ -2789,7 +2804,7 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon expectedLastModificationDate = deleteOntologyRequest.lastModificationDate ) - // Check that none of the entities in the ontology are used in data. + // Check that none of the entities in the ontology are used in data or in other ontologies. ontology = cacheData.ontologies(internalOntologyIri) @@ -2827,6 +2842,33 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon throw UpdateNotPerformedException(s"Ontology ${internalOntologyIri.toOntologySchema(ApiV2Complex)} was not deleted. Please report this as a possible bug.") } + // Remove the ontology from the cache. + + updatedSubClassOfRelations = cacheData.subClassOfRelations.filterNot { + case (subClass, _) => subClass.getOntologyFromEntity == internalOntologyIri + }.map { + case (subClass, baseClasses) => subClass -> baseClasses.filterNot(_.getOntologyFromEntity == internalOntologyIri) + } + + updatedSuperClassOfRelations = calculateSuperClassOfRelations(updatedSubClassOfRelations) + + updatedSubPropertyOfRelations = cacheData.subPropertyOfRelations.filterNot { + case (subProperty, _) => subProperty.getOntologyFromEntity == internalOntologyIri + }.map { + case (subProperty, baseProperties) => subProperty -> baseProperties.filterNot(_.getOntologyFromEntity == internalOntologyIri) + } + + updatedStandoffProperties = cacheData.standoffProperties.filterNot(_.getOntologyFromEntity == internalOntologyIri) + + updatedCacheData = cacheData.copy( + ontologies = cacheData.ontologies - internalOntologyIri, + subClassOfRelations = updatedSubClassOfRelations, + superClassOfRelations = updatedSuperClassOfRelations, + subPropertyOfRelations = updatedSubPropertyOfRelations, + standoffProperties = updatedStandoffProperties + ) + + _ = storeCacheData(updatedCacheData) } yield SuccessResponseV2(s"Ontology ${internalOntologyIri.toOntologySchema(ApiV2Complex)} has been deleted") } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala index 983a2bad23..7d77efccdb 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala @@ -109,7 +109,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { assert(response.ontologies.size == 1) val metadata = response.ontologies.head assert(metadata.ontologyIri.toString == "http://www.knora.org/ontology/00FF/foo") - fooIri.set(metadata.ontologyIri.toOntologySchema(ApiV2Complex).toString) + fooIri.set(metadata.ontologyIri.toString) fooLastModDate = metadata.lastModificationDate.getOrElse(throw AssertionException(s"${metadata.ontologyIri} has no last modification date")) } @@ -117,7 +117,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { val newLabel = "The modified foo ontology" responderManager ! ChangeOntologyMetadataRequestV2( - ontologyIri = fooIri.get.toSmartIri, + ontologyIri = fooIri.get.toSmartIri.toOntologySchema(ApiV2Complex), label = newLabel, lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, @@ -127,7 +127,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { val response = expectMsgType[ReadOntologyMetadataV2](timeout) assert(response.ontologies.size == 1) val metadata = response.ontologies.head - assert(metadata.ontologyIri.toString == "http://www.knora.org/ontology/00FF/foo") + assert(metadata.ontologyIri == fooIri.get.toSmartIri) assert(metadata.label.contains(newLabel)) val newFooLastModDate = metadata.lastModificationDate.getOrElse(throw AssertionException(s"${metadata.ontologyIri} has no last modification date")) assert(newFooLastModDate.isAfter(fooLastModDate)) @@ -167,7 +167,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { "not allow a user to delete an ontology if they are not a sysadmin or an admin in the ontology's project" in { responderManager ! DeleteOntologyRequestV2( - ontologyIri = fooIri.get.toSmartIri, + ontologyIri = fooIri.get.toSmartIri.toOntologySchema(ApiV2Complex), lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, requestingUser = SharedTestDataADM.imagesUser02 @@ -182,7 +182,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { "delete the 'foo' ontology" in { responderManager ! DeleteOntologyRequestV2( - ontologyIri = fooIri.get.toSmartIri, + ontologyIri = fooIri.get.toSmartIri.toOntologySchema(ApiV2Complex), lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, requestingUser = imagesUser