Skip to content

Commit

Permalink
Merge pull request #157 from catenax-ng/main
Browse files Browse the repository at this point in the history
Update to DTR Client Lib, BOM lifecycle asSpecified
  • Loading branch information
ds-jhartmann authored Aug 25, 2023
2 parents 8bd8e05 + 722171c commit f04fa78
Show file tree
Hide file tree
Showing 20 changed files with 269 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Added fetchCatalog to EDCCatalogFacade

## [3.3.4] - 2023-08-24
### Fixed
Expand Down
2 changes: 1 addition & 1 deletion DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ maven/mavencentral/org.eclipse.tractusx.irs/irs-edc-client/0.0.2-SNAPSHOT, Apach
maven/mavencentral/org.eclipse.tractusx.irs/irs-ess/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx.irs/irs-models/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx.irs/irs-policy-store/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx.irs/irs-registry-client/1.1.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx.irs/irs-registry-client/1.1.1-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.glassfish/jakarta.json/2.0.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jsonp
maven/mavencentral/org.graalvm.sdk/graal-sdk/23.0.1, UPL-1.0, approved, #9850
maven/mavencentral/org.hamcrest/hamcrest-core/2.2, BSD-3-Clause, approved, clearlydefined
Expand Down
5 changes: 5 additions & 0 deletions docs/src/api/irs-v1.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,7 @@ components:
enum:
- asBuilt
- asPlanned
- asSpecified
bpn:
type: string
callbackUrl:
Expand Down Expand Up @@ -1934,6 +1935,7 @@ components:
enum:
- asBuilt
- asPlanned
- asSpecified
quantity:
$ref: '#/components/schemas/Quantity'
MeasurementUnit:
Expand Down Expand Up @@ -2095,6 +2097,7 @@ components:
enum:
- asBuilt
- asPlanned
- asSpecified
callbackUrl:
type: string
description: "Callback url to notify requestor when job processing is finished.\
Expand Down Expand Up @@ -2157,6 +2160,7 @@ components:
enum:
- asBuilt
- asPlanned
- asSpecified
callbackUrl:
type: string
description: "Callback url to notify requestor when job processing is finished.\
Expand Down Expand Up @@ -2190,6 +2194,7 @@ components:
enum:
- asBuilt
- asPlanned
- asSpecified
callbackUrl:
type: string
description: "Callback url to notify requestor when job processing is finished.\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.tractusx.irs.component.Bpn;
import org.eclipse.tractusx.irs.component.Relationship;
import org.eclipse.tractusx.irs.component.Submodel;
Expand Down Expand Up @@ -64,7 +65,7 @@ public class ItemTreesAssembler {
tombstones.addAll(itemGraph.getTombstones());
shells.addAll(itemGraph.getShells());
submodels.addAll(itemGraph.getSubmodels());
bpns.addAll(itemGraph.getBpns());
bpns.addAll(itemGraph.getBpns().stream().filter(bpn -> StringUtils.isNotBlank(bpn.getManufacturerName())).toList());
});

log.info("Assembled item graph from {} partial graphs", numberOfPartialTrees);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private void processEndpoint(final Endpoint endpoint, final RelationshipAspect r
}

private static List<Bpn> getBpnsFrom(final List<Relationship> relationships) {
return relationships.stream().map(Relationship::getBpn).map(Bpn::withManufacturerId).toList();
return relationships.stream().map(Relationship::getBpn).filter(StringUtils::isNotBlank).map(Bpn::withManufacturerId).toList();
}

private List<PartChainIdentificationKey> getIdsToProcess(final List<Relationship> relationships,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ public List<AspectModel> getAllAspectModels() {
"EsrCertificate", MODEL_TYPE, MODEL_STATUS),
new AspectModel("urn:bamm:io.catenax.single_level_bom_as_built:1.0.0#SingleLevelBomAsBuilt",
"1.0.0", "SingleLevelBomAsBuilt", MODEL_TYPE, MODEL_STATUS),
new AspectModel("urn:bamm:io.catenax.part_as_specified:2.0.0#PartAsSpecified",
"2.0.0", "PartAsSpecified", MODEL_TYPE, MODEL_STATUS),
new AspectModel("urn:bamm:io.catenax.part_as_planned:1.0.1#PartAsPlanned",
"1.0.1", "PartAsPlanned", MODEL_TYPE, MODEL_STATUS));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,9 @@ public JobHandle registerItemJob(final @NonNull RegisterJob request) {

public JobHandle registerItemJob(final @NonNull RegisterJob request, final UUID batchId) {
final var params = buildJobParameter(request);
if (params.getBomLifecycle().equals(BomLifecycle.AS_PLANNED) && params.getDirection()
.equals(Direction.UPWARD)) {
if (params.getDirection().equals(Direction.UPWARD) && !params.getBomLifecycle().equals(BomLifecycle.AS_BUILT)) {
// Currently not supported variant
throw new IllegalArgumentException("BomLifecycle asPlanned with direction upward is not supported yet!");
throw new IllegalArgumentException("Upward direction is supported only for asBuilt bomLifecycle parameter!");
}
if (params.isLookupBPNs() && StringUtils.isBlank(bpdmUrl)) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ void shouldStartJobAndRetrieveResult() {
assertThat(finishedJob.get().getShells()).isNotEmpty();
assertThat(finishedJob.get().getTombstones()).isEmpty();
assertThat(finishedJob.get().getSubmodels()).isEmpty();
assertThat(finishedJob.get().getBpns()).isNotEmpty();
assertThat(finishedJob.get().getBpns()).isEmpty();
assertThat(finishedJob.get().getJob()).isNotNull();
assertThat(finishedJob.get().getJob().getSummary()).isNotNull();
assertThat(finishedJob.get().getJob().getParameter()).isNotNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,16 @@ void shouldThrowIllegalArgumentExceptionForLifecycleAsPlannedAndDirectionUpward(
assertThrows(IllegalArgumentException.class, () -> service.registerItemJob(registerJob));
}

@Test
void shouldThrowIllegalArgumentExceptionForLifecycleAsSpecifiedAndDirectionUpward() {
final RegisterJob registerJob = new RegisterJob();
registerJob.setKey(PartChainIdentificationKey.builder().globalAssetId(UUID.randomUUID().toString()).build());
registerJob.setDirection(Direction.UPWARD);
registerJob.setBomLifecycle(BomLifecycle.AS_SPECIFIED);

assertThrows(IllegalArgumentException.class, () -> service.registerItemJob(registerJob));
}

private int getRelationshipsSize(final UUID jobId) {
return service.getJobForJobId(jobId, false).getRelationships().size();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.edc.catalog.spi.Catalog;
import org.eclipse.edc.catalog.spi.CatalogRequest;
import org.eclipse.edc.catalog.spi.Dataset;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.tractusx.irs.edc.client.configuration.JsonLdConfiguration;
import org.eclipse.tractusx.irs.edc.client.model.CatalogItem;

import org.springframework.stereotype.Component;

/**
Expand Down Expand Up @@ -74,6 +76,19 @@ private static CatalogItem createCatalogItem(final Catalog pageableCatalog, fina
return builder.build();
}

/**
* Fetches a list of {@link CatalogItem} objects based on the given {@link CatalogRequest}.
* This method communicates with the control plane client to retrieve the catalog
* and maps it to a list of catalog items.
*
* @param catalogRequest The request containing the parameters needed to fetch the catalog.
* @return A list of {@link CatalogItem} objects representing the items in the catalog.
*/
public List<CatalogItem> fetchCatalogItems(final CatalogRequest catalogRequest) {
final Catalog catalog = controlPlaneClient.getCatalog(catalogRequest);
return mapToCatalogItems(catalog);
}

private static List<CatalogItem> mapToCatalogItems(final Catalog catalog) {
if (catalog.getDatasets() == null) {
return List.of();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public enum RelationshipAspect {
Direction.DOWNWARD),
SINGLE_LEVEL_BOM_AS_BUILT("SingleLevelBomAsBuilt", SingleLevelBomAsBuilt.class, BomLifecycle.AS_BUILT,
Direction.DOWNWARD),
SINGLE_LEVEL_BOM_AS_SPECIFIED("SingleLevelBomAsSpecified", SingleLevelBomAsSpecified.class, BomLifecycle.AS_SPECIFIED,
Direction.DOWNWARD),
SINGLE_LEVEL_USAGE_AS_BUILT("SingleLevelUsageAsBuilt", SingleLevelUsageAsBuilt.class, BomLifecycle.AS_BUILT,
Direction.UPWARD);

Expand All @@ -56,6 +58,7 @@ public enum RelationshipAspect {
* @return Returns traversal aspect type
* asBuilt + downward => SingleLevelBomAsBuilt
* asPlanned + downward => SingleLevelBomAsPlanned
* asSpecified + downward => SingleLevelBomAsSpecified
* asBuilt + upward => SingleLevelUsageAsBuilt
* asPlanned + upward => SingleLevelXXXAsPlanned
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/********************************************************************************
* Copyright (c) 2021,2022,2023
* 2022: ZF Friedrichshafen AG
* 2022: ISTOS GmbH
* 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* 2022,2023: BOSCH AG
* Copyright (c) 2021,2022,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 org.eclipse.tractusx.irs.edc.client;

import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.jackson.Jacksonized;
import org.eclipse.tractusx.irs.component.GlobalAssetIdentification;
import org.eclipse.tractusx.irs.component.LinkedItem;
import org.eclipse.tractusx.irs.component.MeasurementUnit;
import org.eclipse.tractusx.irs.component.Quantity;
import org.eclipse.tractusx.irs.component.Relationship;
import org.eclipse.tractusx.irs.component.enums.AspectType;
import org.eclipse.tractusx.irs.component.enums.BomLifecycle;

/**
* SingleLevelBomAsSpecified
*/
@Data
@Jacksonized
@AllArgsConstructor
@NoArgsConstructor
public class SingleLevelBomAsSpecified implements RelationshipSubmodel {

private String catenaXId;
private Set<SingleLevelBomAsSpecified.ChildData> childParts;

@Override
public List<Relationship> asRelationships() {
return Optional.ofNullable(this.childParts).stream().flatMap(Collection::stream)
.map(childData -> childData.toRelationship(this.catenaXId))
.toList();
}

/**
* ChildData
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
/* package */ static class ChildData {

private String childPartsCategory;
private Set<Part> part;
private String childCatenaXId;
private String businessPartner;

public Relationship toRelationship(final String catenaXId) {
final Part childPart = this.part.stream().findFirst().orElse(new Part());

final LinkedItem.LinkedItemBuilder linkedItem = LinkedItem.builder()
.childCatenaXId(GlobalAssetIdentification.of(this.childCatenaXId))
.lifecycleContext(BomLifecycle.AS_SPECIFIED)
.assembledOn(childPart.getCreatedOn())
.lastModifiedOn(childPart.getLastModifiedOn());

if (childPart.getPartQuantity() != null) {
linkedItem.quantity(Quantity.builder()
.quantityNumber(childPart.getPartQuantity().getQuantityNumber())
.measurementUnit(MeasurementUnit.builder().lexicalValue(childPart.getPartQuantity().getMeasurementUnit()).build())
.build());
}

return Relationship.builder()
.catenaXId(GlobalAssetIdentification.of(catenaXId))
.linkedItem(linkedItem.build())
.bpn(this.businessPartner)
.aspectType(AspectType.SINGLE_LEVEL_BOM_AS_SPECIFIED.toString())
.build();
}

/**
* Part
*/
@Data
@Jacksonized
@SuppressWarnings("PMD.ShortClassName")
/* package */ static class Part {

private String ownerPartId;
private String partVersion;
private PartQuantity partQuantity;
private String partDescription;
private ZonedDateTime createdOn;
private ZonedDateTime lastModifiedOn;

/**
* Part Quantity
*/
@Data
@Jacksonized
/* package */ static class PartQuantity {
private Double quantityNumber;
private String measurementUnit;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public Map<String, Object> createSubmodelForId(final String endpointAddress) {
return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSingleLevelBomAsBuilt).orElse(Map.of());
} else if (endpointAddress.contains("singleLevelUsageAsBuilt")) {
return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSingleLevelUsageAsBuilt).orElse(Map.of());
} else if (endpointAddress.contains("singleLevelBomAsSpecified")) {
return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSingleLevelBomAsSpecified).orElse(Map.of());
} else if (endpointAddress.contains("serialPart")) {
return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSerialPart).orElse(Map.of());
} else if (endpointAddress.contains("singleLevelBomAsPlanned")) {
Expand All @@ -72,6 +74,8 @@ public Map<String, Object> createSubmodelForId(final String endpointAddress) {
return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getProductDescription).orElse(Map.of());
} else if (endpointAddress.contains("physicalDimension")) {
return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getPhysicalDimension).orElse(Map.of());
} else if (endpointAddress.contains("partAsSpecified")) {
return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getPartAsSpecified).orElse(Map.of());
}
return Map.of();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
import org.eclipse.tractusx.irs.component.enums.Direction;
import org.eclipse.tractusx.irs.data.StringMapper;
import org.eclipse.tractusx.irs.edc.client.exceptions.ContractNegotiationException;
import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException;
import org.eclipse.tractusx.irs.edc.client.exceptions.TimeoutException;
import org.eclipse.tractusx.irs.edc.client.exceptions.TransferProcessException;
import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyException;
Expand Down Expand Up @@ -223,6 +222,19 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsPlan
assertThat(submodelResponse).contains("urn:uuid:e5c96ab5-896a-482c-8761-efd74777ca97");
}

@Test
void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsSpecified() throws Exception {
final String catenaXId = "urn:uuid:ed333e9a-5afa-40b2-99da-bae2fd21501e";
when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn(
List.of(CatalogItem.builder().itemId(catenaXId).build()));
prepareTestdata(catenaXId, "_singleLevelBomAsSpecified");

final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID)
.get(5, TimeUnit.SECONDS);

assertThat(submodelResponse).contains("urn:uuid:7eeeac86-7b69-444d-81e6-655d0f1513bd");
}

@Test
void shouldReturnEmptyRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelUsageAsBuilt() throws Exception {
final String catenaXId = "urn:uuid:61c83b41-def0-4742-a1a8-e4e8a8cb210e";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ public enum AspectType {
MATERIAL_FOR_HOMOLOGATION(AspectTypesConstants.MATERIAL_FOR_HOMOLOGATION),
MATERIAL_FOR_RECYCLING(AspectTypesConstants.MATERIAL_FOR_RECYCLING),
PART_AS_PLANNED(AspectTypesConstants.PART_AS_PLANNED),
PART_AS_SPECIFIED(AspectTypesConstants.PART_AS_SPECIFIED),
PHYSICAL_DIMENSION(AspectTypesConstants.PHYSICAL_DIMENSION),
PRODUCT_DESCRIPTION(AspectTypesConstants.PRODUCT_DESCRIPTION),
RETURN_REQUEST(AspectTypesConstants.RETURN_REQUEST),
SERIAL_PART(AspectTypesConstants.SERIAL_PART),
SINGLE_LEVEL_BOM_AS_BUILT(AspectTypesConstants.SINGLE_LEVEL_BOM_AS_BUILT),
SINGLE_LEVEL_BOM_AS_PLANNED(AspectTypesConstants.SINGLE_LEVEL_BOM_AS_PLANNED),
SINGLE_LEVEL_BOM_AS_SPECIFIED(AspectTypesConstants.SINGLE_LEVEL_BOM_AS_SPECIFIED),
SINGLE_LEVEL_USAGE_AS_BUILT(AspectTypesConstants.SINGLE_LEVEL_USAGE_AS_BUILT);

private final String name;
Expand Down Expand Up @@ -120,12 +122,14 @@ public static final class AspectTypesConstants {
public static final String MATERIAL_FOR_HOMOLOGATION = "MaterialForHomologation";
public static final String MATERIAL_FOR_RECYCLING = "MaterialForRecycling";
public static final String PART_AS_PLANNED = "PartAsPlanned";
public static final String PART_AS_SPECIFIED = "PartAsSpecified";
public static final String PHYSICAL_DIMENSION = "PhysicalDimension";
public static final String PRODUCT_DESCRIPTION = "ProductDescription";
public static final String RETURN_REQUEST = "ReturnRequest";
public static final String SERIAL_PART = "SerialPart";
public static final String SINGLE_LEVEL_BOM_AS_BUILT = "SingleLevelBomAsBuilt";
public static final String SINGLE_LEVEL_BOM_AS_PLANNED = "SingleLevelBomAsPlanned";
public static final String SINGLE_LEVEL_BOM_AS_SPECIFIED = "SingleLevelBomAsSpecified";
public static final String SINGLE_LEVEL_USAGE_AS_BUILT = "SingleLevelUsageAsBuilt";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
@Getter
public enum BomLifecycle {
AS_BUILT("asBuilt", AspectType.SERIAL_PART),
AS_PLANNED("asPlanned", AspectType.PART_AS_PLANNED);
AS_PLANNED("asPlanned", AspectType.PART_AS_PLANNED),
AS_SPECIFIED("asSpecified", AspectType.PART_AS_SPECIFIED);

private final String name;
private final String defaultAspect;
Expand Down
Loading

0 comments on commit f04fa78

Please sign in to comment.