Skip to content

Commit

Permalink
feat(Orchestrator): add persistence layer
Browse files Browse the repository at this point in the history
- add jpa entity model
- adapted tests to use entity model where appropriate and setup a test database
- added a postgres dependency to the Orchestrator chart
  • Loading branch information
nicoprow committed Jul 8, 2024
1 parent e4cc1be commit d6e4cf3
Show file tree
Hide file tree
Showing 34 changed files with 1,577 additions and 301 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ For changes to the BPDM Helm charts please consult the [changelog](charts/bpdm/C
- BPDM Gate: Post endpoint to upload business partner input data using csv file.(#700)
- BPDM Gate: GET endpoint to download the csv file template for business partner upload. (#700)
- Apps: Tax Jurisdiction Code to the physical address of a business partner (#955)
- BPDM Orchestrator: Tasks will now be persisted

### Changed:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class DbTestHelpers(private val entityManagerFactory: EntityManagerFactory?) {
truncateDbTablesFromSchema("bpdm")
truncateDbTablesFromSchema("bpdmgate")
truncateDbTablesFromSchema("bpdm-bridge-dummy")
truncateDbTablesFromSchema("bpdm-orchestrator")
}

private fun truncateDbTablesFromSchema(dbSchemaName: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ fun <T> MutableCollection<T>.replace(elements: Collection<T>) {
addAll(elements)
}

fun <K, V> MutableMap<K, V>.replace(map: Map<K, V>) {
clear()
putAll(map)
}


/**
* Copy overlapping elements by index from [elements] to [this] collection by applying the [copyFunction].
Expand Down
14 changes: 14 additions & 0 deletions bpdm-orchestrator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Manage database migrations -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>

<!-- Test -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@
package org.eclipse.tractusx.bpdm.orchestrator

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.runApplication
import org.springframework.scheduling.annotation.EnableScheduling


@SpringBootApplication(exclude = [DataSourceAutoConfiguration::class])
@SpringBootApplication
@ConfigurationPropertiesScan
@EnableScheduling
class Application
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2021,2024 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 org.eclipse.tractusx.bpdm.orchestrator.entity

import jakarta.persistence.Column
import jakarta.persistence.Embeddable
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated
import org.eclipse.tractusx.orchestrator.api.model.BpnReferenceType

@Embeddable
data class BpnReferenceDb(
@Column(name = "value")
val referenceValue: String?,
@Column(name = "desired_bpn")
val desiredBpn: String?,
@Enumerated(EnumType.STRING)
@Column(name = "type")
val referenceType: BpnReferenceType?
) {
enum class Scope {
LegalEntity,
Site,
LegalAddress,
SiteMainAddress,
AdditionalAddress,
UncategorizedAddress
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*******************************************************************************
* Copyright (c) 2021,2024 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 org.eclipse.tractusx.bpdm.orchestrator.entity

import jakarta.persistence.Column
import jakarta.persistence.Embeddable
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated
import org.eclipse.tractusx.bpdm.common.model.BusinessStateType
import java.time.Instant

@Embeddable
data class BusinessStateDb(
@Column(name = "valid_from")
val validFrom: Instant?,
@Column(name = "valid_to")
val validTo: Instant?,
@Enumerated(EnumType.STRING)
@Column(name = "type")
val type: BusinessStateType?,
@Enumerated(EnumType.STRING)
@Column(name = "scope", nullable = false)
val scope: Scope
) {
enum class Scope {
LegalEntity,
Site,
Uncategorized,
LegalAddress,
SiteMainAddress,
AdditionalAddress,
UncategorizedAddress
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright (c) 2021,2024 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 org.eclipse.tractusx.bpdm.orchestrator.entity

import jakarta.persistence.Column
import jakarta.persistence.Embeddable
import java.time.Instant

@Embeddable
data class ConfidenceCriteriaDb(
@Column(name = "shared_by_owner")
val sharedByOwner: Boolean?,
@Column(name = "checked_by_external_datasource")
val checkedByExternalDataSource: Boolean?,
@Column(name = "number_of_sharing_members")
val numberOfSharingMembers: Int?,
@Column(name = "last_confidence_check")
val lastConfidenceCheckAt: Instant?,
@Column(name = "next_confidence_check")
val nextConfidenceCheckAt: Instant?,
@Column(name = "confidence_level")
val confidenceLevel: Int?
) {
enum class Scope {
LegalEntity,
Site,
LegalAddress,
SiteMainAddress,
AdditionalAddress,
UncategorizedAddress
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*******************************************************************************
* Copyright (c) 2021,2024 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 org.eclipse.tractusx.bpdm.orchestrator.entity

import jakarta.persistence.*
import org.eclipse.tractusx.bpdm.common.util.replace
import org.eclipse.tractusx.orchestrator.api.model.*
import java.time.Instant
import java.util.*

@Entity
@Table(
name = "golden_record_tasks",
indexes = [
Index(name = "index_tasks_uuid", columnList = "uuid"),
Index(name = "index_tasks_step_step_state", columnList = "task_step,task_step_state"),
Index(name = "index_tasks_pending_timeout", columnList = "task_pending_timeout"),
Index(name = "index_tasks_retention_timeout", columnList = "task_retention_timeout")
]
)
class GoldenRecordTaskDb(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "bpdm_sequence")
@SequenceGenerator(name = "bpdm_sequence", sequenceName = "bpdm_sequence", allocationSize = 1)
@Column(name = "id", nullable = false, updatable = false, insertable = false)
val id: Long = 0,

@Column(name = "uuid", nullable = false, updatable = false, unique = true, columnDefinition = "uuid")
val uuid: UUID = UUID.randomUUID(),

@Column(updatable = false, nullable = false, name = "CREATED_AT")
var createdAt: Instant = Instant.now(),

@Column(nullable = false, name = "UPDATED_AT")
var updatedAt: Instant = createdAt,
@Embedded
val processingState: ProcessingState,
@Embedded
val businessPartner: BusinessPartner
) {
fun updateBusinessPartner(newBusinessPartnerData: BusinessPartner){
with(newBusinessPartnerData){
//Trick to make sure on a change to the business partner model
// we get a compile error if we don't also adjust this update method
// We discard the created business partner object afterward, it is just there for this check
BusinessPartner(
nameParts = nameParts.also { businessPartner.nameParts.replace(it) },
identifiers = identifiers.also { businessPartner.identifiers.replace(it) },
businessStates = businessStates.also { businessPartner.businessStates.replace(it) },
confidences = confidences.also { businessPartner.confidences.replace(it) },
addresses = addresses.also { businessPartner.addresses.replace(it) },
bpnReferences = bpnReferences.also { businessPartner.bpnReferences.replace(it) },
legalName = legalName.also { businessPartner.legalName = it },
legalShortName = legalShortName.also { businessPartner.legalShortName = it },
siteExists = siteExists.also { businessPartner.siteExists = it },
siteName = siteName.also { businessPartner.siteName = it },
legalForm = legalForm.also { businessPartner.legalForm = it },
isCatenaXMemberData = isCatenaXMemberData.also { businessPartner.isCatenaXMemberData = it },
owningCompany = owningCompany.also { businessPartner.owningCompany = it },
legalEntityHasChanged = legalEntityHasChanged.also { businessPartner.legalEntityHasChanged = it },
siteHasChanged = siteHasChanged.also { businessPartner.siteHasChanged = it }
)
}
}

@Embeddable
class ProcessingState(
@Enumerated(EnumType.STRING)
@Column(name = "task_mode", nullable = false)
var mode: TaskMode,
@Enumerated(EnumType.STRING)
@Column(name = "task_result_state", nullable = false)
var resultState: ResultState,
@ElementCollection
@CollectionTable(name = "task_errors", joinColumns = [JoinColumn(name = "task_id", foreignKey = ForeignKey(name = "fk_errors_tasks"))])
val errors: MutableList<TaskErrorDb>,
@Enumerated(EnumType.STRING)
@Column(name = "task_step", nullable = false)
var step: TaskStep,
@Enumerated(EnumType.STRING)
@Column(name = "task_step_state", nullable = false)
var stepState: StepState,
@Column(name = "task_pending_timeout")
var pendingTimeout: Instant?,
@Column(name = "task_retention_timeout")
var retentionTimeout: Instant?
)

@Embeddable
class BusinessPartner(
@ElementCollection(fetch = FetchType.EAGER)
@OrderColumn(name = "index", nullable = false)
@CollectionTable(
name = "business_partner_name_parts",
joinColumns = [JoinColumn(name = "task_id", foreignKey = ForeignKey(name = "fk_name_parts_tasks"))]
)
val nameParts: MutableList<NamePartDb>,
@ElementCollection(fetch = FetchType.EAGER)
@OrderColumn(name = "index", nullable = false)
@CollectionTable(
name = "business_partner_identifiers",
joinColumns = [JoinColumn(name = "task_id", foreignKey = ForeignKey(name = "fk_identifiers_tasks"))]
)
val identifiers: MutableList<IdentifierDb>,
@ElementCollection(fetch = FetchType.EAGER)
@OrderColumn(name = "index", nullable = false)
@CollectionTable(
name = "business_partner_states",
joinColumns = [JoinColumn(name = "task_id", foreignKey = ForeignKey(name = "fk_states_tasks"))]
)
val businessStates: MutableList<BusinessStateDb>,
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "scope")
@MapKeyEnumerated(EnumType.STRING)
@CollectionTable(
name = "business_partner_confidences",
joinColumns = [JoinColumn(name = "task_id", foreignKey = ForeignKey(name = "fk_confidences_tasks"))],
uniqueConstraints = [UniqueConstraint(name = "uc_business_partner_confidences_task_scope", columnNames = ["task_id", "scope"])]
)
val confidences: MutableMap<ConfidenceCriteriaDb.Scope, ConfidenceCriteriaDb>,
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "scope")
@MapKeyEnumerated(EnumType.STRING)
@CollectionTable(
name = "business_partner_addresses",
joinColumns = [JoinColumn(name = "task_id", foreignKey = ForeignKey(name = "fk_addresses_tasks"))],
uniqueConstraints = [UniqueConstraint(name = "uc_business_partner_addresses_task_scope", columnNames = ["task_id", "scope"])]
)
val addresses: MutableMap<PostalAddressDb.Scope, PostalAddressDb>,
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "scope")
@MapKeyEnumerated(EnumType.STRING)
@CollectionTable(
name = "business_partner_bpn_references",
joinColumns = [JoinColumn(name = "task_id", foreignKey = ForeignKey(name = "fk_bpn_references_tasks"))],
uniqueConstraints = [UniqueConstraint(name = "uc_business_partner_bpn_references_task_scope", columnNames = ["task_id", "scope"])]
)
val bpnReferences: MutableMap<BpnReferenceDb.Scope, BpnReferenceDb>,
@Column(name = "legal_name")
var legalName: String?,
@Column(name = "legal_short_name")
var legalShortName: String?,
@Column(name = "site_exists", nullable = false)
var siteExists: Boolean,
@Column(name = "site_name")
var siteName: String?,
@Column(name = "legal_form")
var legalForm: String?,
@Column(name = "is_cx_member")
var isCatenaXMemberData: Boolean?,
@Column(name = "owning_company_bpnl")
var owningCompany: String?,
@Column(name = "legal_entity_has_changed")
var legalEntityHasChanged: Boolean?,
@Column(name = "site_has_changed")
var siteHasChanged: Boolean?
)

}
Loading

0 comments on commit d6e4cf3

Please sign in to comment.