Skip to content

Commit

Permalink
refactor: better SoC for entity and attribute representations
Browse files Browse the repository at this point in the history
  • Loading branch information
bobeal committed Nov 24, 2023
1 parent 8df4712 commit 3ccaced
Show file tree
Hide file tree
Showing 27 changed files with 388 additions and 286 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ data class EntitiesQuery(
val scopeQ: String? = null,
val paginationQuery: PaginationQuery,
val attrs: Set<ExpandedTerm> = emptySet(),
val includeSysAttrs: Boolean = false,
val useSimplifiedRepresentation: Boolean = false,
val geoQuery: GeoQuery? = null,
val context: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_TERM
import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty
Expand All @@ -33,7 +35,6 @@ data class EntityPayload(
val specificAccessPolicy: SpecificAccessPolicy? = null
) {
fun serializeProperties(
withSysAttrs: Boolean,
withCompactTerms: Boolean = false,
contexts: List<String> = emptyList()
): Map<String, Any> {
Expand All @@ -56,6 +57,11 @@ data class EntityPayload(
JSONLD_VALUE_TERM to this
)
}

resultEntity[NGSILD_CREATED_AT_TERM] = createdAt
modifiedAt?.run {
resultEntity[NGSILD_MODIFIED_AT_TERM] = this
}
} else {
resultEntity[JSONLD_ID] = entityId.toString()
resultEntity[JSONLD_TYPE] = types
Expand All @@ -67,14 +73,13 @@ data class EntityPayload(
specificAccessPolicy?.run {
resultEntity[AuthContextModel.AUTH_PROP_SAP] = buildExpandedProperty(this)
}
if (withSysAttrs) {
resultEntity[NGSILD_CREATED_AT_PROPERTY] = buildNonReifiedDateTime(createdAt)

modifiedAt?.run {
resultEntity[NGSILD_MODIFIED_AT_PROPERTY] = buildNonReifiedDateTime(this)
}
resultEntity[NGSILD_CREATED_AT_PROPERTY] = buildNonReifiedDateTime(createdAt)
modifiedAt?.run {
resultEntity[NGSILD_MODIFIED_AT_PROPERTY] = buildNonReifiedDateTime(this)
}
}

return resultEntity
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ class EntityPayloadService(
temporalEntityAttributes: List<TemporalEntityAttribute>,
entityPayload: EntityPayload
): Map<String, Any> {
val entityCoreAttributes = entityPayload.serializeProperties(withSysAttrs = true)
val entityCoreAttributes = entityPayload.serializeProperties()
val expandedAttributes = temporalEntityAttributes
.groupBy { tea ->
tea.attributeName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ fun composeEntitiesQuery(
val q = requestParams.getFirst(QUERY_PARAM_Q)?.decode()
val scopeQ = requestParams.getFirst(QUERY_PARAM_SCOPEQ)
val attrs = parseAndExpandRequestParameter(requestParams.getFirst(QUERY_PARAM_ATTRS), contextLink)
val includeSysAttrs = requestParams.getOrDefault(QUERY_PARAM_OPTIONS, emptyList())
.contains(QUERY_PARAM_OPTIONS_SYSATTRS_VALUE)
val useSimplifiedRepresentation = requestParams.getOrDefault(QUERY_PARAM_OPTIONS, emptyList())
.contains(QUERY_PARAM_OPTIONS_KEYVALUES_VALUE)
val paginationQuery = parsePaginationParameters(
requestParams,
defaultPagination.limitDefault,
Expand All @@ -48,8 +44,6 @@ fun composeEntitiesQuery(
scopeQ = scopeQ,
paginationQuery = paginationQuery,
attrs = attrs,
includeSysAttrs = includeSysAttrs,
useSimplifiedRepresentation = useSimplifiedRepresentation,
geoQuery = geoQuery,
context = contextLink
)
Expand Down Expand Up @@ -99,10 +93,6 @@ fun composeEntitiesQueryFromPostRequest(
parseGeoQueryParameters(geoQueryElements, contextLink).bind()
} else null

val includeSysAttrs = requestParams.getOrDefault(QUERY_PARAM_OPTIONS, emptyList())
.contains(QUERY_PARAM_OPTIONS_SYSATTRS_VALUE)
val useSimplifiedRepresentation = requestParams.getOrDefault(QUERY_PARAM_OPTIONS, emptyList())
.contains(QUERY_PARAM_OPTIONS_KEYVALUES_VALUE)
val paginationQuery = parsePaginationParameters(
requestParams,
defaultPagination.limitDefault,
Expand All @@ -117,8 +107,6 @@ fun composeEntitiesQueryFromPostRequest(
scopeQ = query.scopeQ,
paginationQuery = paginationQuery,
attrs = attrs,
includeSysAttrs = includeSysAttrs,
useSimplifiedRepresentation = useSimplifiedRepresentation,
geoQuery = geoQuery,
context = contextLink
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ object TemporalEntityBuilder {
)

return entityTemporalResult.entityPayload.serializeProperties(
withSysAttrs = temporalEntitiesQuery.entitiesQuery.includeSysAttrs,
withCompactTerms = true,
contexts
).plus(temporalAttributes)
Expand Down Expand Up @@ -222,3 +221,15 @@ object TemporalEntityBuilder {
}
}
}

/**
* A specific application of sysAttrs option to temporal entities, that only applies it to the entity and not to the
* attributes. Currently, this is not clear what should be done for attributes who already convey specifically asked
* temporal information.
*/
fun CompactedJsonLdEntity.applySysAttrs(includeSysAttrs: Boolean) =
this.let {
if (!includeSysAttrs)
it.minus(JsonLdUtils.NGSILD_SYSATTRS_TERMS)
else it
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class AttributeHandler(
@RequestParam details: Optional<Boolean>
): ResponseEntity<*> = either {
val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind()
val mediaType = getApplicableMediaType(httpHeaders)
val mediaType = getApplicableMediaType(httpHeaders).bind()
val detailedRepresentation = details.orElse(false)

val availableAttribute: Any = if (detailedRepresentation)
Expand All @@ -46,7 +46,7 @@ class AttributeHandler(
@PathVariable attrId: String
): ResponseEntity<*> = either {
val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind()
val mediaType = getApplicableMediaType(httpHeaders)
val mediaType = getApplicableMediaType(httpHeaders).bind()
val expandedAttribute = JsonLdUtils.expandJsonLdTerm(attrId.decode(), contextLink)

val attributeTypeInfo =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class EntityAccessControlHandler(
val sub = getSubFromSecurityContext()

val contextLink = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind()
val mediaType = getApplicableMediaType(httpHeaders)
val mediaType = getApplicableMediaType(httpHeaders).bind()

val entitiesQuery = composeEntitiesQuery(
applicationProperties.pagination,
Expand All @@ -71,14 +71,16 @@ class EntityAccessControlHandler(

val compactedEntities = JsonLdUtils.compactEntities(
countAndAuthorizedEntities.second,
entitiesQuery.useSimplifiedRepresentation,
entitiesQuery.includeSysAttrs,
contextLink,
mediaType
)

val ngsiLdDataRepresentation = parseRepresentations(
params.getOrDefault(QUERY_PARAM_OPTIONS, emptyList()),
mediaType
)
buildQueryResponse(
compactedEntities,
compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation),
countAndAuthorizedEntities.first,
"/ngsi-ld/v1/entityAccessControl/entities",
entitiesQuery.paginationQuery,
Expand All @@ -99,7 +101,7 @@ class EntityAccessControlHandler(
val sub = getSubFromSecurityContext()

val contextLink = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind()
val mediaType = getApplicableMediaType(httpHeaders)
val mediaType = getApplicableMediaType(httpHeaders).bind()
val entitiesQuery = composeEntitiesQuery(
applicationProperties.pagination,
params,
Expand All @@ -120,14 +122,16 @@ class EntityAccessControlHandler(

val compactedEntities = JsonLdUtils.compactEntities(
countAndGroupEntities.second,
entitiesQuery.useSimplifiedRepresentation,
entitiesQuery.includeSysAttrs,
contextLink,
mediaType
)

val ngsiLdDataRepresentation = parseRepresentations(
params.getOrDefault(QUERY_PARAM_OPTIONS, emptyList()),
mediaType
)
buildQueryResponse(
compactedEntities,
compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation),
countAndGroupEntities.first,
"/ngsi-ld/v1/entityAccessControl/groups",
entitiesQuery.paginationQuery,
Expand All @@ -150,7 +154,7 @@ class EntityAccessControlHandler(
authorizationService.userIsAdmin(sub).bind()

val contextLink = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind()
val mediaType = getApplicableMediaType(httpHeaders)
val mediaType = getApplicableMediaType(httpHeaders).bind()
val entitiesQuery = composeEntitiesQuery(
applicationProperties.pagination,
params,
Expand All @@ -170,14 +174,16 @@ class EntityAccessControlHandler(

val compactedEntities = JsonLdUtils.compactEntities(
countAndUserEntities.second,
entitiesQuery.useSimplifiedRepresentation,
entitiesQuery.includeSysAttrs,
contextLink,
mediaType
)

val ngsiLdDataRepresentation = parseRepresentations(
params.getOrDefault(QUERY_PARAM_OPTIONS, emptyList()),
mediaType
)
buildQueryResponse(
compactedEntities,
compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation),
countAndUserEntities.first,
"/ngsi-ld/v1/entityAccessControl/users",
entitiesQuery.paginationQuery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import com.egm.stellio.shared.util.JsonUtils.serializeObject
import com.egm.stellio.shared.web.BaseHandler
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.MediaType.APPLICATION_JSON_VALUE
import org.springframework.http.ResponseEntity
import org.springframework.util.MultiValueMap
import org.springframework.web.bind.annotation.*
Expand All @@ -43,7 +43,7 @@ class EntityHandler(
/**
* Implements 6.4.3.1 - Create Entity
*/
@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
@PostMapping(consumes = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
suspend fun create(
@RequestHeader httpHeaders: HttpHeaders,
@RequestBody requestBody: Mono<String>
Expand Down Expand Up @@ -81,7 +81,7 @@ class EntityHandler(
/**
* Implements 6.5.3.4 - Merge Entity
*/
@PatchMapping("/{entityId}", consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
@PatchMapping("/{entityId}", consumes = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
suspend fun merge(
@RequestHeader httpHeaders: HttpHeaders,
@PathVariable entityId: URI,
Expand Down Expand Up @@ -135,7 +135,7 @@ class EntityHandler(
/**
* Implements 6.5.3.3 - Replace Entity
*/
@PutMapping("/{entityId}", consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
@PutMapping("/{entityId}", consumes = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
suspend fun replace(
@RequestHeader httpHeaders: HttpHeaders,
@PathVariable entityId: URI,
Expand Down Expand Up @@ -181,12 +181,12 @@ class EntityHandler(
/**
* Implements 6.4.3.2 - Query Entities
*/
@GetMapping(produces = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
@GetMapping(produces = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
suspend fun getEntities(
@RequestHeader httpHeaders: HttpHeaders,
@RequestParam params: MultiValueMap<String, String>
): ResponseEntity<*> = either {
val mediaType = getApplicableMediaType(httpHeaders)
val mediaType = getApplicableMediaType(httpHeaders).bind()
val sub = getSubFromSecurityContext()

val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind()
Expand All @@ -204,14 +204,16 @@ class EntityHandler(

val compactedEntities = JsonLdUtils.compactEntities(
filteredEntities,
entitiesQuery.useSimplifiedRepresentation,
entitiesQuery.includeSysAttrs,
contextLink,
mediaType
)

val ngsiLdDataRepresentation = parseRepresentations(
params.getOrDefault(QUERY_PARAM_OPTIONS, emptyList()),
mediaType
)
buildQueryResponse(
compactedEntities,
compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation),
countAndEntities.second,
"/ngsi-ld/v1/entities",
entitiesQuery.paginationQuery,
Expand All @@ -227,13 +229,13 @@ class EntityHandler(
/**
* Implements 6.5.3.1 - Retrieve Entity
*/
@GetMapping("/{entityId}", produces = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
@GetMapping("/{entityId}", produces = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE, GEO_JSON_CONTENT_TYPE])
suspend fun getByURI(
@RequestHeader httpHeaders: HttpHeaders,
@PathVariable entityId: URI,
@RequestParam params: MultiValueMap<String, String>
): ResponseEntity<*> = either {
val mediaType = getApplicableMediaType(httpHeaders)
val mediaType = getApplicableMediaType(httpHeaders).bind()
val sub = getSubFromSecurityContext()

val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind()
Expand All @@ -255,16 +257,14 @@ class EntityHandler(
JsonLdUtils.filterJsonLdEntityOnAttributes(jsonLdEntity, queryParams.attrs),
jsonLdEntity.contexts
)
val compactedEntity = JsonLdUtils.compact(filteredJsonLdEntity, contextLink, mediaType).toMutableMap()

prepareGetSuccessResponse(mediaType, contextLink).body(
serializeObject(
compactedEntity.toFinalRepresentation(
queryParams.includeSysAttrs,
queryParams.useSimplifiedRepresentation
)
)
val compactedEntity = JsonLdUtils.compactEntity(filteredJsonLdEntity, contextLink, mediaType).toMutableMap()

val ngsiLdDataRepresentation = parseRepresentations(
params.getOrDefault(QUERY_PARAM_OPTIONS, emptyList()),
mediaType
)
prepareGetSuccessResponse(mediaType, contextLink)
.body(serializeObject(compactedEntity.toFinalRepresentation(ngsiLdDataRepresentation)))
}.fold(
{ it.toErrorResponse() },
{ it }
Expand Down Expand Up @@ -302,7 +302,7 @@ class EntityHandler(
* Implements 6.6.3.1 - Append Entity Attributes
*
*/
@PostMapping("/{entityId}/attrs", consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
@PostMapping("/{entityId}/attrs", consumes = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE])
suspend fun appendEntityAttributes(
@RequestHeader httpHeaders: HttpHeaders,
@PathVariable entityId: URI,
Expand Down Expand Up @@ -356,7 +356,7 @@ class EntityHandler(
*/
@PatchMapping(
"/{entityId}/attrs",
consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE, JSON_MERGE_PATCH_CONTENT_TYPE]
consumes = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE, JSON_MERGE_PATCH_CONTENT_TYPE]
)
suspend fun updateEntityAttributes(
@RequestHeader httpHeaders: HttpHeaders,
Expand Down Expand Up @@ -406,7 +406,7 @@ class EntityHandler(
*/
@PatchMapping(
"/{entityId}/attrs/{attrId}",
consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE, JSON_MERGE_PATCH_CONTENT_TYPE]
consumes = [APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE, JSON_MERGE_PATCH_CONTENT_TYPE]
)
suspend fun partialAttributeUpdate(
@RequestHeader httpHeaders: HttpHeaders,
Expand Down
Loading

0 comments on commit 3ccaced

Please sign in to comment.