Skip to content

Commit

Permalink
Merge pull request #632 from catenax-ng/main
Browse files Browse the repository at this point in the history
chore: update error handling when publishing assets
  • Loading branch information
ds-mmaul authored Feb 5, 2024
2 parents a96e05c + 6070822 commit 4a52068
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Bumped cypress-io/github-action from 6.6.0 to 6.6.1
- Bumped tj-actions/changed-files from v41 to v42
- Fixed some response type descriptions within swagger documentation
- Error handling when publishing assets

### Removed

Expand Down
2 changes: 1 addition & 1 deletion DEPENDENCIES_FRONTEND
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,7 @@ npm/npmjs/@angular/compiler/16.2.12, MIT, approved, clearlydefined
npm/npmjs/@angular/core/16.2.12, MIT, approved, clearlydefined
npm/npmjs/@angular/forms/16.2.12, MIT, approved, clearlydefined
npm/npmjs/@angular/language-service/16.2.12, MIT AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND Unlicense AND CC-BY-4.0 AND LicenseRef-Public-domain, approved, #11035
npm/npmjs/@angular/material/16.2.13, , restricted, clearlydefined
npm/npmjs/@angular/material/16.2.13, MIT, restricted, clearlydefined
npm/npmjs/@angular/platform-browser-dynamic/16.2.12, MIT, approved, clearlydefined
npm/npmjs/@angular/platform-browser/16.2.12, MIT, approved, clearlydefined
npm/npmjs/@angular/router/16.2.12, MIT, approved, clearlydefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,12 @@ public class ImportController {

@PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ImportResponse> importJson(@RequestPart("file") MultipartFile file) {
log.info("Received request to import assets.");
List<String> jsonSchemaErrors = jsonFileValidator.isValid(file);
ValidationResponse validationResponse = new ValidationResponse(jsonSchemaErrors);

if (!jsonSchemaErrors.isEmpty()) {
log.warn("Asset import request cannot be processed. Errors: {}", validationResponse);
return ResponseEntity
.badRequest()
.body(new ImportResponse(validationResponse));
Expand All @@ -155,6 +157,7 @@ public ResponseEntity<ImportResponse> importJson(@RequestPart("file") MultipartF
assetBaseSet.getValue())
).toList();

log.info("Successfully imported {} assets.", importStateMessages.size());
ImportResponse importResponse = new ImportResponse(importStateMessages);

return ResponseEntity.ok(importResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public interface AssetRepository {

List<AssetBase> getAssetsById(List<String> assetIds);

boolean existsById(String assetId);

AssetBase getAssetByChildId(String childId);

List<AssetBase> getAssets();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/********************************************************************************
* Copyright (c) 2023, 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.traceability.assets.domain.importpoc.exception;

public class PublishAssetException extends RuntimeException {
public PublishAssetException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2023,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -23,11 +23,15 @@
import org.eclipse.tractusx.traceability.assets.application.importpoc.PublishService;
import org.eclipse.tractusx.traceability.assets.domain.asbuilt.repository.AssetAsBuiltRepository;
import org.eclipse.tractusx.traceability.assets.domain.asplanned.repository.AssetAsPlannedRepository;
import org.eclipse.tractusx.traceability.assets.domain.base.AssetRepository;
import org.eclipse.tractusx.traceability.assets.domain.base.model.AssetBase;
import org.eclipse.tractusx.traceability.assets.domain.base.model.ImportState;
import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.PublishAssetException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@RequiredArgsConstructor
Expand All @@ -40,18 +44,40 @@ public class PublishServiceImpl implements PublishService {
@Override
public void publishAssets(String policyId, List<String> assetIds) {
//Update assets with policy id
List<AssetBase> assetAsPlannedList = assetAsPlannedRepository.getAssetsById(assetIds).stream()
.filter(assetAsPlanned -> ImportState.TRANSIENT.equals(assetAsPlanned.getImportState()))
.peek(assetAsPlanned -> assetAsPlanned.setImportState(ImportState.IN_SYNCHRONIZATION))
.peek(assetAsPlanned -> assetAsPlanned.setPolicyId(policyId))
.toList();
assetAsPlannedRepository.saveAll(assetAsPlannedList);

List<AssetBase> assetAsBuiltList = assetAsBuiltRepository.getAssetsById(assetIds).stream()
.filter(assetAsBuilt -> ImportState.TRANSIENT.equals(assetAsBuilt.getImportState()))
.peek(assetAsBuilt -> assetAsBuilt.setImportState(ImportState.IN_SYNCHRONIZATION))
.peek(assetAsBuilt -> assetAsBuilt.setPolicyId(policyId))
.toList();
assetAsBuiltRepository.saveAll(assetAsBuiltList);
assetIds.forEach(this::throwIfNotExists);

log.info("Updating status of asPlannedAssets.");
updateAssetWithStatusAndPolicy(policyId, assetIds, assetAsPlannedRepository);
log.info("Updating status of asBuiltAssets.");
updateAssetWithStatusAndPolicy(policyId, assetIds, assetAsBuiltRepository);
}
private void throwIfNotExists(String assetId) {
if (!(assetAsBuiltRepository.existsById(assetId) || assetAsPlannedRepository.existsById(assetId))) {
throw new PublishAssetException("No asset found with the provided ID: " + assetId);
}
}


private void updateAssetWithStatusAndPolicy(String policyId, List<String> assetIds, AssetRepository repository) {
List<AssetBase> assetList = repository.getAssetsById(assetIds);
List<AssetBase> saveList = assetList.stream()
.filter(this::validTransientState)
.map(asset -> {
asset.setImportState(ImportState.IN_SYNCHRONIZATION);
asset.setPolicyId(policyId);
return asset;
}).toList();

List<AssetBase> assetBases = repository.saveAll(saveList);

log.info("Successfully set {} in status IN_SYNCHRONIZATION", assetBases.stream().map(AssetBase::getId).collect(Collectors.joining(", ")));
}

private boolean validTransientState(AssetBase assetBase) {
if (ImportState.TRANSIENT.equals(assetBase.getImportState())) {
return true;
}
throw new PublishAssetException("Asset with ID " + assetBase.getId() + " is not in TRANSIENT state.");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ public AssetBase getAssetById(String assetId) {
.orElseThrow(() -> new AssetNotFoundException("Asset with id %s was not found.".formatted(assetId)));
}

@Override
@Transactional
public boolean existsById(String assetId) {
return jpaAssetAsBuiltRepository.existsById(assetId);
}

@Override
public List<AssetBase> getAssetsById(List<String> assetIds) {
return jpaAssetAsBuiltRepository.findByIdIn(assetIds).stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public AssetBase getAssetById(String assetId) {
.orElseThrow(() -> new AssetNotFoundException("Asset with id %s was not found.".formatted(assetId)));
}

@Override
@Transactional
public boolean existsById(String assetId) {
return jpaAssetAsPlannedRepository.existsById(assetId);
}

@Override
public List<AssetBase> getAssetsById(List<String> assetIds) {
return jpaAssetAsPlannedRepository.findByIdIn(assetIds).stream().map(AssetAsPlannedEntity::toDomain)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.eclipse.tractusx.traceability.assets.application.importpoc.validation.exception.JsonFileProcessingException;
import org.eclipse.tractusx.traceability.assets.domain.asbuilt.exception.AssetNotFoundException;
import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.ImportException;
import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.PublishAssetException;
import org.eclipse.tractusx.traceability.bpn.domain.model.BpnNotFoundException;
import org.eclipse.tractusx.traceability.common.domain.ParseLocalDateException;
import org.eclipse.tractusx.traceability.common.model.UnsupportedSearchCriteriaFieldException;
Expand Down Expand Up @@ -110,6 +111,13 @@ ResponseEntity<ErrorResponse> handleAssetNotFoundException(AssetNotFoundExceptio
.body(new ErrorResponse(exception.getMessage()));
}

@ExceptionHandler(PublishAssetException.class)
ResponseEntity<ErrorResponse> handlePublishAssetException(PublishAssetException exception) {
log.warn("handlePublishAssetException", exception);
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(exception.getMessage()));
}

@ExceptionHandler(ImportException.class)
ResponseEntity<ErrorResponse> handleImportException(ImportException exception) {
log.warn("handleImportException", exception);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@

import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

class ImportControllerIT extends IntegrationTestSpecification {

Expand Down Expand Up @@ -397,4 +399,38 @@ void givenValidFile_whenPublishData_thenStatusShouldChangeToInSynchronization()
assertThat(ImportState.IN_SYNCHRONIZATION).isEqualTo(asset.getImportState());

}

@Test
void givenInvalidAssetID_whenPublishData_thenStatusCode404() throws JoseException {
// given
String path = getClass().getResource("/testdata/importfiles/validImportFile.json").getFile();
File file = new File(path);

given()
.header(oAuth2Support.jwtAuthorization(JwtRole.ADMIN))
.when()
.multiPart(file)
.post("/api/assets/import")
.then()
.statusCode(200)
.extract().as(ImportResponse.class);

RegisterAssetRequest registerAssetRequest = new RegisterAssetRequest("Trace-X policy", List.of("test", "urn:uuid:254604ab-2153-45fb-8cad-54ef09f4080f"));


// when
given()
.header(oAuth2Support.jwtAuthorization(JwtRole.ADMIN))
.contentType(ContentType.JSON)
.when()
.body(registerAssetRequest)
.post("/api/assets/publish")
.then()
.statusCode(404);

//then
AssetBase asset = assetAsBuiltRepository.getAssetById("urn:uuid:254604ab-2153-45fb-8cad-54ef09f4080f");
assertNull(asset.getPolicyId());
assertEquals(asset.getImportState(), ImportState.TRANSIENT);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2023, 2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -26,4 +26,5 @@ public record ValidationResponse(List<String> validationErrors) {
public static ValidationResponse emptyValidationResult() {
return new ValidationResponse(List.of());
}

}

0 comments on commit 4a52068

Please sign in to comment.