@@ -97,7 +97,13 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon
9797 superClassOfRelations : Map [SmartIri , Set [SmartIri ]],
9898 subPropertyOfRelations : Map [SmartIri , Set [SmartIri ]],
9999 guiAttributeDefinitions : Map [SmartIri , Set [SalsahGuiAttributeDefinition ]],
100- standoffProperties : Set [SmartIri ])
100+ standoffProperties : Set [SmartIri ]) {
101+ lazy val allPropertyDefs : Map [SmartIri , PropertyInfoContentV2 ] = ontologies.values
102+ .flatMap(_.properties.map {
103+ case (propertyIri, readPropertyInfo) => propertyIri -> readPropertyInfo.entityInfoContent
104+ })
105+ .toMap
106+ }
101107
102108 /**
103109 * Receives a message of type [[OntologiesResponderRequestV2 ]], and returns an appropriate response message.
@@ -163,7 +169,7 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon
163169 */
164170 private def loadOntologies (featureFactoryConfig : FeatureFactoryConfig ,
165171 requestingUser : UserADM ): Future [SuccessResponseV2 ] = {
166- for {
172+ val loadOntologiesFuture : Future [ SuccessResponseV2 ] = for {
167173 _ <- Future {
168174 if (! (requestingUser.id == KnoraSystemInstances .Users .SystemUser .id || requestingUser.permissions.isSystemAdmin)) {
169175 throw ForbiddenException (s " Only a system administrator can reload ontologies " )
@@ -211,8 +217,19 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon
211217 ontologyGraphs : Iterable [OntologyGraph ] <- Future .sequence(ontologyGraphResponseFutures)
212218
213219 _ = makeOntologyCache(allOntologyMetadata, ontologyGraphs)
214-
215220 } yield SuccessResponseV2 (" Ontologies loaded." )
221+
222+ loadOntologiesFuture.recover {
223+ case exception : Throwable =>
224+ exception match {
225+ case inconsistentRepositoryDataException : InconsistentRepositoryDataException =>
226+ log.error(inconsistentRepositoryDataException.message)
227+ SuccessResponseV2 (
228+ s " An error occurred when loading ontologies: ${inconsistentRepositoryDataException.message}" )
229+
230+ case other => throw other
231+ }
232+ }
216233 }
217234
218235 /**
@@ -895,24 +912,16 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon
895912 }
896913 }
897914
898- // A cardinality on a property with a boolean object must be 1 or 0-1.
899-
900- val invalidCardinalitiesOnBooleanProps : Set [SmartIri ] = directCardinalities.filter {
901- case (propertyIri, knoraCardinalityInfo) =>
902- val propertyObjectClassConstraint : SmartIri = allPropertyDefs(propertyIri).requireIriObject(
903- OntologyConstants .KnoraBase .ObjectClassConstraint .toSmartIri,
904- throw InconsistentRepositoryDataException (
905- s " Property $propertyIri has no knora-base:objectClassConstraint " )
906- )
907- propertyObjectClassConstraint == OntologyConstants .KnoraBase .BooleanValue .toSmartIri &&
908- ! (knoraCardinalityInfo.cardinality == Cardinality .MustHaveOne || knoraCardinalityInfo.cardinality == Cardinality .MayHaveOne )
909- }.keySet
910-
911- if (invalidCardinalitiesOnBooleanProps.nonEmpty) {
912- throw InconsistentRepositoryDataException (
913- s " Class $classIri has one or more invalid cardinalities on boolean properties: ${invalidCardinalitiesOnBooleanProps
914- .mkString(" , " )}" )
915- }
915+ // Check for invalid cardinalities on boolean properties.
916+ checkForInvalidBooleanCardinalities(
917+ classIri = classIri,
918+ directCardinalities = directCardinalities,
919+ allPropertyDefs = allPropertyDefs,
920+ schemaForErrors = InternalSchema ,
921+ errorFun = { msg : String =>
922+ throw InconsistentRepositoryDataException (msg)
923+ }
924+ )
916925
917926 // All its base classes with Knora IRIs must also be resource classes.
918927 for (baseClass <- classDef.subClassOf) {
@@ -1023,6 +1032,42 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon
10231032 }
10241033 }
10251034
1035+ /**
1036+ * Checks for invalid cardinalities on boolean properties.
1037+ *
1038+ * @param classIri the class IRI.
1039+ * @param directCardinalities the cardinalities directly defined on the class.
1040+ * @param allPropertyDefs all property definitions.
1041+ */
1042+ def checkForInvalidBooleanCardinalities (classIri : SmartIri ,
1043+ directCardinalities : Map [SmartIri , KnoraCardinalityInfo ],
1044+ allPropertyDefs : Map [SmartIri , PropertyInfoContentV2 ],
1045+ schemaForErrors : OntologySchema ,
1046+ errorFun : String => Nothing ): Unit = {
1047+ // A cardinality on a property with a boolean object must be 1 or 0-1.
1048+
1049+ val invalidCardinalitiesOnBooleanProps : Set [SmartIri ] = directCardinalities.filter {
1050+ case (propertyIri, knoraCardinalityInfo) =>
1051+ val objectClassConstraintIri = OntologyConstants .KnoraBase .ObjectClassConstraint .toSmartIri
1052+
1053+ val propertyObjectClassConstraint : SmartIri = allPropertyDefs(propertyIri).requireIriObject(
1054+ objectClassConstraintIri,
1055+ errorFun(s " Property ${propertyIri
1056+ .toOntologySchema(schemaForErrors)} has no ${objectClassConstraintIri.toOntologySchema(schemaForErrors)}" )
1057+ )
1058+
1059+ propertyObjectClassConstraint == OntologyConstants .KnoraBase .BooleanValue .toSmartIri &&
1060+ ! (knoraCardinalityInfo.cardinality == Cardinality .MustHaveOne || knoraCardinalityInfo.cardinality == Cardinality .MayHaveOne )
1061+ }.keySet
1062+
1063+ if (invalidCardinalitiesOnBooleanProps.nonEmpty) {
1064+ errorFun(
1065+ s " Class ${classIri.toOntologySchema(schemaForErrors).toSparql} has one or more invalid cardinalities on boolean properties: ${invalidCardinalitiesOnBooleanProps
1066+ .map(_.toOntologySchema(schemaForErrors).toSparql)
1067+ .mkString(" , " )}" )
1068+ }
1069+ }
1070+
10261071 /**
10271072 * Constructs a map of property IRIs to [[ReadPropertyInfoV2 ]] instances, based on property definitions loaded from the
10281073 * triplestore.
@@ -2504,6 +2549,17 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon
25042549 case None => ()
25052550 }
25062551
2552+ // Check for invalid cardinalities on boolean properties.
2553+ checkForInvalidBooleanCardinalities(
2554+ classIri = internalClassDef.classIri,
2555+ directCardinalities = internalClassDef.directCardinalities,
2556+ allPropertyDefs = cacheData.allPropertyDefs,
2557+ schemaForErrors = ApiV2Complex ,
2558+ errorFun = { msg : String =>
2559+ throw BadRequestException (msg)
2560+ }
2561+ )
2562+
25072563 (classDefWithAddedLinkValueProps, cardinalitiesForClassWithInheritance)
25082564 }
25092565
0 commit comments