diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt index fd2e72d73..6a31ceb00 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt @@ -29,6 +29,7 @@ import org.springframework.web.reactive.function.client.awaitBodyOrNull import org.springframework.web.reactive.function.client.awaitExchange import java.net.URI +// ContextsourceRegistration is null in case of local error typealias DistributionStatus = Either, Unit> @Service @@ -155,7 +156,7 @@ class DistributedEntityProvisionService( GatewayTimeoutException(message).left() } else { logger.warn("Error creating an entity for CSR at $uri: $response") - ContextSourceException(response).left() + ContextSourceException.fromResponse(response).left() } }.fold( onSuccess = { it }, diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt index 904f351c8..ec6fc79e4 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt @@ -92,6 +92,7 @@ class EntityHandler( extractPayloadAndContexts(requestBody, httpHeaders, applicationProperties.contexts.core).bind() val expandedEntity = expandJsonLdEntity(body, contexts) + expandedEntity.toNgsiLdEntity().bind() val (distributionStatuses, remainingEntity) = distributedEntityProvisionService .distributeCreateEntity(httpHeaders, expandedEntity, contexts) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt index b7a40b55f..8b689bdaf 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt @@ -2,8 +2,8 @@ package com.egm.stellio.shared.model import com.apicatalog.jsonld.JsonLdError import com.apicatalog.jsonld.JsonLdErrorCode -import com.egm.stellio.shared.util.JsonLdUtils.logger -import com.egm.stellio.shared.util.mapper +import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap +import com.egm.stellio.shared.util.toUri import org.slf4j.LoggerFactory import org.springframework.http.HttpStatus import org.springframework.http.MediaType @@ -17,8 +17,8 @@ const val DEFAULT_DETAIL = "If you have difficulty identifying the exact cause o "https://github.com/stellio-hub/stellio-context-broker" sealed class APIException( - val type: URI, - val status: HttpStatus, + open val type: URI, + open val status: HttpStatus, override val message: String, open val detail: String = DEFAULT_DETAIL ) : Exception(message) { @@ -36,18 +36,45 @@ sealed class APIException( } } -data class ContextSourceException(val problemDetail: ProblemDetail) : APIException( - type = problemDetail.type, - status = HttpStatus.valueOf(problemDetail.status), - message = problemDetail.title ?: "no title provided", - detail = problemDetail.detail ?: "no detail provided" +data class ContextSourceException( + override val type: URI, + override val status: HttpStatus, + val title: String, + override val detail: String +) : APIException( + type = type, + status = status, + message = title, + detail = detail, ) { - constructor(response: String?) : this( - mapper.readValue( - response, - ProblemDetail::class.java - ) - ) + companion object { + fun fromResponse(response: String): ContextSourceException { + val responseMap = response.deserializeAsMap() + return kotlin.runCatching { + // mandatory + val type = responseMap[ProblemDetail::type.name].toString().toUri() + val title = responseMap[ProblemDetail::title.name]!!.toString() + + // optional + val status = responseMap[ProblemDetail::status.name]?.let { HttpStatus.valueOf(it as Int) } + val detail = responseMap[ProblemDetail::detail.name]?.toString() + + ContextSourceException( + type = type, + status = status ?: HttpStatus.BAD_GATEWAY, + title = title, + detail = detail ?: "no detail provided" + ) + }.fold({ it }, { + ContextSourceException( + ErrorType.BAD_GATEWAY.type, + HttpStatus.BAD_GATEWAY, + "ContextSource sent a badly formed error", + response + ) + }) + } + } } data class ConflictException(override val message: String) : APIException( @@ -172,6 +199,8 @@ enum class ErrorType(val type: URI) { INVALID_REQUEST(URI("https://uri.etsi.org/ngsi-ld/errors/InvalidRequest")), BAD_REQUEST_DATA(URI("https://uri.etsi.org/ngsi-ld/errors/BadRequestData")), ALREADY_EXISTS(URI("https://uri.etsi.org/ngsi-ld/errors/AlreadyExists")), + + // todo add error to the presentation CONFLICT(URI("https://uri.etsi.org/ngsi-ld/errors/Conflict")), // defined only in 6.3.17 BAD_GATEWAY(URI("https://uri.etsi.org/ngsi-ld/errors/BadGateway")), // defined only in 6.3.17 GATEWAY_TIMEOUT(URI("https://uri.etsi.org/ngsi-ld/errors/GatewayTimeout")), // defined only in 6.3.17