Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: switch to Titanium JSON-LD library #1073

Merged
merged 19 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0683c2d
feat(WIP): migrate JSON-LD processing lib to Titanium
bobeal Dec 10, 2023
2876eed
refactor: improve expanded values builders
bobeal Dec 18, 2023
b9de2a1
refactor: expanded / compacted entity wrappers
bobeal Dec 20, 2023
ce6a5fd
fix(temporal): sysAttrs handling for temporal queries
bobeal Dec 23, 2023
8428f0e
fix(temporal): aggregated and simplified representation of attributes…
bobeal Dec 25, 2023
674d90c
feat(common): try to extract the wrapped cause when JSON-LD processin…
bobeal Dec 26, 2023
045b491
refactor: introduce an ExpandedMembers file for manipulation of expan…
bobeal Dec 28, 2023
aeae049
refactor: clean up all the expand / compact processing utilities
bobeal Dec 28, 2023
c861f54
fixup: unused import
bobeal Dec 31, 2023
a69de71
more tests for JsonLdUtils / refactor geoJsonToWkt processing
bobeal Dec 31, 2023
e18b440
refactor: move some last expanded members functions
bobeal Dec 31, 2023
c7073e0
refactoring in tests utils and expanded members
bobeal Dec 31, 2023
ad217d2
refactor: misc cleanup
bobeal Jan 1, 2024
bdde76d
feat(temporal): merge uri value type to string for properties
bobeal Jan 3, 2024
0841693
refactor: extract some constants from JsonLdUtils
bobeal Jan 3, 2024
5f6dc34
refactor: rename extractRelationshipObject et getRelationshipObject
bobeal Jan 3, 2024
31e57ed
refactor: extract creation of a simplified or aggregated temporal ins…
bobeal Jan 3, 2024
b527e04
chore(subscription): update contexts references
bobeal Jan 6, 2024
1087976
fix(temporal): do not restore geo-properties in temporal or aggregate…
bobeal Jan 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ subprojects {
implementation("org.springframework.kafka:spring-kafka")

implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("com.github.jsonld-java:jsonld-java:0.13.6")

implementation("com.apicatalog:titanium-json-ld:1.3.3")
implementation("org.glassfish:jakarta.json:2.0.1")

implementation("io.arrow-kt:arrow-fx-coroutines:1.2.1")

Expand Down
8 changes: 4 additions & 4 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ complexity:
TooManyFunctions:
active: true
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
thresholdInFiles: 20
thresholdInClasses: 20
thresholdInInterfaces: 20
thresholdInObjects: 20
thresholdInFiles: 30
thresholdInClasses: 30
thresholdInInterfaces: 30
thresholdInObjects: 30
thresholdInEnums: 11
ignoreDeprecated: false
ignorePrivate: false
Expand Down
2 changes: 1 addition & 1 deletion search-service/config/detekt/baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<ID>LongMethod:AttributeInstanceService.kt$AttributeInstanceService$@Transactional suspend fun create(attributeInstance: AttributeInstance): Either&lt;APIException, Unit&gt;</ID>
<ID>LongMethod:EntityAccessControlHandler.kt$EntityAccessControlHandler$@PostMapping("/{subjectId}/attrs", consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE]) suspend fun addRightsOnEntities( @RequestHeader httpHeaders: HttpHeaders, @PathVariable subjectId: String, @RequestBody requestBody: Mono&lt;String&gt; ): ResponseEntity&lt;*&gt;</ID>
<ID>LongMethod:QueryServiceTests.kt$QueryServiceTests$@Test fun `it should query temporal entities as requested by query params`()</ID>
<ID>LongMethod:QueryServiceTests.kt$QueryServiceTests$@Test fun `it should return an empty list for an attribute if it has no temporal values`()</ID>
<ID>LongMethod:TemporalEntityBuilderTests.kt$TemporalEntityBuilderTests$@Test fun `it should return a temporal entity with values aggregated`()</ID>
<ID>LongMethod:TemporalScopeBuilderTests.kt$TemporalScopeBuilderTests$@Test fun `it should build an aggregated temporal representation of scopes`()</ID>
<ID>LongMethod:V0_29__JsonLd_migration.kt$V0_29__JsonLd_migration$override fun migrate(context: Context)</ID>
Expand All @@ -28,6 +29,5 @@
<ID>ReturnCount:EntitiesQueryUtils.kt$fun buildTemporalQuery( params: MultiValueMap&lt;String, String&gt;, inQueryEntities: Boolean = false, withAggregatedValues: Boolean = false ): Either&lt;APIException, TemporalQuery&gt;</ID>
<ID>SwallowedException:EntitiesQueryUtils.kt$e: IllegalArgumentException</ID>
<ID>TooManyFunctions:EntityPayloadService.kt$EntityPayloadService</ID>
<ID>TooManyFunctions:TemporalEntityAttributeService.kt$TemporalEntityAttributeService</ID>
</CurrentIssues>
</SmellBaseline>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import arrow.core.Either
import arrow.core.Option
import com.egm.stellio.search.model.EntitiesQuery
import com.egm.stellio.shared.model.APIException
import com.egm.stellio.shared.model.JsonLdEntity
import com.egm.stellio.shared.model.ExpandedEntity
import com.egm.stellio.shared.util.Sub
import java.net.URI

Expand All @@ -23,20 +23,20 @@ interface AuthorizationService {

suspend fun getAuthorizedEntities(
entitiesQuery: EntitiesQuery,
contextLink: String,
contexts: List<String>,
sub: Option<Sub>
): Either<APIException, Pair<Int, List<JsonLdEntity>>>
): Either<APIException, Pair<Int, List<ExpandedEntity>>>

suspend fun getGroupsMemberships(
offset: Int,
limit: Int,
contextLink: String,
contexts: List<String>,
sub: Option<Sub>
): Either<APIException, Pair<Int, List<JsonLdEntity>>>
): Either<APIException, Pair<Int, List<ExpandedEntity>>>

suspend fun getUsers(
offset: Int,
limit: Int,
contextLink: String,
): Either<APIException, Pair<Int, List<JsonLdEntity>>>
contexts: List<String>,
): Either<APIException, Pair<Int, List<ExpandedEntity>>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import arrow.core.Option
import arrow.core.right
import com.egm.stellio.search.model.EntitiesQuery
import com.egm.stellio.shared.model.APIException
import com.egm.stellio.shared.model.JsonLdEntity
import com.egm.stellio.shared.model.ExpandedEntity
import com.egm.stellio.shared.util.Sub
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Component
Expand Down Expand Up @@ -41,20 +41,20 @@ class DisabledAuthorizationService : AuthorizationService {

override suspend fun getAuthorizedEntities(
entitiesQuery: EntitiesQuery,
contextLink: String,
contexts: List<String>,
sub: Option<Sub>
): Either<APIException, Pair<Int, List<JsonLdEntity>>> = Pair(-1, emptyList<JsonLdEntity>()).right()
): Either<APIException, Pair<Int, List<ExpandedEntity>>> = Pair(-1, emptyList<ExpandedEntity>()).right()

override suspend fun getGroupsMemberships(
offset: Int,
limit: Int,
contextLink: String,
contexts: List<String>,
sub: Option<Sub>
): Either<APIException, Pair<Int, List<JsonLdEntity>>> = Pair(-1, emptyList<JsonLdEntity>()).right()
): Either<APIException, Pair<Int, List<ExpandedEntity>>> = Pair(-1, emptyList<ExpandedEntity>()).right()

override suspend fun getUsers(
offset: Int,
limit: Int,
contextLink: String,
): Either<APIException, Pair<Int, List<JsonLdEntity>>> = Pair(-1, emptyList<JsonLdEntity>()).right()
contexts: List<String>,
): Either<APIException, Pair<Int, List<ExpandedEntity>>> = Pair(-1, emptyList<ExpandedEntity>()).right()
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import arrow.fx.coroutines.parMap
import com.egm.stellio.search.model.EntitiesQuery
import com.egm.stellio.shared.model.APIException
import com.egm.stellio.shared.model.AccessDeniedException
import com.egm.stellio.shared.model.JsonLdEntity
import com.egm.stellio.shared.model.ExpandedEntity
import com.egm.stellio.shared.util.*
import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
Expand Down Expand Up @@ -95,9 +95,9 @@ class EnabledAuthorizationService(

override suspend fun getAuthorizedEntities(
entitiesQuery: EntitiesQuery,
contextLink: String,
contexts: List<String>,
sub: Option<Sub>
): Either<APIException, Pair<Int, List<JsonLdEntity>>> = either {
): Either<APIException, Pair<Int, List<ExpandedEntity>>> = either {
val accessRights = entitiesQuery.attrs.mapNotNull { AccessRight.forExpandedAttributeName(it).getOrNull() }
val entitiesAccessControl = entityAccessRightsService.getSubjectAccessRights(
sub,
Expand Down Expand Up @@ -127,8 +127,8 @@ class EnabledAuthorizationService(
)
} else entityAccessControl
}
.map { it.serializeProperties(contextLink) }
.map { JsonLdEntity(it, listOf(contextLink)) }
.map { it.serializeProperties(contexts) }
.map { ExpandedEntity(it, contexts) }

val count = entityAccessRightsService.getSubjectAccessRightsCount(
sub,
Expand All @@ -143,9 +143,9 @@ class EnabledAuthorizationService(
override suspend fun getGroupsMemberships(
offset: Int,
limit: Int,
contextLink: String,
contexts: List<String>,
sub: Option<Sub>
): Either<APIException, Pair<Int, List<JsonLdEntity>>> = either {
): Either<APIException, Pair<Int, List<ExpandedEntity>>> = either {
val groups =
when (userIsAdmin(sub)) {
is Either.Left -> {
Expand All @@ -162,10 +162,7 @@ class EnabledAuthorizationService(
}

val jsonLdEntities = groups.second.map {
JsonLdEntity(
it.serializeProperties(),
listOf(contextLink)
)
ExpandedEntity(it.serializeProperties(), contexts)
}

Pair(groups.first, jsonLdEntities)
Expand All @@ -174,16 +171,13 @@ class EnabledAuthorizationService(
override suspend fun getUsers(
offset: Int,
limit: Int,
contextLink: String
): Either<APIException, Pair<Int, List<JsonLdEntity>>> = either {
contexts: List<String>,
): Either<APIException, Pair<Int, List<ExpandedEntity>>> = either {
val users = subjectReferentialService.getUsers(offset, limit)
val usersCount = subjectReferentialService.getUsersCount().bind()

val jsonLdEntities = users.map {
JsonLdEntity(
it.serializeProperties(contextLink),
listOf(contextLink)
)
ExpandedEntity(it.serializeProperties(contexts), contexts)
}

Pair(usersCount, jsonLdEntities)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
package com.egm.stellio.search.authorization

import com.egm.stellio.shared.util.*
import com.egm.stellio.shared.model.ExpandedAttributeInstances
import com.egm.stellio.shared.model.ExpandedTerm
import com.egm.stellio.shared.model.addNonReifiedProperty
import com.egm.stellio.shared.model.addSubAttribute
import com.egm.stellio.shared.util.AccessRight
import com.egm.stellio.shared.util.AuthContextModel
import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_RIGHT
import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP
import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUBJECT_INFO
import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_ADMIN
import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_READ
import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_WRITE
import com.egm.stellio.shared.util.JsonLdUtils.DATASET_ID_PREFIX
import com.egm.stellio.shared.util.AuthContextModel.DATASET_ID_PREFIX
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyMapValue
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedRelationship
import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedProperty
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedRelationshipValue
import com.egm.stellio.shared.util.extractSub
import com.egm.stellio.shared.util.toUri
import java.net.URI

data class EntityAccessRights(
Expand All @@ -33,39 +39,39 @@ data class EntityAccessRights(
) {
val datasetId: URI = (DATASET_ID_PREFIX + uri.extractSub()).toUri()

suspend fun serializeProperties(contextLink: String): ExpandedAttributeInstances =
buildExpandedRelationship(uri)
.addSubAttribute(NGSILD_DATASET_ID_PROPERTY, buildNonReifiedProperty(datasetId.toString()))
suspend fun serializeProperties(contexts: List<String>): ExpandedAttributeInstances =
buildExpandedRelationshipValue(uri)
.addNonReifiedProperty(NGSILD_DATASET_ID_PROPERTY, datasetId.toString())
.addSubAttribute(
AUTH_PROP_SUBJECT_INFO,
buildExpandedPropertyMapValue(subjectInfo, listOf(contextLink))
buildExpandedPropertyMapValue(subjectInfo, contexts)
)
}

suspend fun serializeProperties(contextLink: String): Map<String, Any> {
suspend fun serializeProperties(contexts: List<String>): Map<String, Any> {
val resultEntity = mutableMapOf<String, Any>()

resultEntity[JSONLD_ID] = id.toString()
resultEntity[JSONLD_TYPE] = types
resultEntity[AUTH_PROP_RIGHT] = buildExpandedProperty(right.attributeName)
resultEntity[AUTH_PROP_RIGHT] = buildExpandedPropertyValue(right.attributeName)

specificAccessPolicy?.run {
resultEntity[AUTH_PROP_SAP] = buildExpandedProperty(this)
resultEntity[AUTH_PROP_SAP] = buildExpandedPropertyValue(this)
}

rCanAdminUsers?.run {
resultEntity[AUTH_REL_CAN_ADMIN] = this.map {
it.serializeProperties(contextLink)
it.serializeProperties(contexts)
}.flatten()
}
rCanWriteUsers?.run {
resultEntity[AUTH_REL_CAN_WRITE] = this.map {
it.serializeProperties(contextLink)
it.serializeProperties(contexts)
}.flatten()
}
rCanReadUsers?.run {
resultEntity[AUTH_REL_CAN_READ] = this.map {
it.serializeProperties(contextLink)
it.serializeProperties(contexts)
}.flatten()
}
return resultEntity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.egm.stellio.search.authorization

import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_NAME
import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_IS_MEMBER_OF
import com.egm.stellio.shared.util.AuthContextModel.GROUP_ENTITY_PREFIX
import com.egm.stellio.shared.util.AuthContextModel.GROUP_TYPE
import com.egm.stellio.shared.util.JsonLdUtils
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue

data class Group(
val id: String,
Expand All @@ -18,10 +18,10 @@ data class Group(
resultEntity[JsonLdUtils.JSONLD_ID] = GROUP_ENTITY_PREFIX + id
resultEntity[JsonLdUtils.JSONLD_TYPE] = listOf(type)

resultEntity[NGSILD_NAME_PROPERTY] = buildExpandedProperty(name)
resultEntity[AUTH_PROP_NAME] = buildExpandedPropertyValue(name)

isMember.run {
resultEntity[AUTH_REL_IS_MEMBER_OF] = buildExpandedProperty(isMember.toString())
resultEntity[AUTH_REL_IS_MEMBER_OF] = buildExpandedPropertyValue(isMember.toString())
}
return resultEntity
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import com.egm.stellio.shared.util.AuthContextModel.USER_ENTITY_PREFIX
import com.egm.stellio.shared.util.AuthContextModel.USER_TYPE
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyMapValue
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue

data class User(
val id: String,
Expand All @@ -23,27 +23,27 @@ data class User(
val familyName: String? = null,
val subjectInfo: Map<String, String>
) {
suspend fun serializeProperties(contextLink: String): Map<String, Any> {
suspend fun serializeProperties(contexts: List<String>): Map<String, Any> {
val resultEntity = mutableMapOf<String, Any>()
resultEntity[JSONLD_ID] = USER_ENTITY_PREFIX + id
resultEntity[JSONLD_TYPE] = listOf(type)

resultEntity[AUTH_PROP_USERNAME] = buildExpandedProperty(username)
resultEntity[AUTH_PROP_USERNAME] = buildExpandedPropertyValue(username)

givenName?.run {
resultEntity[AUTH_PROP_GIVEN_NAME] = buildExpandedProperty(givenName)
resultEntity[AUTH_PROP_GIVEN_NAME] = buildExpandedPropertyValue(givenName)
}

familyName?.run {
resultEntity[AUTH_PROP_FAMILY_NAME] = buildExpandedProperty(familyName)
resultEntity[AUTH_PROP_FAMILY_NAME] = buildExpandedPropertyValue(familyName)
}

subjectInfo.filterKeys {
!setOf(AUTH_TERM_USERNAME, AUTH_TERM_GIVEN_NAME, AUTH_TERM_FAMILY_NAME, AUTH_TERM_KIND).contains(it)
}.run {
if (this.isNotEmpty())
resultEntity[AUTH_PROP_SUBJECT_INFO] =
buildExpandedPropertyMapValue(this, listOf(contextLink))
buildExpandedPropertyMapValue(this, contexts)
}

return resultEntity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import com.egm.stellio.search.service.EntityEventService
import com.egm.stellio.search.service.EntityPayloadService
import com.egm.stellio.shared.model.*
import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute
import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity
import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerms
import com.egm.stellio.shared.util.JsonUtils.deserializeAs
import com.egm.stellio.shared.util.toExpandedAttributes
import com.egm.stellio.shared.web.NGSILD_TENANT_HEADER
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -64,10 +64,16 @@ class ObservationEventListener(
tenantUri: URI,
observationEvent: EntityCreateEvent
): Either<APIException, Unit> = either {
val expandedEntity = expandJsonLdEntity(
observationEvent.operationPayload,
observationEvent.contexts
)
val ngsiLdEntity = expandedEntity.toNgsiLdEntity().bind()

mono {
entityPayloadService.createEntity(
observationEvent.operationPayload,
observationEvent.contexts,
ngsiLdEntity,
expandedEntity,
observationEvent.sub
).map {
entityEventService.publishEntityCreateEvent(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.egm.stellio.search.model

import com.egm.stellio.shared.model.ExpandedAttributeInstance
import com.egm.stellio.shared.model.WKTCoordinates
import com.egm.stellio.shared.util.ExpandedAttributeInstance
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_INSTANCE_ID_PROPERTY
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY
import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedDateTime
import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedProperty
import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue
import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue
import com.egm.stellio.shared.util.JsonUtils.serializeObject
import com.egm.stellio.shared.util.toUri
import io.r2dbc.postgresql.codec.Json
Expand Down Expand Up @@ -72,10 +72,10 @@ data class AttributeInstance private constructor(
instanceId: URI,
modifiedAt: ZonedDateTime? = null
): ExpandedAttributeInstance =
this.plus(NGSILD_INSTANCE_ID_PROPERTY to buildNonReifiedProperty(instanceId.toString()))
this.plus(NGSILD_INSTANCE_ID_PROPERTY to buildNonReifiedPropertyValue(instanceId.toString()))
.let {
if (modifiedAt != null)
it.plus(NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedDateTime(modifiedAt))
it.plus(NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedTemporalValue(modifiedAt))
else it
}

Expand Down
Loading
Loading