Skip to content

Commit

Permalink
Merge pull request #186 from catenax-ng/feat/brige_sharing_status_api
Browse files Browse the repository at this point in the history
Bridge sharing status api
  • Loading branch information
nicoprow authored May 24, 2023
2 parents 6650807 + 20b483d commit 7c4ceae
Show file tree
Hide file tree
Showing 5 changed files with 530 additions and 397 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ package com.catenax.bpdm.bridge.dummy.controller

import com.catenax.bpdm.bridge.dummy.service.SyncService
import io.swagger.v3.oas.annotations.Operation
import mu.KotlinLogging
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
Expand All @@ -32,15 +31,11 @@ class BridgeController(
val syncService: SyncService
) {

private val logger = KotlinLogging.logger { }

@Operation(
summary = "Start sync between Gate and Pool"
)
@PostMapping("/sync")
fun triggerSync() {
logger.info("Bridge sync started...")
syncService.sync()
logger.info("Bridge sync completed")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package com.catenax.bpdm.bridge.dummy.service

import com.catenax.bpdm.bridge.dummy.dto.GateAddressInfo
import com.catenax.bpdm.bridge.dummy.dto.GateLegalEntityInfo
import com.catenax.bpdm.bridge.dummy.dto.GateSiteInfo
import mu.KotlinLogging
import org.eclipse.tractusx.bpdm.common.dto.request.PaginationRequest
import org.eclipse.tractusx.bpdm.gate.api.client.GateClient
import org.eclipse.tractusx.bpdm.gate.api.model.AddressGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.LegalEntityGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.request.PaginationStartAfterRequest
import org.eclipse.tractusx.bpdm.gate.api.model.response.LsaType
import org.springframework.stereotype.Service
import java.time.Instant

@Service
class GateQueryService(
val gateClient: GateClient
) {

private val logger = KotlinLogging.logger { }

fun getChangedExternalIdsByLsaType(modifiedAfter: Instant?): Map<LsaType, Set<String>> {
// TODO use pagination properly
val entriesGate = gateClient.changelog().getChangelogEntriesLsaType(
lsaType = null,
fromTime = modifiedAfter,
paginationRequest = PaginationRequest(0, 100)
)

return entriesGate.content
.groupBy { it.businessPartnerType }
.mapValues { (_, list) -> list.map { it.externalId }.toSet() }
.also {
logger.info {
"Changed entries in Gate since last sync: " +
"${it[LsaType.LegalEntity]?.size ?: 0} legal entities, " +
"${it[LsaType.Site]?.size ?: 0} sites, " +
"${it[LsaType.Address]?.size ?: 0} addresses"
}
}
}

fun getLegalEntityInfos(externalIds: Set<String>): Collection<GateLegalEntityInfo> {
val entries = getLegalEntitiesInput(externalIds)
val bpnByExternalId = getBpnByExternalId(LsaType.LegalEntity, externalIds)

return entries.map {
GateLegalEntityInfo(
legalEntity = it.legalEntity,
externalId = it.externalId,
bpn = bpnByExternalId[it.externalId]
)
}
}

fun getSiteInfos(externalIds: Set<String>): Collection<GateSiteInfo> {
val entries = getSitesInput(externalIds)
val bpnByExternalId = getBpnByExternalId(LsaType.Site, externalIds)

return entries.map {
GateSiteInfo(
site = it.site,
externalId = it.externalId,
legalEntityExternalId = it.legalEntityExternalId,
bpn = bpnByExternalId[it.externalId]
)
}
}

fun getAddressInfos(externalIds: Set<String>): Collection<GateAddressInfo> {
val entries = getAddressesInput(externalIds)
val bpnByExternalId = getBpnByExternalId(LsaType.Address, externalIds)

return entries.map {
GateAddressInfo(
address = it.address,
externalId = it.externalId,
legalEntityExternalId = it.legalEntityExternalId,
siteExternalId = it.siteExternalId,
bpn = bpnByExternalId[it.externalId]
)
}
}

fun getBpnByExternalId(lsaType: LsaType, externalIds: Set<String>): Map<String, String> {
if (externalIds.isEmpty()) {
return emptyMap()
}
// TODO use pagination properly
val page = gateClient.sharingState().getSharingStates(
lsaType = lsaType,
externalIds = externalIds,
paginationRequest = PaginationRequest(0, 100)
)
return page.content
.associateBy { it.externalId }
.filter { it.value.bpn != null }
.mapValues { it.value.bpn!! }
}

private fun getLegalEntitiesInput(externalIds: Set<String>): Collection<LegalEntityGateInputResponse> {
if (externalIds.isEmpty()) {
return emptyList()
}
// TODO use pagination properly
val response = gateClient.legalEntities().getLegalEntitiesByExternalIds(
externalIds = externalIds,
paginationRequest = PaginationStartAfterRequest(null, 100)
)
logger.info { "Gate returned ${response.content.size} valid legal entities, ${response.invalidEntries} were invalid" }
return response.content
}

private fun getSitesInput(externalIds: Set<String>): Collection<SiteGateInputResponse> {
if (externalIds.isEmpty()) {
return emptyList()
}
// TODO use pagination properly
val response = gateClient.sites().getSitesByExternalIds(
externalIds = externalIds,
paginationRequest = PaginationStartAfterRequest(null, 100)
)
logger.info { "Gate returned ${response.content.size} valid sites, ${response.invalidEntries} were invalid" }
return response.content
}

private fun getAddressesInput(externalIds: Set<String>): Collection<AddressGateInputResponse> {
if (externalIds.isEmpty()) {
return emptyList()
}
// TODO use pagination properly
val response = gateClient.addresses().getAddressesByExternalIds(
externalIds = externalIds,
paginationRequest = PaginationStartAfterRequest(null, 100)
)
logger.info { "Gate returned ${response.content.size} valid addresses, ${response.invalidEntries} were invalid" }
return response.content
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package com.catenax.bpdm.bridge.dummy.service

import mu.KotlinLogging
import org.eclipse.tractusx.bpdm.gate.api.client.GateClient
import org.eclipse.tractusx.bpdm.gate.api.exception.BusinessPartnerSharingError
import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateDto
import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType
import org.eclipse.tractusx.bpdm.gate.api.model.response.LsaType
import org.eclipse.tractusx.bpdm.pool.api.model.response.*
import org.springframework.stereotype.Service
import java.time.LocalDateTime

@Service
class GateUpdateService(
val gateClient: GateClient
) {

private val logger = KotlinLogging.logger { }

fun handleLegalEntityCreateResponse(
responseWrapper: LegalEntityPartnerCreateResponseWrapper
) {
for (entity in responseWrapper.entities) {
val externalId = entity.index
buildSuccessSharingStateDto(LsaType.LegalEntity, externalId, entity.legalEntity.bpn, true)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
for (errorInfo in responseWrapper.errors) {
val externalId = errorInfo.entityKey
buildErrorSharingStateDto(LsaType.LegalEntity, externalId, null, errorInfo, true)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
logger.info { "Sharing states for ${responseWrapper.entityCount} valid and ${responseWrapper.errorCount} invalid new legal entities were updated in the Gate" }
}

fun handleLegalEntityUpdateResponse(
responseWrapper: LegalEntityPartnerUpdateResponseWrapper,
externalIdByBpn: Map<String, String>
) {
for (entity in responseWrapper.entities) {
val bpn = entity.legalEntity.bpn
val externalId = externalIdByBpn[bpn]
buildSuccessSharingStateDto(LsaType.LegalEntity, externalId, bpn, false)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
for (errorInfo in responseWrapper.errors) {
val bpn = errorInfo.entityKey
val externalId = externalIdByBpn[bpn]
buildErrorSharingStateDto(LsaType.LegalEntity, externalId, bpn, errorInfo, false)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
logger.info { "Sharing states for ${responseWrapper.entityCount} valid and ${responseWrapper.errorCount} invalid modified legal entities were updated in the Gate" }
}

fun handleSiteCreateResponse(
responseWrapper: SitePartnerCreateResponseWrapper
) {
for (entity in responseWrapper.entities) {
val externalId = entity.index
buildSuccessSharingStateDto(LsaType.Site, externalId, entity.site.bpn, true)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
for (errorInfo in responseWrapper.errors) {
val externalId = errorInfo.entityKey
buildErrorSharingStateDto(LsaType.Site, externalId, null, errorInfo, true)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
logger.info { "Sharing states for ${responseWrapper.entityCount} valid and ${responseWrapper.errorCount} invalid new sites were updated in the Gate" }
}

fun handleSiteUpdateResponse(
responseWrapper: SitePartnerUpdateResponseWrapper,
externalIdByBpn: Map<String, String>
) {
for (entity in responseWrapper.entities) {
val bpn = entity.site.bpn
val externalId = externalIdByBpn[bpn]
buildSuccessSharingStateDto(LsaType.Site, externalId, bpn, false)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
for (errorInfo in responseWrapper.errors) {
val bpn = errorInfo.entityKey
val externalId = externalIdByBpn[bpn]
buildErrorSharingStateDto(LsaType.Site, externalId, bpn, errorInfo, false)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
logger.info { "Sharing states for ${responseWrapper.entityCount} valid and ${responseWrapper.errorCount} invalid modified sites were updated in the Gate" }
}

fun handleAddressCreateResponse(
responseWrapper: AddressPartnerCreateResponseWrapper
) {
for (entity in responseWrapper.entities) {
val externalId = entity.index
buildSuccessSharingStateDto(LsaType.Address, externalId, entity.address.bpn, true)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
for (errorInfo in responseWrapper.errors) {
val externalId = errorInfo.entityKey
buildErrorSharingStateDto(LsaType.Address, externalId, null, errorInfo, true)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
logger.info { "Sharing states for ${responseWrapper.entityCount} valid and ${responseWrapper.errorCount} invalid new addresses were updated in the Gate" }
}

fun handleAddressUpdateResponse(
responseWrapper: AddressPartnerUpdateResponseWrapper,
externalIdByBpn: Map<String, String>
) {
for (entity in responseWrapper.entities) {
val bpn = entity.bpn
val externalId = externalIdByBpn[bpn]
buildSuccessSharingStateDto(LsaType.Address, externalId, bpn, false)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
for (errorInfo in responseWrapper.errors) {
val bpn = errorInfo.entityKey
val externalId = externalIdByBpn[bpn]
buildErrorSharingStateDto(LsaType.Address, externalId, bpn, errorInfo, false)
?.let { gateClient.sharingState().upsertSharingState(it) }
}
logger.info { "Sharing states for ${responseWrapper.entityCount} valid and ${responseWrapper.errorCount} invalid modified addresses were updated in the Gate" }
}

private fun buildSuccessSharingStateDto(lsaType: LsaType, externalId: String?, bpn: String, processStarted: Boolean): SharingStateDto? {
if (externalId == null) {
logger.warn { "Encountered externalId=null in Pool response for $bpn, can't update the Gate sharing state" }
return null
}
return SharingStateDto(
lsaType = lsaType,
externalId = externalId,
sharingStateType = SharingStateType.Success,
bpn = bpn,
sharingProcessStarted = if (processStarted) LocalDateTime.now() else null
)
}

private fun buildErrorSharingStateDto(
lsaType: LsaType,
externalId: String?,
bpn: String?,
errorInfo: ErrorInfo<*>,
processStarted: Boolean
): SharingStateDto? {
if (externalId == null) {
logger.warn { "Couldn't determine externalId for $errorInfo, can't update the Gate sharing state" }
return null
}
return SharingStateDto(
lsaType = lsaType,
externalId = externalId,
sharingStateType = SharingStateType.Error,
bpn = bpn,
sharingErrorCode = BusinessPartnerSharingError.SharingProcessError,
sharingErrorMessage = "${errorInfo.message} (${errorInfo.errorCode})",
sharingProcessStarted = if (processStarted) LocalDateTime.now() else null
)
}

}
Loading

0 comments on commit 7c4ceae

Please sign in to comment.