From: aravind.est Date: Thu, 4 Sep 2025 13:18:47 +0000 (+0100) Subject: Fix Sonar issues and IDE suggestions X-Git-Tag: 1.6.1~4 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=ff54c86e37d61264a1a9734306f19bb9d351b011;p=nonrtric%2Fplt%2Finformationcoordinatorservice.git Fix Sonar issues and IDE suggestions Sonar issues fixed. IDE suggestions fixed. Issue-ID: INT-193 Change-Id: I34c35cdbb02d429a4f775efd6c669db5c581faa3 Signed-off-by: aravind.est (cherry picked from commit 9924c4a2f4458091d5c45de1496bceec70719359) --- diff --git a/api/ics-api.json b/api/ics-api.json index 346ef46..81d8ea6 100644 --- a/api/ics-api.json +++ b/api/ics-api.json @@ -319,13 +319,13 @@ "description": "Identity of the owner of the job", "type": "string" }, - "job_definition": { - "description": "Information type specific job data", - "type": "object" - }, "status_notification_uri": { "description": "The target of Information subscription job status notifications", "type": "string" + }, + "job_definition": { + "description": "Information type specific job data", + "type": "object" } } }, diff --git a/api/ics-api.yaml b/api/ics-api.yaml index 6762bc5..a36dd94 100644 --- a/api/ics-api.yaml +++ b/api/ics-api.yaml @@ -1625,12 +1625,12 @@ components: job_owner: type: string description: Identity of the owner of the job - job_definition: - type: object - description: Information type specific job data status_notification_uri: type: string description: The target of Information subscription job status notifications + job_definition: + type: object + description: Information type specific job data description: Information for an Information Job producer_status: required: diff --git a/src/main/java/org/oransc/ics/Application.java b/src/main/java/org/oransc/ics/Application.java index 694bfe3..e3b051d 100644 --- a/src/main/java/org/oransc/ics/Application.java +++ b/src/main/java/org/oransc/ics/Application.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,12 +36,9 @@ public class Application { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(Application.class); - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - logger.warn("Shutting down, received signal SIGTERM"); - SpringApplication.exit(context); - } - }); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + logger.warn("Shutting down, received signal SIGTERM"); + SpringApplication.exit(context); + })); } } diff --git a/src/main/java/org/oransc/ics/clients/AsyncRestClient.java b/src/main/java/org/oransc/ics/clients/AsyncRestClient.java index 3edabf9..59465a2 100644 --- a/src/main/java/org/oransc/ics/clients/AsyncRestClient.java +++ b/src/main/java/org/oransc/ics/clients/AsyncRestClient.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -144,8 +145,7 @@ public class AsyncRestClient { } private void onError(Throwable t) { - if (t instanceof WebClientResponseException) { - WebClientResponseException e = (WebClientResponseException) t; + if (t instanceof WebClientResponseException e) { logger.debug("Response error: {}", e.getResponseBodyAsString()); } } diff --git a/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java b/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java index 64a3ce5..f8452f3 100644 --- a/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java +++ b/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +38,6 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import javax.net.ssl.KeyManagerFactory; import org.oransc.ics.configuration.WebClientConfig; @@ -123,7 +123,7 @@ public class AsyncRestClientFactory { List certificateList = Collections.list(trustStore.aliases()).stream() // .filter(alias -> isCertificateEntry(trustStore, alias)) // .map(alias -> getCertificate(trustStore, alias)) // - .collect(Collectors.toList()); + .toList(); final X509Certificate[] certificates = certificateList.toArray(new X509Certificate[certificateList.size()]); return SslContextBuilder.forClient() // @@ -136,7 +136,7 @@ public class AsyncRestClientFactory { try { return trustStore.isCertificateEntry(alias); } catch (KeyStoreException e) { - logger.error("Error reading truststore {}", e.getMessage()); + logger.error("Error reading truststore for certificate entry {}", e.getMessage()); return false; } } diff --git a/src/main/java/org/oransc/ics/controllers/ErrorResponse.java b/src/main/java/org/oransc/ics/controllers/ErrorResponse.java index 43c5748..052c1a5 100644 --- a/src/main/java/org/oransc/ics/controllers/ErrorResponse.java +++ b/src/main/java/org/oransc/ics/controllers/ErrorResponse.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,11 +100,8 @@ public class ErrorResponse { public static ResponseEntity create(Throwable e, HttpStatus code) { if (e instanceof RuntimeException) { code = HttpStatus.INTERNAL_SERVER_ERROR; - } else if (e instanceof ServiceException) { - ServiceException se = (ServiceException) e; - if (se.getHttpStatus() != null) { - code = se.getHttpStatus(); - } + } else if (e instanceof ServiceException se && se.getHttpStatus() != null) { + code = se.getHttpStatus(); } return create(e.getMessage(), code); } diff --git a/src/main/java/org/oransc/ics/controllers/StatusController.java b/src/main/java/org/oransc/ics/controllers/StatusController.java index ef43f8e..fd8c8f1 100644 --- a/src/main/java/org/oransc/ics/controllers/StatusController.java +++ b/src/main/java/org/oransc/ics/controllers/StatusController.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +31,10 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; import org.oransc.ics.repository.InfoJobs; import org.oransc.ics.repository.InfoProducers; import org.oransc.ics.repository.InfoTypes; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -41,21 +42,20 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; +@SuppressWarnings("java:S6830") @RestController("StatusController") @Tag(name = StatusController.API_NAME, description = StatusController.API_DESCRIPTION) +@RequiredArgsConstructor public class StatusController { public static final String API_NAME = "Service status"; public static final String API_DESCRIPTION = "API for monitoring of the service"; - @Autowired - private InfoJobs infoJobs; + private final InfoJobs infoJobs; - @Autowired - private InfoTypes infoTypes; + private final InfoTypes infoTypes; - @Autowired - private InfoProducers infoProducers; + private final InfoProducers infoProducers; @Schema(name = "service_status_info") public static class StatusInfo { diff --git a/src/main/java/org/oransc/ics/controllers/a1e/A1eController.java b/src/main/java/org/oransc/ics/controllers/a1e/A1eController.java index 879d6d8..bff261a 100644 --- a/src/main/java/org/oransc/ics/controllers/a1e/A1eController.java +++ b/src/main/java/org/oransc/ics/controllers/a1e/A1eController.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +21,6 @@ package org.oransc.ics.controllers.a1e; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -34,14 +34,11 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import java.lang.invoke.MethodHandles; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.json.JSONObject; -import org.oransc.ics.configuration.ApplicationConfig; +import lombok.RequiredArgsConstructor; import org.oransc.ics.controllers.ErrorResponse; import org.oransc.ics.controllers.VoidResponse; import org.oransc.ics.controllers.authorization.AuthorizationCheck; @@ -55,7 +52,6 @@ import org.oransc.ics.repository.InfoType; import org.oransc.ics.repository.InfoTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -70,33 +66,26 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; -@SuppressWarnings("java:S3457") // No need to call "toString()" method as formatting and string .. +@SuppressWarnings({"java:S3457", "java:S6830"}) // No need to call "toString()" method as formatting and string .. @RestController("A1-EI") @Tag(name = A1eConsts.CONSUMER_API_NAME, description = A1eConsts.CONSUMER_API_DESCRIPTION) @RequestMapping(path = A1eConsts.API_ROOT, produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor public class A1eController { private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - @Autowired - ApplicationConfig applicationConfig; + private final InfoJobs infoJobs; - @Autowired - private InfoJobs infoJobs; + private final InfoTypes infoTypes; - @Autowired - private InfoTypes infoTypes; + private final InfoProducers infoProducers; - @Autowired - private InfoProducers infoProducers; + private final ProducerCallbacks producerCallbacks; - @Autowired - ProducerCallbacks producerCallbacks; + private final AuthorizationCheck authorization; - @Autowired - private AuthorizationCheck authorization; - - private static Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); @GetMapping(path = "/eitypes", produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "EI type identifiers", description = "") @@ -293,7 +282,7 @@ public class A1eController { public Mono> putIndividualEiJob( // @PathVariable("eiJobId") String eiJobId, // @RequestBody A1eEiJobInfo eiJobObject, // - @RequestHeader Map headers) throws ServiceException { + @RequestHeader Map headers) { final boolean isNewJob = this.infoJobs.get(eiJobId) == null; try { @@ -302,7 +291,7 @@ public class A1eController { return authorization.doAccessControl(headers, eiType, eiJobObject.jobDefinition, AccessType.WRITE) // .flatMap(x -> validatePutEiJob(eiJobId, eiType, eiJobObject)) // .flatMap(job -> startEiJob(job, eiType)) // - .doOnNext(newEiJob -> this.infoJobs.put(newEiJob)) // + .doOnNext(this.infoJobs::put) // .map(newEiJob -> new ResponseEntity<>(isNewJob ? HttpStatus.CREATED : HttpStatus.OK)) // .onErrorResume( throwable -> Mono.just(ErrorResponse.create(throwable, HttpStatus.INTERNAL_SERVER_ERROR))); @@ -320,9 +309,9 @@ public class A1eController { private Mono validatePutEiJob(String eiJobId, InfoType eiType, A1eEiJobInfo eiJobInfo) { try { - validateJsonObjectAgainstSchema(eiType.getJobDataSchema(), eiJobInfo.jobDefinition); - validateUri(eiJobInfo.jobResultUri); - validateUri(eiJobInfo.statusNotificationUri); + this.infoJobs.validateJsonObjectAgainstSchema(eiType.getJobDataSchema(), eiJobInfo.jobDefinition); + this.infoJobs.validateUri(eiJobInfo.jobResultUri); + this.infoJobs.validateUri(eiJobInfo.statusNotificationUri); InfoJob existingEiJob = this.infoJobs.get(eiJobId); if (existingEiJob != null) { @@ -337,31 +326,6 @@ public class A1eController { } } - private void validateUri(String url) throws URISyntaxException, ServiceException { - if (url != null && !url.isEmpty()) { - URI uri = new URI(url); - if (!uri.isAbsolute()) { - throw new ServiceException("URI: " + url + " is not absolute", HttpStatus.BAD_REQUEST); - } - } - } - - private void validateJsonObjectAgainstSchema(Object schemaObj, Object object) throws ServiceException { - try { - ObjectMapper mapper = new ObjectMapper(); - - String schemaAsString = mapper.writeValueAsString(schemaObj); - JSONObject schemaJSON = new JSONObject(schemaAsString); - var schema = org.everit.json.schema.loader.SchemaLoader.load(schemaJSON); - - String objectAsString = mapper.writeValueAsString(object); - JSONObject json = new JSONObject(objectAsString); - schema.validate(json); - } catch (Exception e) { - throw new ServiceException("Json validation failure " + e.toString(), HttpStatus.BAD_REQUEST); - } - } - private InfoJob toEiJob(A1eEiJobInfo info, String id, InfoType type) { return InfoJob.builder() // .id(id) // diff --git a/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobInfo.java b/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobInfo.java index 2a042f1..913b973 100644 --- a/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobInfo.java +++ b/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,27 +29,27 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(name = "EiJobObject", description = "Information for an Enrichment Information Job") public class A1eEiJobInfo { - @Schema(name = "eiTypeId", description = "EI type Idenitifier of the EI job", required = true) + @Schema(name = "eiTypeId", description = "EI type Idenitifier of the EI job", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("eiTypeId") @JsonProperty(value = "eiTypeId", required = true) public String eiTypeId = ""; - @Schema(name = "jobOwner", description = "Identity of the owner of the job", required = true) + @Schema(name = "jobOwner", description = "Identity of the owner of the job", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("jobOwner") @JsonProperty(value = "jobOwner", required = true) public String owner = ""; - @Schema(name = "jobDefinition", description = "EI type specific job data", required = true) + @Schema(name = "jobDefinition", description = "EI type specific job data", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("jobDefinition") @JsonProperty(value = "jobDefinition", required = true) public Object jobDefinition; - @Schema(name = "jobResultUri", description = "The target URI of the EI data", required = true) + @Schema(name = "jobResultUri", description = "The target URI of the EI data", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("jobResultUri") @JsonProperty(value = "jobResultUri", required = true) public String jobResultUri = ""; - @Schema(name = "statusNotificationUri", description = "The target of EI job status notifications", required = false) + @Schema(name = "statusNotificationUri", description = "The target of EI job status notifications", requiredMode = Schema.RequiredMode.NOT_REQUIRED) @SerializedName("jobStatusNotificationUri") @JsonProperty(value = "jobStatusNotificationUri", required = false) public String statusNotificationUri = ""; diff --git a/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobStatus.java b/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobStatus.java index e635f2e..1d01427 100644 --- a/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobStatus.java +++ b/src/main/java/org/oransc/ics/controllers/a1e/A1eEiJobStatus.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +38,7 @@ public class A1eEiJobStatus { + "ENABLED: the A1-EI producer is able to deliver EI result for the EI job
" // + "DISABLED: the A1-EI producer is unable to deliver EI result for the EI job"; - @Schema(name = "eiJobStatus", description = OPERATIONAL_STATE_DESCRIPTION, required = true) + @Schema(name = "eiJobStatus", description = OPERATIONAL_STATE_DESCRIPTION, requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("eiJobStatus") @JsonProperty(value = "eiJobStatus", required = true) public EiJobStatusValues state; diff --git a/src/main/java/org/oransc/ics/controllers/authorization/AuthorizationResult.java b/src/main/java/org/oransc/ics/controllers/authorization/AuthorizationResult.java index ef986ea..f1919d5 100644 --- a/src/main/java/org/oransc/ics/controllers/authorization/AuthorizationResult.java +++ b/src/main/java/org/oransc/ics/controllers/authorization/AuthorizationResult.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +32,7 @@ import lombok.Getter; @Builder public class AuthorizationResult { - @Schema(name = "result", description = "If true, the access is granted", required = true) + @Schema(name = "result", description = "If true, the access is granted", requiredMode = Schema.RequiredMode.REQUIRED) @JsonProperty(value = "result", required = true) @SerializedName("result") @Getter diff --git a/src/main/java/org/oransc/ics/controllers/authorization/SubscriptionAuthRequest.java b/src/main/java/org/oransc/ics/controllers/authorization/SubscriptionAuthRequest.java index 1b07ac9..329db29 100644 --- a/src/main/java/org/oransc/ics/controllers/authorization/SubscriptionAuthRequest.java +++ b/src/main/java/org/oransc/ics/controllers/authorization/SubscriptionAuthRequest.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,29 +52,29 @@ public class SubscriptionAuthRequest { READ, WRITE } - @Schema(name = "access_type", description = "Access type", required = true) + @Schema(name = "access_type", description = "Access type", requiredMode = Schema.RequiredMode.REQUIRED) @JsonProperty(value = "access_type", required = true) @SerializedName("access_type") private AccessType accessType; - @Schema(name = "info_type_id", description = "Information type identifier", required = true) + @Schema(name = "info_type_id", description = "Information type identifier", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_type_id") @JsonProperty(value = "info_type_id", required = true) private String infoTypeId; - @Schema(name = "job_definition", description = "Information type specific job data", required = true) + @Schema(name = "job_definition", description = "Information type specific job data", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("job_definition") @JsonProperty(value = "job_definition", required = true) private Object jobDefinition; - @Schema(name = "auth_token", description = "Authorization token", required = true) + @Schema(name = "auth_token", description = "Authorization token", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("auth_token") @JsonProperty(value = "auth_token", required = true) private String authToken; } - @Schema(name = "input", description = "Input", required = true) + @Schema(name = "input", description = "Input", requiredMode = Schema.RequiredMode.REQUIRED) @JsonProperty(value = "input", required = true) @SerializedName("input") private Input input; diff --git a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerController.java b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerController.java index b48ac35..4dbcc43 100644 --- a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerController.java +++ b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerController.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +21,6 @@ package org.oransc.ics.controllers.r1consumer; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -34,14 +34,11 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import java.lang.invoke.MethodHandles; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; -import org.json.JSONObject; import org.oransc.ics.controllers.ErrorResponse; import org.oransc.ics.controllers.VoidResponse; import org.oransc.ics.controllers.authorization.AuthorizationCheck; @@ -73,7 +70,7 @@ import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@SuppressWarnings("java:S3457") // No need to call "toString()" method as formatting and string .. +@SuppressWarnings({"java:S3457", "java:S6830"}) // No need to call "toString()" method as formatting and string .. @RestController("Consumer API") @Tag(name = ConsumerConsts.CONSUMER_API_NAME, description = ConsumerConsts.CONSUMER_API_DESCRIPTION) @RequestMapping(path = ConsumerConsts.API_ROOT, produces = MediaType.APPLICATION_JSON_VALUE) @@ -489,9 +486,9 @@ public class ConsumerController { private Mono validatePutInfoJob(String jobId, InfoType infoType, ConsumerJobInfo jobInfo) { try { - validateJsonObjectAgainstSchema(infoType.getJobDataSchema(), jobInfo.jobDefinition); - validateUri(jobInfo.statusNotificationUri); - validateUri(jobInfo.jobResultUri); + this.infoJobs.validateJsonObjectAgainstSchema(infoType.getJobDataSchema(), jobInfo.jobDefinition); + this.infoJobs.validateUri(jobInfo.statusNotificationUri); + this.infoJobs.validateUri(jobInfo.jobResultUri); InfoJob existingJob = this.infoJobs.get(jobId); if (existingJob != null) { @@ -507,31 +504,6 @@ public class ConsumerController { } } - private void validateUri(String url) throws URISyntaxException, ServiceException { - if (url != null && !url.isEmpty()) { - URI uri = new URI(url); - if (!uri.isAbsolute()) { - throw new ServiceException("URI: " + url + " is not absolute", HttpStatus.BAD_REQUEST); - } - } - } - - private void validateJsonObjectAgainstSchema(Object schemaObj, Object object) throws ServiceException { - try { - ObjectMapper mapper = new ObjectMapper(); - - String schemaAsString = mapper.writeValueAsString(schemaObj); - JSONObject schemaJSON = new JSONObject(schemaAsString); - var schema = org.everit.json.schema.loader.SchemaLoader.load(schemaJSON); - - String objectAsString = mapper.writeValueAsString(object); - JSONObject json = new JSONObject(objectAsString); - schema.validate(json); - } catch (Exception e) { - throw new ServiceException("Json validation failure " + e.toString(), HttpStatus.BAD_REQUEST); - } - } - private InfoJob toInfoJob(ConsumerJobInfo info, String id, InfoType type) { return InfoJob.builder() // .id(id) // diff --git a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerInfoTypeInfo.java b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerInfoTypeInfo.java index 1f11c15..8675efe 100644 --- a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerInfoTypeInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerInfoTypeInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2021 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +29,7 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(name = "consumer_information_type", description = "Information for an Information type") public class ConsumerInfoTypeInfo { - @Schema(name = "job_data_schema", description = "Json schema for the job data", required = true) + @Schema(name = "job_data_schema", description = "Json schema for the job data", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("job_data_schema") @JsonProperty(value = "job_data_schema", required = true) public Object jobDataSchema; @@ -42,12 +43,12 @@ public class ConsumerInfoTypeInfo { + "ENABLED: one or several producers for the information type are available
" // + "DISABLED: no producers for the information type are available"; - @Schema(name = "type_status", description = STATUS_DESCRIPTION, required = true) + @Schema(name = "type_status", description = STATUS_DESCRIPTION, requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("type_status") @JsonProperty(value = "type_status", required = true) public ConsumerTypeStatusValues state; - @Schema(name = "no_of_producers", description = "The number of registered producers for the type", required = true) + @Schema(name = "no_of_producers", description = "The number of registered producers for the type", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("no_of_producers") @JsonProperty(value = "no_of_producers", required = true) public int noOfProducers; diff --git a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobInfo.java b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobInfo.java index 62483d0..fcac7a8 100644 --- a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,34 +34,34 @@ public class ConsumerJobInfo { @Schema( name = "info_type_id", description = "Information type Idenitifier of the subscription job", - required = true) + requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_type_id") @JsonProperty(value = "info_type_id", required = true) public String infoTypeId = ""; - @Schema(name = "job_owner", description = "Identity of the owner of the job", required = true) - @SerializedName("job_owner") - @JsonProperty(value = "job_owner", required = true) - public String owner = ""; - - @Schema(name = "job_definition", description = "Information type specific job data", required = true) - @SerializedName("job_definition") - @JsonProperty(value = "job_definition", required = true) - public Object jobDefinition; - - @Schema(name = "job_result_uri", description = "The target URI of the subscribed information", required = true) + @Schema(name = "job_result_uri", description = "The target URI of the subscribed information", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("job_result_uri") @JsonProperty(value = "job_result_uri", required = false) public String jobResultUri = ""; + @Schema(name = "job_owner", description = "Identity of the owner of the job", requiredMode = Schema.RequiredMode.REQUIRED) + @SerializedName("job_owner") + @JsonProperty(value = "job_owner", required = true) + public String owner = ""; + @Schema( name = "status_notification_uri", description = "The target of Information subscription job status notifications", - required = false) + requiredMode = Schema.RequiredMode.NOT_REQUIRED) @SerializedName("status_notification_uri") @JsonProperty(value = "status_notification_uri", required = false) public String statusNotificationUri = ""; + @Schema(name = "job_definition", description = "Information type specific job data", requiredMode = Schema.RequiredMode.REQUIRED) + @SerializedName("job_definition") + @JsonProperty(value = "job_definition", required = true) + public Object jobDefinition; + public ConsumerJobInfo() { } diff --git a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobStatus.java b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobStatus.java index 78657fd..0a91df1 100644 --- a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobStatus.java +++ b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerJobStatus.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,12 +42,12 @@ public class ConsumerJobStatus { private static final String PRODUCERS_DESCRIPTION = "An array of all registered Information Producer Identifiers."; - @Schema(name = "info_job_status", description = OPERATIONAL_STATE_DESCRIPTION, required = true) + @Schema(name = "info_job_status", description = OPERATIONAL_STATE_DESCRIPTION, requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_job_status") @JsonProperty(value = "info_job_status", required = true) public InfoJobStatusValues state; - @Schema(name = "producers", description = PRODUCERS_DESCRIPTION, required = true) + @Schema(name = "producers", description = PRODUCERS_DESCRIPTION, requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("producers") @JsonProperty(value = "producers", required = true) public Collection producers; diff --git a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeRegistrationInfo.java b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeRegistrationInfo.java index fa4ea99..ac127be 100644 --- a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeRegistrationInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeRegistrationInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2021 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,12 +29,12 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(name = "consumer_type_registration_info", description = "Information for an Information type") public class ConsumerTypeRegistrationInfo { - @Schema(name = "info_type_id", description = "Information type identifier", required = true) + @Schema(name = "info_type_id", description = "Information type identifier", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_type_id") @JsonProperty(value = "info_type_id", required = true) public String infoTypeId; - @Schema(name = "job_data_schema", description = "Json schema for the job data", required = true) + @Schema(name = "job_data_schema", description = "Json schema for the job data", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("job_data_schema") @JsonProperty(value = "job_data_schema", required = true) public Object jobDataSchema; @@ -47,7 +48,7 @@ public class ConsumerTypeRegistrationInfo { + "REGISTERED: the information type has been registered
" // + "DEREGISTERED: the information type has been removed"; - @Schema(name = "status", description = REGISTRATION_DESCRIPTION, required = true) + @Schema(name = "status", description = REGISTRATION_DESCRIPTION, requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("status") @JsonProperty(value = "status", required = true) public ConsumerTypeStatusValues state; diff --git a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeSubscriptionInfo.java b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeSubscriptionInfo.java index fc3c35d..10b80d9 100644 --- a/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeSubscriptionInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerTypeSubscriptionInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2021 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,12 +33,12 @@ import lombok.ToString; @Schema(name = "consumer_type_subscription_info", description = "Information for an information type subscription") public class ConsumerTypeSubscriptionInfo { - @Schema(name = "status_result_uri", description = "The target URI of the subscribed information", required = true) + @Schema(name = "status_result_uri", description = "The target URI of the subscribed information", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("status_result_uri") @JsonProperty(value = "status_result_uri", required = true) public String statusResultUri = ""; - @Schema(name = "owner", description = "Identity of the owner of the subscription", required = true) + @Schema(name = "owner", description = "Identity of the owner of the subscription", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("owner") @JsonProperty(value = "owner", required = true) public String owner = ""; diff --git a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java index 25e20e3..a142032 100644 --- a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java +++ b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +28,7 @@ import java.lang.invoke.MethodHandles; import java.time.Duration; import java.util.Collection; +import java.util.List; import org.oransc.ics.clients.AsyncRestClient; import org.oransc.ics.clients.AsyncRestClientFactory; import org.oransc.ics.clients.SecurityContext; @@ -50,7 +52,7 @@ import reactor.util.retry.Retry; public class ProducerCallbacks { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private static Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); private final AsyncRestClient restClient; @@ -87,14 +89,14 @@ public class ProducerCallbacks { return Flux.fromIterable(getProducersForJob(type, infoProducers)) // .flatMap(infoProducer -> startInfoJob(infoProducer, infoJob, retrySpec)) // .collectList() // - .map(okResponses -> Integer.valueOf(okResponses.size())); // + .map(List::size); // } /** * Start all jobs for one producer * - * @param producer - * @param infoJobs + * @param producer information producer + * @param infoJobs information jobs */ public Flux startInfoJobs(InfoProducer producer, InfoJobs infoJobs) { final int maxNoOfParalellRequests = 10; diff --git a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerController.java b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerController.java index b2a7d52..bfb0837 100644 --- a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerController.java +++ b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerController.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +42,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import lombok.RequiredArgsConstructor; import org.oransc.ics.controllers.ErrorResponse; import org.oransc.ics.controllers.VoidResponse; import org.oransc.ics.exceptions.ServiceException; @@ -54,7 +56,6 @@ import org.oransc.ics.repository.InfoTypeSubscriptions; import org.oransc.ics.repository.InfoTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -66,25 +67,22 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -@SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally +@SuppressWarnings({"squid:S2629", "java:S6830"}) // Invoke method(s) only conditionally @RestController("Producer registry") @Tag(name = ProducerConsts.PRODUCER_API_NAME, description = ProducerConsts.PRODUCER_API_DESCRIPTION) +@RequiredArgsConstructor public class ProducerController { - private static Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - @Autowired - private InfoJobs infoJobs; + private final InfoJobs infoJobs; - @Autowired - private InfoTypes infoTypes; + private final InfoTypes infoTypes; - @Autowired - private InfoProducers infoProducers; + private final InfoProducers infoProducers; - @Autowired - private InfoTypeSubscriptions typeSubscriptions; + private final InfoTypeSubscriptions typeSubscriptions; @GetMapping(path = ProducerConsts.API_ROOT + "/info-types", produces = MediaType.APPLICATION_JSON_VALUE) // @Operation(summary = "Info Type identifiers", description = "") // diff --git a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerInfoTypeInfo.java b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerInfoTypeInfo.java index 45c5a93..4dd3c68 100644 --- a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerInfoTypeInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerInfoTypeInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +29,7 @@ import io.swagger.v3.oas.annotations.media.Schema; @Schema(name = "producer_info_type_info", description = "Information for an Information Type") public class ProducerInfoTypeInfo { - @Schema(name = "info_job_data_schema", description = "Json schema for the job data", required = true) + @Schema(name = "info_job_data_schema", description = "Json schema for the job data", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_job_data_schema") @JsonProperty(value = "info_job_data_schema", required = true) public Object jobDataSchema; @@ -36,7 +37,7 @@ public class ProducerInfoTypeInfo { @Schema( name = "info_type_information", description = "Type specific information for the information type", - required = false) + requiredMode = Schema.RequiredMode.NOT_REQUIRED) @SerializedName("info_type_information") @JsonProperty(value = "info_type_information", required = false) public Object typeSpecificInformation; diff --git a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerJobInfo.java b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerJobInfo.java index 6dc9717..d64de41 100644 --- a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerJobInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerJobInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +31,7 @@ import org.oransc.ics.repository.InfoJob; @Schema(name = "producer_info_job_request", description = "The body of the Information Producer callbacks for Information Job creation and deletion") public class ProducerJobInfo { - @Schema(name = "info_job_identity", description = "Identity of the Information Job", required = true) + @Schema(name = "info_job_identity", description = "Identity of the Information Job", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_job_identity") @JsonProperty("info_job_identity") public String id = ""; diff --git a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerRegistrationInfo.java b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerRegistrationInfo.java index f2c7ad1..9626077 100644 --- a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerRegistrationInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerRegistrationInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,12 +34,12 @@ import lombok.ToString; @Schema(name = "producer_registration_info", description = "Information for an Information Producer") public class ProducerRegistrationInfo { - @Schema(name = "supported_info_types", description = "Supported Information Type IDs", required = true) + @Schema(name = "supported_info_types", description = "Supported Information Type IDs", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("supported_info_types") @JsonProperty(value = "supported_info_types", required = true) public Collection supportedTypeIds; - @Schema(name = "info_job_callback_url", description = "callback for Information Job", required = true) + @Schema(name = "info_job_callback_url", description = "callback for Information Job", requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_job_callback_url") @JsonProperty(value = "info_job_callback_url", required = true) public String jobCallbackUrl = ""; @@ -46,7 +47,7 @@ public class ProducerRegistrationInfo { @Schema( name = "info_producer_supervision_callback_url", description = "callback for producer supervision", - required = true) + requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("info_producer_supervision_callback_url") @JsonProperty(value = "info_producer_supervision_callback_url", required = true) public String producerSupervisionCallbackUrl = ""; diff --git a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerStatusInfo.java b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerStatusInfo.java index 9a04023..9877569 100644 --- a/src/main/java/org/oransc/ics/controllers/r1producer/ProducerStatusInfo.java +++ b/src/main/java/org/oransc/ics/controllers/r1producer/ProducerStatusInfo.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,11 +34,12 @@ public class ProducerStatusInfo { ENABLED, DISABLED } - private static final String OPERATIONAL_STATE_DESCRIPTION = "Operational state, values:\n" // - + "ENABLED: the producer is operational\n" // - + "DISABLED: the producer is not operational"; + private static final String OPERATIONAL_STATE_DESCRIPTION = """ + Operational state, values: + ENABLED: the producer is operational + DISABLED: the producer is not operational"""; - @Schema(name = "operational_state", description = OPERATIONAL_STATE_DESCRIPTION, required = true) + @Schema(name = "operational_state", description = OPERATIONAL_STATE_DESCRIPTION, requiredMode = Schema.RequiredMode.REQUIRED) @SerializedName("operational_state") @JsonProperty(value = "operational_state", required = true) public final OperationalState opState; diff --git a/src/main/java/org/oransc/ics/datastore/S3ObjectStore.java b/src/main/java/org/oransc/ics/datastore/S3ObjectStore.java index 8d564a6..b35531c 100644 --- a/src/main/java/org/oransc/ics/datastore/S3ObjectStore.java +++ b/src/main/java/org/oransc/ics/datastore/S3ObjectStore.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,7 +43,6 @@ import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.S3AsyncClientBuilder; import software.amazon.awssdk.services.s3.model.CreateBucketRequest; import software.amazon.awssdk.services.s3.model.CreateBucketResponse; -import software.amazon.awssdk.services.s3.model.Delete; import software.amazon.awssdk.services.s3.model.DeleteBucketRequest; import software.amazon.awssdk.services.s3.model.DeleteBucketResponse; import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; @@ -72,11 +72,10 @@ class S3ObjectStore implements DataStore { getS3AsynchClient(applicationConfig); } - private static synchronized S3AsyncClient getS3AsynchClient(ApplicationConfig applicationConfig) { + private static synchronized void getS3AsynchClient(ApplicationConfig applicationConfig) { if (applicationConfig.isS3Enabled() && s3AsynchClient == null) { s3AsynchClient = getS3AsyncClientBuilder(applicationConfig).build(); } - return s3AsynchClient; } private static S3AsyncClientBuilder getS3AsyncClientBuilder(ApplicationConfig applicationConfig) { @@ -168,13 +167,9 @@ class S3ObjectStore implements DataStore { oids.add(oid); } - Delete delete = Delete.builder() // - .objects(oids) // - .build(); - DeleteObjectsRequest request = DeleteObjectsRequest.builder() // .bucket(bucket()) // - .delete(delete) // + .delete(delete -> delete.objects(oids)) // .build(); CompletableFuture future = s3AsynchClient.deleteObjects(request); diff --git a/src/main/java/org/oransc/ics/repository/InfoJob.java b/src/main/java/org/oransc/ics/repository/InfoJob.java index e9a43e8..26f19c5 100644 --- a/src/main/java/org/oransc/ics/repository/InfoJob.java +++ b/src/main/java/org/oransc/ics/repository/InfoJob.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -100,8 +101,8 @@ public class InfoJob { @Override public boolean equals(Object o) { - if (o instanceof InfoJob) { - return this.id.equals(((InfoJob) o).id); + if (o instanceof InfoJob infoJob) { + return this.id.equals(infoJob.id); } return this.id.equals(o); } diff --git a/src/main/java/org/oransc/ics/repository/InfoJobs.java b/src/main/java/org/oransc/ics/repository/InfoJobs.java index ff5a403..05e12ed 100644 --- a/src/main/java/org/oransc/ics/repository/InfoJobs.java +++ b/src/main/java/org/oransc/ics/repository/InfoJobs.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +21,14 @@ package org.oransc.ics.repository; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapterFactory; import java.lang.invoke.MethodHandles; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -32,6 +36,7 @@ import java.util.Objects; import java.util.ServiceLoader; import java.util.Vector; +import org.json.JSONObject; import org.oransc.ics.configuration.ApplicationConfig; import org.oransc.ics.controllers.r1producer.ProducerCallbacks; import org.oransc.ics.datastore.DataStore; @@ -47,10 +52,10 @@ import reactor.core.publisher.Mono; * Dynamic representation of all existing Information Jobs. */ public class InfoJobs { - private Map allEiJobs = new HashMap<>(); + private final Map allEiJobs = new HashMap<>(); - private MultiMap jobsByType = new MultiMap<>(); - private MultiMap jobsByOwner = new MultiMap<>(); + private final MultiMap jobsByType = new MultiMap<>(); + private final MultiMap jobsByOwner = new MultiMap<>(); private final Gson gson; private final InfoTypes infoTypes; @@ -176,6 +181,31 @@ public class InfoJobs { dataStore.deleteAllData().flatMap(s -> dataStore.createDataStore()).blockLast(); } + public void validateUri(String url) throws URISyntaxException, ServiceException { + if (url != null && !url.isEmpty()) { + URI uri = new URI(url); + if (!uri.isAbsolute()) { + throw new ServiceException("URI: " + url + " is not absolute", HttpStatus.BAD_REQUEST); + } + } + } + + public void validateJsonObjectAgainstSchema(Object schemaObj, Object object) throws ServiceException { + try { + ObjectMapper mapper = new ObjectMapper(); + + String schemaAsString = mapper.writeValueAsString(schemaObj); + JSONObject schemaJSON = new JSONObject(schemaAsString); + var schema = org.everit.json.schema.loader.SchemaLoader.load(schemaJSON); + + String objectAsString = mapper.writeValueAsString(object); + JSONObject json = new JSONObject(objectAsString); + schema.validate(json); + } catch (Exception e) { + throw new ServiceException("Json validation failure " + e, HttpStatus.BAD_REQUEST); + } + } + private void doPut(InfoJob job) { InfoJob prevDefinition = this.get(job.getId()); if (prevDefinition == null) { diff --git a/src/main/java/org/oransc/ics/repository/InfoProducer.java b/src/main/java/org/oransc/ics/repository/InfoProducer.java index 3fa278e..a284c27 100644 --- a/src/main/java/org/oransc/ics/repository/InfoProducer.java +++ b/src/main/java/org/oransc/ics/repository/InfoProducer.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,8 +89,8 @@ public class InfoProducer { @Override public boolean equals(Object o) { - if (o instanceof InfoProducer) { - return this.id.equals(((InfoProducer) o).id); + if (o instanceof InfoProducer infoProducer) { + return this.id.equals(infoProducer.id); } return this.id.equals(o); } diff --git a/src/main/java/org/oransc/ics/repository/InfoProducers.java b/src/main/java/org/oransc/ics/repository/InfoProducers.java index 17ad366..7adc7e5 100644 --- a/src/main/java/org/oransc/ics/repository/InfoProducers.java +++ b/src/main/java/org/oransc/ics/repository/InfoProducers.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +55,7 @@ public class InfoProducers { this.infoTypes = infoTypes; } - public InfoProducer registerProducer(InfoProducerRegistrationInfo producerInfo) { + public void registerProducer(InfoProducerRegistrationInfo producerInfo) { final String producerId = producerInfo.getId(); InfoProducer previousDefinition = this.get(producerId); @@ -71,7 +72,6 @@ public class InfoProducers { .flatMapMany(list -> consumerCallbacks.notifyJobStatus(previousTypes, this)) // .subscribe(); - return producer; } private InfoProducer createProducer(InfoProducerRegistrationInfo producerInfo) { diff --git a/src/main/java/org/oransc/ics/repository/InfoType.java b/src/main/java/org/oransc/ics/repository/InfoType.java index db7e26b..519bdef 100644 --- a/src/main/java/org/oransc/ics/repository/InfoType.java +++ b/src/main/java/org/oransc/ics/repository/InfoType.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -197,8 +198,8 @@ public class InfoType { @Override public boolean equals(Object o) { - if (o instanceof InfoType) { - return this.id.equals(((InfoType) o).id); + if (o instanceof InfoType infoType) { + return this.id.equals(infoType.id); } return this.id.equals(o); } diff --git a/src/main/java/org/oransc/ics/repository/InfoTypeSubscriptions.java b/src/main/java/org/oransc/ics/repository/InfoTypeSubscriptions.java index a7961f8..786a335 100644 --- a/src/main/java/org/oransc/ics/repository/InfoTypeSubscriptions.java +++ b/src/main/java/org/oransc/ics/repository/InfoTypeSubscriptions.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * Copyright (C) 2019-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -85,8 +86,8 @@ public class InfoTypeSubscriptions { @Override public boolean equals(Object o) { - if (o instanceof SubscriptionInfo) { - return this.id.equals(((SubscriptionInfo) o).id); + if (o instanceof SubscriptionInfo subscriptionInfo) { + return this.id.equals(subscriptionInfo.id); } return this.id.equals(o); } diff --git a/src/test/java/org/oransc/ics/ApplicationTest.java b/src/test/java/org/oransc/ics/ApplicationTest.java index 42b8696..a0d39b5 100644 --- a/src/test/java/org/oransc/ics/ApplicationTest.java +++ b/src/test/java/org/oransc/ics/ApplicationTest.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +25,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; @@ -119,10 +118,10 @@ import reactor.test.StepVerifier; class ApplicationTest { private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private final String TYPE_ID = "typeId_1.9.9"; - private final String PRODUCER_ID = "producerId"; - private final String EI_JOB_PROPERTY = "\"property1\""; - private final String JOB_ID = "jobId"; + private final String typeId = "typeId_1.9.9"; + private final String producerId = "producerId"; + private final String eiJobProperty = "\"property1\""; + private final String jobId = "jobId"; @Autowired ApplicationContext context; @@ -216,7 +215,7 @@ class ApplicationTest { @Test void a1eGetEiTypes() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, "test"); + putInfoProducerWithOneType(producerId, "test"); String url = A1eConsts.API_ROOT + "/eitypes"; String rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo("[\"test\"]"); @@ -224,7 +223,7 @@ class ApplicationTest { @Test void testTrustValidation() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, "test"); + putInfoProducerWithOneType(producerId, "test"); String url = A1eConsts.API_ROOT + "/eitypes"; String rsp = restClient(true).get(url).block(); assertThat(rsp).isEqualTo("[\"test\"]"); @@ -232,7 +231,7 @@ class ApplicationTest { @Test void consumerGetInfoTypes() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, "test"); + putInfoProducerWithOneType(producerId, "test"); String url = ConsumerConsts.API_ROOT + "/info-types"; String rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo("[\"test\"]"); @@ -240,10 +239,10 @@ class ApplicationTest { @Test void consumerDeleteJobsForOneOwner() throws Exception { - putInfoProducerWithOneType("producer1", TYPE_ID); - putInfoJob(TYPE_ID, "jobId1"); - putInfoJob(TYPE_ID, "jobId2"); - putEiJob(TYPE_ID, "jobId3", "otherOwner"); + putInfoProducerWithOneType("producer1", typeId); + putInfoJob(typeId, "jobId1"); + putInfoJob(typeId, "jobId2"); + putEiJob(typeId, "jobId3", "otherOwner"); assertThat(this.infoJobs.size()).isEqualTo(3); String url = ConsumerConsts.API_ROOT + "/info-jobs?owner=owner"; restClient().delete(url).block(); @@ -255,14 +254,14 @@ class ApplicationTest { } @Test - void a1eGetEiTypesEmpty() throws Exception { + void a1eGetEiTypesEmpty() { String url = A1eConsts.API_ROOT + "/eitypes"; String rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo("[]"); } @Test - void consumerGetEiTypesEmpty() throws Exception { + void consumerGetEiTypesEmpty() { String url = ConsumerConsts.API_ROOT + "/info-types"; String rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo("[]"); @@ -270,7 +269,7 @@ class ApplicationTest { @Test void a1eGetEiType() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, "test"); + putInfoProducerWithOneType(producerId, "test"); String url = A1eConsts.API_ROOT + "/eitypes/test"; String rsp = restClient().get(url).block(); A1eEiTypeInfo info = gson.fromJson(rsp, A1eEiTypeInfo.class); @@ -279,7 +278,7 @@ class ApplicationTest { @Test void consumerGetEiType() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, "test"); + putInfoProducerWithOneType(producerId, "test"); String url = ConsumerConsts.API_ROOT + "/info-types/test"; String rsp = restClient().get(url).block(); ConsumerInfoTypeInfo info = gson.fromJson(rsp, ConsumerInfoTypeInfo.class); @@ -290,23 +289,23 @@ class ApplicationTest { } @Test - void a1eGetEiTypeNotFound() throws Exception { + void a1eGetEiTypeNotFound() { String url = A1eConsts.API_ROOT + "/eitypes/junk"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Information type not found: junk"); } @Test - void consumerGetEiTypeNotFound() throws Exception { + void consumerGetEiTypeNotFound() { String url = ConsumerConsts.API_ROOT + "/info-types/junk"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Information type not found: junk"); } @Test void a1eGetEiJobsIds() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); final String JOB_ID_JSON = "[\"jobId\"]"; - String url = A1eConsts.API_ROOT + "/eijobs?infoTypeId=" + TYPE_ID; + String url = A1eConsts.API_ROOT + "/eijobs?infoTypeId=" + typeId; String rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo(JOB_ID_JSON); @@ -322,7 +321,7 @@ class ApplicationTest { rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo(JOB_ID_JSON); - url = A1eConsts.API_ROOT + "/eijobs?eiTypeId=" + TYPE_ID + "&&owner=owner"; + url = A1eConsts.API_ROOT + "/eijobs?eiTypeId=" + typeId + "&&owner=owner"; rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo(JOB_ID_JSON); @@ -333,10 +332,10 @@ class ApplicationTest { @Test void consumerGetInformationJobsIds() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); final String JOB_ID_JSON = "[\"jobId\"]"; - String url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=" + TYPE_ID; + String url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=" + typeId; String rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo(JOB_ID_JSON); @@ -352,7 +351,7 @@ class ApplicationTest { rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo(JOB_ID_JSON); - url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=" + TYPE_ID + "&&owner=owner"; + url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=" + typeId + "&&owner=owner"; rsp = restClient().get(url).block(); assertThat(rsp).isEqualTo(JOB_ID_JSON); @@ -363,67 +362,67 @@ class ApplicationTest { @Test void a1eGetEiJob() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); String url = A1eConsts.API_ROOT + "/eijobs/jobId"; String rsp = restClient().get(url).block(); A1eEiJobInfo info = gson.fromJson(rsp, A1eEiJobInfo.class); assertThat(info.owner).isEqualTo("owner"); - assertThat(info.eiTypeId).isEqualTo(TYPE_ID); + assertThat(info.eiTypeId).isEqualTo(typeId); } @Test void consumerGetEiJob() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId"; String rsp = restClient().get(url).block(); ConsumerJobInfo info = gson.fromJson(rsp, ConsumerJobInfo.class); assertThat(info.owner).isEqualTo("owner"); - assertThat(info.infoTypeId).isEqualTo(TYPE_ID); + assertThat(info.infoTypeId).isEqualTo(typeId); } @Test void a1eGetEiJobNotFound() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = A1eConsts.API_ROOT + "/eijobs/junk"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk"); } @Test void consumerGetInfoJobNotFound() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = ConsumerConsts.API_ROOT + "/info-jobs/junk"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk"); } @Test void a1eGetEiJobStatus() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); verifyJobStatus("jobId", "ENABLED"); } @Test void consumerGetInfoJobStatus() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId/status"; String rsp = restClient().get(url).block(); assertThat(rsp) // .contains("ENABLED") // - .contains(PRODUCER_ID); + .contains(producerId); ConsumerJobStatus status = gson.fromJson(rsp, ConsumerJobStatus.class); - assertThat(status.producers).contains(PRODUCER_ID); + assertThat(status.producers).contains(producerId); } @Test void a1eDeleteEiJob() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); assertThat(this.infoJobs.size()).isEqualTo(1); String url = A1eConsts.API_ROOT + "/eijobs/jobId"; restClient().delete(url).block(); @@ -437,8 +436,8 @@ class ApplicationTest { @Test void consumerDeleteInfoJob() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); assertThat(this.infoJobs.size()).isEqualTo(1); String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId"; restClient().delete(url).block(); @@ -453,24 +452,24 @@ class ApplicationTest { @Test void a1eDeleteEiJobNotFound() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = A1eConsts.API_ROOT + "/eijobs/junk"; - testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk"); + testErrorCode(restClient().delete(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk"); } @Test void consumerDeleteEiJobNotFound() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = ConsumerConsts.API_ROOT + "/info-jobs/junk"; - testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk"); + testErrorCode(restClient().delete(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk"); } @Test void a1ePutEiJob() throws Exception { // Test that one producer accepting a job is enough - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); + putInfoProducerWithOneTypeRejecting("simulateProducerError", typeId); String url = A1eConsts.API_ROOT + "/eijobs/jobId"; String body = gson.toJson(eiJobInfo()); @@ -492,7 +491,7 @@ class ApplicationTest { InfoJob job = this.infoJobs.getJob("jobId"); assertThat(job.getOwner()).isEqualTo("owner"); - verifyJobStatus(JOB_ID, "ENABLED"); + verifyJobStatus(jobId, "ENABLED"); } @Test @@ -511,8 +510,8 @@ class ApplicationTest { putInfoProducerWithOneType(REG_TYPE_ID4, REG_TYPE_ID4); putInfoProducerWithOneType(REG_TYPE_ID5, REG_TYPE_ID5); - String url = A1eConsts.API_ROOT + "/eijobs/" + JOB_ID; - String body = gson.toJson(eiJobInfo(PUT_TYPE_ID, JOB_ID)); + String url = A1eConsts.API_ROOT + "/eijobs/" + jobId; + String body = gson.toJson(eiJobInfo(PUT_TYPE_ID, jobId)); ResponseEntity resp = restClient().putForEntity(url, body).block(); assertThat(this.infoJobs.size()).isEqualTo(1); assertThat(this.infoJobs.getJobs().iterator().next().getType().getId()).isEqualTo(REG_TYPE_ID1); @@ -530,21 +529,21 @@ class ApplicationTest { final String REG_TYPE_ID1 = "type_1.5.0"; // Compatible putInfoProducerWithOneType(REG_TYPE_ID1, REG_TYPE_ID1); - String body = gson.toJson(eiJobInfo("junkTypeId", JOB_ID)); + String body = gson.toJson(eiJobInfo("junkTypeId", jobId)); String url = A1eConsts.API_ROOT + "/eijobs/jobId"; testErrorCode(restClient().put(url, body), HttpStatus.NOT_FOUND, "not found"); - url = A1eConsts.API_ROOT + "/eijobs/" + JOB_ID; + url = A1eConsts.API_ROOT + "/eijobs/" + jobId; final String PUT_TYPE_ERROR_ID = "type_1.1"; - body = gson.toJson(eiJobInfo(PUT_TYPE_ERROR_ID, JOB_ID)); + body = gson.toJson(eiJobInfo(PUT_TYPE_ERROR_ID, jobId)); testErrorCode(restClient().put(url, body), HttpStatus.NOT_FOUND, "not found"); } @Test void consumerPutInformationJob() throws Exception { // Test that one producer accepting a job is enough - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId"; String body = gson.toJson(consumerJobInfo()); @@ -562,7 +561,7 @@ class ApplicationTest { InfoJob job = this.infoJobs.getJob("jobId"); assertThat(job.getOwner()).isEqualTo("owner"); - verifyJobStatus(JOB_ID, "ENABLED"); + verifyJobStatus(jobId, "ENABLED"); body = gson.toJson(consumerJobInfo("junkTypeId", "jobId", "")); testErrorCode(restClient().put(url, body), HttpStatus.NOT_FOUND, "not found"); @@ -604,7 +603,7 @@ class ApplicationTest { // the principles for backwards compability. assertThat(request.typeId.equals(REG_TYPE_ID1) || request.typeId.equals(REG_TYPE_ID2)).isTrue(); - verifyJobStatus(JOB_ID, "ENABLED"); + verifyJobStatus(jobId, "ENABLED"); // Test update job resp = restClient().putForEntity(url, body).block(); @@ -615,11 +614,11 @@ class ApplicationTest { @Test void a1ePutEiJob_jsonSchemavalidationError() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = A1eConsts.API_ROOT + "/eijobs/jobId"; // The element with name "property1" is mandatory in the schema - A1eEiJobInfo jobInfo = new A1eEiJobInfo(TYPE_ID, toJsonObject("{ \"XXstring\" : \"value\" }"), "owner", + A1eEiJobInfo jobInfo = new A1eEiJobInfo(typeId, toJsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri", "jobStatusUrl"); String body = gson.toJson(jobInfo); @@ -631,12 +630,12 @@ class ApplicationTest { @Test void consumerPutJob_jsonSchemavalidationError() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId"; // The element with name "property1" is mandatory in the schema ConsumerJobInfo jobInfo = - new ConsumerJobInfo(TYPE_ID, toJsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri", null); + new ConsumerJobInfo(typeId, toJsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri", null); String body = gson.toJson(jobInfo); testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "Json validation failure"); @@ -644,11 +643,11 @@ class ApplicationTest { @Test void consumerPutJob_uriError() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId"; - ConsumerJobInfo jobInfo = new ConsumerJobInfo(TYPE_ID, jsonObject(""), "owner", "junk", null); + ConsumerJobInfo jobInfo = new ConsumerJobInfo(typeId, jsonObject(""), "owner", "junk", null); String body = gson.toJson(jobInfo); testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "URI: junk is not absolute"); @@ -678,14 +677,14 @@ class ApplicationTest { } @Test - void producerPutType() throws JsonMappingException, JsonProcessingException, ServiceException { - assertThat(putInfoType(TYPE_ID)).isEqualTo(HttpStatus.CREATED); - assertThat(putInfoType(TYPE_ID)).isEqualTo(HttpStatus.OK); + void producerPutType() throws ServiceException { + assertThat(putInfoType(typeId)).isEqualTo(HttpStatus.CREATED); + assertThat(putInfoType(typeId)).isEqualTo(HttpStatus.OK); } @Test void producerPutType_noSchema() { - String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID; + String url = ProducerConsts.API_ROOT + "/info-types/" + typeId; String body = "{}"; testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "No schema provided"); @@ -694,31 +693,31 @@ class ApplicationTest { @Test void producerDeleteType() throws Exception { - putInfoType(TYPE_ID); - this.putInfoJob(TYPE_ID, "job1"); - this.putInfoJob(TYPE_ID, "job2"); - deleteInfoType(TYPE_ID); + putInfoType(typeId); + this.putInfoJob(typeId, "job1"); + this.putInfoJob(typeId, "job2"); + deleteInfoType(typeId); assertThat(this.infoTypes.size()).isZero(); assertThat(this.infoJobs.size()).isZero(); // Test that also the job is deleted - testErrorCode(restClient().delete(deleteInfoTypeUrl(TYPE_ID)), HttpStatus.NOT_FOUND, + testErrorCode(restClient().delete(deleteInfoTypeUrl(typeId)), HttpStatus.NOT_FOUND, "Information type not found"); } @Test void producerDeleteTypeExistingProducer() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID; - testErrorCode(restClient().delete(url), HttpStatus.CONFLICT, "The type has active producers: " + PRODUCER_ID); + putInfoProducerWithOneType(producerId, typeId); + String url = ProducerConsts.API_ROOT + "/info-types/" + typeId; + testErrorCode(restClient().delete(url), HttpStatus.CONFLICT, "The type has active producers: " + producerId); assertThat(this.infoTypes.size()).isEqualTo(1); } @Test void producerDeleteTypeExistingJob() throws Exception { - putInfoType(TYPE_ID); - String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID; - putInfoJob(TYPE_ID, JOB_ID); + putInfoType(typeId); + String url = ProducerConsts.API_ROOT + "/info-types/" + typeId; + putInfoJob(typeId, jobId); restClient().delete(url).block(); assertThat(this.infoTypes.size()).isZero(); @@ -728,8 +727,8 @@ class ApplicationTest { @Test void producerPutProducerWithOneType_rejecting() throws Exception { - putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID); - String url = A1eConsts.API_ROOT + "/eijobs/" + JOB_ID; + putInfoProducerWithOneTypeRejecting("simulateProducerError", typeId); + String url = A1eConsts.API_ROOT + "/eijobs/" + jobId; String body = gson.toJson(eiJobInfo()); restClient().put(url, body).block(); @@ -738,39 +737,39 @@ class ApplicationTest { await().untilAsserted(() -> assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2)); assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2); - verifyJobStatus(JOB_ID, "DISABLED"); + verifyJobStatus(jobId, "DISABLED"); } @Test void producerGetInfoProducerTypes() throws Exception { - final String EI_TYPE_ID_2 = TYPE_ID + "_2"; - putInfoProducerWithOneType("producer1", TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + final String EI_TYPE_ID_2 = typeId + "_2"; + putInfoProducerWithOneType("producer1", typeId); + putInfoJob(typeId, "jobId"); putInfoProducerWithOneType("producer2", EI_TYPE_ID_2); putInfoJob(EI_TYPE_ID_2, "jobId2"); String url = ProducerConsts.API_ROOT + "/info-types"; ResponseEntity resp = restClient().getForEntity(url).block(); assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(resp.getBody()).contains(TYPE_ID); + assertThat(resp.getBody()).contains(typeId); assertThat(resp.getBody()).contains(EI_TYPE_ID_2); } @Test void producerPutInfoProducer() throws Exception { - this.putInfoType(TYPE_ID); + this.putInfoType(typeId); String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId"; - String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID)); + String body = gson.toJson(producerInfoRegistratioInfo(typeId)); ResponseEntity resp = restClient().putForEntity(url, body).block(); assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED); assertThat(this.infoTypes.size()).isEqualTo(1); - InfoType type = this.infoTypes.getType(TYPE_ID); + InfoType type = this.infoTypes.getType(typeId); assertThat(this.infoProducers.getProducersSupportingType(type)).hasSize(1); assertThat(this.infoProducers.size()).isEqualTo(1); assertThat(this.infoProducers.get("infoProducerId").getInfoTypes().iterator().next().getId()) - .isEqualTo(TYPE_ID); + .isEqualTo(typeId); resp = restClient().putForEntity(url, body).block(); assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK); @@ -785,10 +784,10 @@ class ApplicationTest { @Test void producerPutInfoProducerExistingJob() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId"; - String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID)); + String body = gson.toJson(producerInfoRegistratioInfo(typeId)); restClient().putForEntity(url, body).block(); ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults(); @@ -798,20 +797,20 @@ class ApplicationTest { } @Test - void testPutInfoProducer_noType() throws Exception { + void testPutInfoProducer_noType() { String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId"; - String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID)); + String body = gson.toJson(producerInfoRegistratioInfo(typeId)); testErrorCode(restClient().put(url, body), HttpStatus.NOT_FOUND, "Information type not found"); } @Test void producerPutProducerAndInfoJob() throws Exception { - this.putInfoType(TYPE_ID); + this.putInfoType(typeId); String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId"; - String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID)); + String body = gson.toJson(producerInfoRegistratioInfo(typeId)); restClient().putForEntity(url, body).block(); assertThat(this.infoTypes.size()).isEqualTo(1); - this.infoTypes.getType(TYPE_ID); + this.infoTypes.getType(typeId); url = A1eConsts.API_ROOT + "/eijobs/jobId"; body = gson.toJson(eiJobInfo()); @@ -825,13 +824,13 @@ class ApplicationTest { @Test void producerGetInfoJobsForProducer() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId1"); - putInfoJob(TYPE_ID, "jobId2"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId1"); + putInfoJob(typeId, "jobId2"); // PUT a consumerRestApiTestBase.java String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId"; - String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID)); + String body = gson.toJson(producerInfoRegistratioInfo(typeId)); restClient().putForEntity(url, body).block(); url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId/info-jobs"; @@ -839,20 +838,20 @@ class ApplicationTest { assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK); ProducerJobInfo[] parsedResp = gson.fromJson(resp.getBody(), ProducerJobInfo[].class); - assertThat(parsedResp[0].typeId).isEqualTo(TYPE_ID); - assertThat(parsedResp[1].typeId).isEqualTo(TYPE_ID); + assertThat(parsedResp[0].typeId).isEqualTo(typeId); + assertThat(parsedResp[1].typeId).isEqualTo(typeId); } @Test void producerDeleteInfoProducer() throws Exception { - putInfoProducerWithOneType("infoProducerId", TYPE_ID); - putInfoProducerWithOneType("infoProducerId2", TYPE_ID); + putInfoProducerWithOneType("infoProducerId", typeId); + putInfoProducerWithOneType("infoProducerId2", typeId); assertThat(this.infoProducers.size()).isEqualTo(2); - InfoType type = this.infoTypes.getType(TYPE_ID); + InfoType type = this.infoTypes.getType(typeId); assertThat(this.infoProducers.getProducerIdsForType(type)).contains("infoProducerId"); assertThat(this.infoProducers.getProducerIdsForType(type)).contains("infoProducerId2"); - putInfoJob(TYPE_ID, "jobId"); + putInfoJob(typeId, "jobId"); assertThat(this.infoJobs.size()).isEqualTo(1); deleteInfoProducer("infoProducerId"); @@ -874,9 +873,9 @@ class ApplicationTest { A1eCallbacksSimulatorController.TestResults consumerCalls = this.a1eCallbacksSimulator.getTestResults(); ProducerSimulatorController.TestResults producerCalls = this.producerSimulator.getTestResults(); - putInfoProducerWithOneType("infoProducerId", TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); - putInfoProducerWithOneType("infoProducerId2", TYPE_ID); + putInfoProducerWithOneType("infoProducerId", typeId); + putInfoJob(typeId, "jobId"); + putInfoProducerWithOneType("infoProducerId2", typeId); await().untilAsserted(() -> assertThat(producerCalls.jobsStarted).hasSize(2)); deleteInfoProducer("infoProducerId2"); @@ -888,7 +887,7 @@ class ApplicationTest { assertThat(consumerCalls.eiJobStatusCallbacks.get(0).state) .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED); - putInfoProducerWithOneType("infoProducerId", TYPE_ID); + putInfoProducerWithOneType("infoProducerId", typeId); await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks).hasSize(2)); assertThat(consumerCalls.eiJobStatusCallbacks.get(1).state).isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED); } @@ -898,27 +897,27 @@ class ApplicationTest { // Test replacing a producer with new and removed types // Create a job - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, JOB_ID); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, jobId); // change the type for the producer, the job shall be disabled - putInfoProducerWithOneType(PRODUCER_ID, "junk"); - verifyJobStatus(JOB_ID, "DISABLED"); + putInfoProducerWithOneType(producerId, "junk"); + verifyJobStatus(jobId, "DISABLED"); A1eCallbacksSimulatorController.TestResults consumerCalls = this.a1eCallbacksSimulator.getTestResults(); await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks).hasSize(1)); assertThat(consumerCalls.eiJobStatusCallbacks.get(0).state) .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED); - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - verifyJobStatus(JOB_ID, "ENABLED"); + putInfoProducerWithOneType(producerId, typeId); + verifyJobStatus(jobId, "ENABLED"); await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks).hasSize(2)); assertThat(consumerCalls.eiJobStatusCallbacks.get(1).state).isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED); } @Test - void producerGetProducerInfoType() throws JsonMappingException, JsonProcessingException, ServiceException { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID; + void producerGetProducerInfoType() throws ServiceException { + putInfoProducerWithOneType(producerId, typeId); + String url = ProducerConsts.API_ROOT + "/info-types/" + typeId; ResponseEntity resp = restClient().getForEntity(url).block(); ProducerInfoTypeInfo info = gson.fromJson(resp.getBody(), ProducerInfoTypeInfo.class); assertThat(info.jobDataSchema).isNotNull(); @@ -928,15 +927,15 @@ class ApplicationTest { } @Test - void producerGetProducerIdentifiers() throws JsonMappingException, JsonProcessingException, ServiceException { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + void producerGetProducerIdentifiers() throws ServiceException { + putInfoProducerWithOneType(producerId, typeId); String url = ProducerConsts.API_ROOT + "/info-producers"; ResponseEntity resp = restClient().getForEntity(url).block(); - assertThat(resp.getBody()).contains(PRODUCER_ID); + assertThat(resp.getBody()).contains(producerId); - url = ProducerConsts.API_ROOT + "/info-producers?infoTypeId=" + TYPE_ID; + url = ProducerConsts.API_ROOT + "/info-producers?infoTypeId=" + typeId; resp = restClient().getForEntity(url).block(); - assertThat(resp.getBody()).contains(PRODUCER_ID); + assertThat(resp.getBody()).contains(producerId); url = ProducerConsts.API_ROOT + "/info-producers?infoTypeId=junk"; resp = restClient().getForEntity(url).block(); @@ -947,19 +946,19 @@ class ApplicationTest { void producerSupervision() throws Exception { A1eCallbacksSimulatorController.TestResults consumerResults = this.a1eCallbacksSimulator.getTestResults(); - putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID); + putInfoProducerWithOneTypeRejecting("simulateProducerError", typeId); { // Create a job - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, JOB_ID); - verifyJobStatus(JOB_ID, "ENABLED"); - deleteInfoProducer(PRODUCER_ID); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, jobId); + verifyJobStatus(jobId, "ENABLED"); + deleteInfoProducer(producerId); // A Job disabled status notification shall now be received await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks).hasSize(1)); assertThat(consumerResults.eiJobStatusCallbacks.get(0).state) .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED); - verifyJobStatus(JOB_ID, "DISABLED"); + verifyJobStatus(jobId, "DISABLED"); } assertThat(this.infoProducers.size()).isEqualTo(1); @@ -980,11 +979,11 @@ class ApplicationTest { // Now we have one disabled job, and no producer. // PUT a producer, then a Job ENABLED status notification shall be received - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks).hasSize(2)); assertThat(consumerResults.eiJobStatusCallbacks.get(1).state) .isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED); - verifyJobStatus(JOB_ID, "ENABLED"); + verifyJobStatus(jobId, "ENABLED"); } @Test @@ -992,16 +991,16 @@ class ApplicationTest { // Test that supervision enables not enabled jobs and sends a notification when // suceeded - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, JOB_ID); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, jobId); - InfoProducer producer = this.infoProducers.getProducer(PRODUCER_ID); - InfoJob job = this.infoJobs.getJob(JOB_ID); + InfoProducer producer = this.infoProducers.getProducer(producerId); + InfoJob job = this.infoJobs.getJob(jobId); // Pretend that the producer did reject the job and the a DISABLED notification // is sent for the job producer.setJobDisabled(job); job.setLastReportedStatus(false); - verifyJobStatus(JOB_ID, "DISABLED"); + verifyJobStatus(jobId, "DISABLED"); // Run the supervision and wait for the job to get started in the producer this.producerSupervision.createTask().blockLast(); @@ -1009,13 +1008,13 @@ class ApplicationTest { await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks).hasSize(1)); assertThat(consumerResults.eiJobStatusCallbacks.get(0).state) .isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED); - verifyJobStatus(JOB_ID, "ENABLED"); + verifyJobStatus(jobId, "ENABLED"); } @Test - void testGetStatus() throws JsonMappingException, JsonProcessingException, ServiceException { - putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID); - putInfoProducerWithOneTypeRejecting("simulateProducerError2", TYPE_ID); + void testGetStatus() throws ServiceException { + putInfoProducerWithOneTypeRejecting("simulateProducerError", typeId); + putInfoProducerWithOneTypeRejecting("simulateProducerError2", typeId); String url = "/status"; ResponseEntity resp = restClient().getForEntity(url).block(); @@ -1035,7 +1034,7 @@ class ApplicationTest { List entries = db.listObjects("").collectList().block(); assertThat(entries).hasSize(NO_OF_OBJS); - db.listObjects("").doOnNext(name -> logger.debug("deleted {}", name)).flatMap(name -> db.deleteObject(name)) + db.listObjects("").doOnNext(name -> logger.debug("deleted {}", name)).flatMap(db::deleteObject) .blockLast(); db.createDataStore().block(); @@ -1044,9 +1043,9 @@ class ApplicationTest { @Test void testJobDatabasePersistence() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId1"); - putInfoJob(TYPE_ID, "jobId2"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId1"); + putInfoJob(typeId, "jobId2"); waitForS3(); assertThat(this.infoJobs.size()).isEqualTo(2); @@ -1080,8 +1079,8 @@ class ApplicationTest { @Test void testTypesDatabasePersistence() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - InfoType savedType = this.infoTypes.getType(TYPE_ID); + putInfoProducerWithOneType(producerId, typeId); + InfoType savedType = this.infoTypes.getType(typeId); waitForS3(); assertThat(this.infoTypes.size()).isEqualTo(1); @@ -1090,7 +1089,7 @@ class ApplicationTest { // Restore the types InfoTypes restoredTypes = new InfoTypes(this.applicationConfig); restoredTypes.restoreTypesFromDatabase().blockLast(); - InfoType restoredType = restoredTypes.getType(TYPE_ID); + InfoType restoredType = restoredTypes.getType(typeId); assertThat(restoredType.getPersistentInfo()).isEqualTo(savedType.getPersistentInfo()); assertThat(restoredTypes.size()).isEqualTo(1); } @@ -1102,7 +1101,7 @@ class ApplicationTest { assertThat(restoredTypes.size()).isZero(); } logger.warn("Test removing a job when the db file is gone"); - this.infoTypes.remove(this.infoTypes.getType(TYPE_ID)); + this.infoTypes.remove(this.infoTypes.getType(typeId)); assertThat(this.infoJobs.size()).isZero(); } @@ -1180,13 +1179,13 @@ class ApplicationTest { final ConsumerSimulatorController.TestResults consumerCalls = this.consumerSimulator.getTestResults(); // Test callback for PUT type - this.putInfoType(TYPE_ID); + this.putInfoType(typeId); await().untilAsserted(() -> assertThat(consumerCalls.typeRegistrationInfoCallbacks).hasSize(1)); assertThat(consumerCalls.typeRegistrationInfoCallbacks.get(0).state) .isEqualTo(ConsumerTypeRegistrationInfo.ConsumerTypeStatusValues.REGISTERED); // Test callback for DELETE type - this.deleteInfoType(TYPE_ID); + this.deleteInfoType(typeId); await().untilAsserted(() -> assertThat(consumerCalls.typeRegistrationInfoCallbacks).hasSize(2)); assertThat(consumerCalls.typeRegistrationInfoCallbacks.get(1).state) .isEqualTo(ConsumerTypeRegistrationInfo.ConsumerTypeStatusValues.DEREGISTERED); @@ -1213,13 +1212,13 @@ class ApplicationTest { restClient().putForEntity(typeSubscriptionUrl() + "/subscriptionId", body).block(); assertThat(this.infoTypeSubscriptions.size()).isEqualTo(1); - this.putInfoType(TYPE_ID); + this.putInfoType(typeId); // The callback will fail and the subscription will be removed await().untilAsserted(() -> assertThat(this.infoTypeSubscriptions.size()).isZero()); } @Test - void testTypeSubscriptionErrorCodes() throws Exception { + void testTypeSubscriptionErrorCodes() { testErrorCode(restClient().get(typeSubscriptionUrl() + "/junk"), HttpStatus.NOT_FOUND, "Could not find Information subscription: junk"); @@ -1235,8 +1234,8 @@ class ApplicationTest { Path authFile = Files.createTempFile("icsTestAuthToken", ".txt"); Files.write(authFile, AUTH_TOKEN.getBytes()); this.securityContext.setAuthTokenFilePath(authFile); - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); var testResults = openPolicyAgentSimulatorController.getTestResults(); @@ -1245,14 +1244,14 @@ class ApplicationTest { // Test OPA check SubscriptionAuthRequest authRequest = testResults.receivedRequests.get(0); assertThat(authRequest.getInput().getAccessType()).isEqualTo(AccessType.WRITE); - assertThat(authRequest.getInput().getInfoTypeId()).isEqualTo(TYPE_ID); + assertThat(authRequest.getInput().getInfoTypeId()).isEqualTo(typeId); assertThat(authRequest.getInput().getAuthToken()).isEqualTo(AUTH_TOKEN); } @Test void testFineGrainedAuthorizationCheckRejections() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, JOB_ID); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, jobId); // Test rejection from OPA this.applicationConfig @@ -1260,51 +1259,51 @@ class ApplicationTest { var testResults = openPolicyAgentSimulatorController.getTestResults(); // R1 - String url = ConsumerConsts.API_ROOT + "/info-jobs/" + JOB_ID; + String url = ConsumerConsts.API_ROOT + "/info-jobs/" + jobId; testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized"); assertThat(testResults.receivedRequests).hasSize(2); SubscriptionAuthRequest authRequest = testResults.receivedRequests.get(1); assertThat(authRequest.getInput().getAccessType()).isEqualTo(AccessType.WRITE); - String body = gson.toJson(consumerJobInfo(TYPE_ID, JOB_ID, "owner")); + String body = gson.toJson(consumerJobInfo(typeId, jobId, "owner")); testErrorCode(restClient().put(url, body), HttpStatus.UNAUTHORIZED, "Not authorized"); testErrorCode(restClient().get(url), HttpStatus.UNAUTHORIZED, "Not authorized"); // A1-E - url = A1eConsts.API_ROOT + "/eijobs/" + JOB_ID; + url = A1eConsts.API_ROOT + "/eijobs/" + jobId; testErrorCode(restClient().get(url), HttpStatus.UNAUTHORIZED, "Not authorized"); testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized"); - body = gson.toJson(eiJobInfo(TYPE_ID, JOB_ID, "owner")); + body = gson.toJson(eiJobInfo(typeId, jobId, "owner")); testErrorCode(restClient().put(url, body), HttpStatus.UNAUTHORIZED, "Not authorized"); } @Test void testFineGrainedAuthorizationCheckRejections_OPA_UNAVALIABLE() throws Exception { - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, JOB_ID); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, jobId); // Test rejection from OPA this.applicationConfig.setAuthAgentUrl("junk"); // R1 - String url = ConsumerConsts.API_ROOT + "/info-jobs/" + JOB_ID; + String url = ConsumerConsts.API_ROOT + "/info-jobs/" + jobId; testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized"); - String body = gson.toJson(consumerJobInfo(TYPE_ID, JOB_ID, "owner")); + String body = gson.toJson(consumerJobInfo(typeId, jobId, "owner")); testErrorCode(restClient().put(url, body), HttpStatus.UNAUTHORIZED, "Not authorized"); testErrorCode(restClient().get(url), HttpStatus.UNAUTHORIZED, "Not authorized"); // A1-E - url = A1eConsts.API_ROOT + "/eijobs/" + JOB_ID; + url = A1eConsts.API_ROOT + "/eijobs/" + jobId; testErrorCode(restClient().get(url), HttpStatus.UNAUTHORIZED, "Not authorized"); testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized"); - body = gson.toJson(eiJobInfo(TYPE_ID, JOB_ID, "owner")); + body = gson.toJson(eiJobInfo(typeId, jobId, "owner")); testErrorCode(restClient().put(url, body), HttpStatus.UNAUTHORIZED, "Not authorized"); } @@ -1314,8 +1313,8 @@ class ApplicationTest { Path authFile = Files.createTempFile("icsTestAuthToken", ".txt"); Files.write(authFile, AUTH_TOKEN.getBytes()); this.securityContext.setAuthTokenFilePath(authFile); - putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); - putInfoJob(TYPE_ID, "jobId"); + putInfoProducerWithOneType(producerId, typeId); + putInfoJob(typeId, "jobId"); // Test that authorization header is sent to the producer. await().untilAsserted(() -> assertThat(this.producerSimulator.getTestResults().receivedHeaders).hasSize(1)); @@ -1325,7 +1324,7 @@ class ApplicationTest { Files.delete(authFile); // Test that it works when the file is deleted. The cached header is used - putInfoJob(TYPE_ID, "jobId2"); + putInfoJob(typeId, "jobId2"); await().untilAsserted(() -> assertThat(this.infoJobs.size()).isEqualByComparingTo(2)); headers = this.producerSimulator.getTestResults().receivedHeaders.get(1); assertThat(headers).containsEntry("authorization", "Bearer " + AUTH_TOKEN); @@ -1348,7 +1347,7 @@ class ApplicationTest { StepVerifier.create(restClient().get(ConsumerConsts.API_ROOT + "/info-jobs")) // Any call .expectSubscription() // - .expectErrorMatches(t -> t instanceof WebClientRequestException) // + .expectErrorMatches(WebClientRequestException.class::isInstance) // .verify(); } @@ -1375,44 +1374,40 @@ class ApplicationTest { assertThat(statusInfo.opState).isEqualTo(expectedOperationalState); } - ProducerInfoTypeInfo ProducerInfoTypeRegistrationInfo(String typeId) - throws JsonMappingException, JsonProcessingException { + ProducerInfoTypeInfo ProducerInfoTypeRegistrationInfo() { return new ProducerInfoTypeInfo(jsonSchemaObject(), typeSpecifcInfoObject()); } - ProducerRegistrationInfo producerEiRegistratioInfoRejecting(String typeId) - throws JsonMappingException, JsonProcessingException { + ProducerRegistrationInfo producerEiRegistratioInfoRejecting(String typeId) { return new ProducerRegistrationInfo(Arrays.asList(typeId), // baseUrl() + ProducerSimulatorController.JOB_ERROR_URL, baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL); } - ProducerRegistrationInfo producerInfoRegistratioInfo(String typeId) - throws JsonMappingException, JsonProcessingException { + ProducerRegistrationInfo producerInfoRegistratioInfo(String typeId) { return new ProducerRegistrationInfo(Arrays.asList(typeId), // baseUrl() + ProducerSimulatorController.JOB_URL, baseUrl() + ProducerSimulatorController.SUPERVISION_URL); } - private ConsumerJobInfo consumerJobInfo() throws JsonMappingException, JsonProcessingException { - return consumerJobInfo(TYPE_ID, JOB_ID, "owner"); + private ConsumerJobInfo consumerJobInfo() { + return consumerJobInfo(typeId, jobId, "owner"); } - ConsumerJobInfo consumerJobInfo(String typeId, String infoJobId, String owner) - throws JsonMappingException, JsonProcessingException { + ConsumerJobInfo consumerJobInfo(String typeId, String infoJobId, String owner) { return new ConsumerJobInfo(typeId, jsonObject(owner), owner, "https://junk.com", baseUrl() + A1eCallbacksSimulatorController.getJobStatusUrl(infoJobId)); } - private A1eEiJobInfo eiJobInfo() throws Exception { - return eiJobInfo(TYPE_ID, JOB_ID); + private A1eEiJobInfo eiJobInfo() { + return eiJobInfo(typeId, jobId); } - A1eEiJobInfo eiJobInfo(String typeId, String infoJobId) throws Exception { + A1eEiJobInfo eiJobInfo(String typeId, String infoJobId) { return eiJobInfo(typeId, infoJobId, "owner"); } - A1eEiJobInfo eiJobInfo(String typeId, String infoJobId, String owner) throws Exception { + A1eEiJobInfo eiJobInfo(String typeId, String infoJobId, String owner) { return new A1eEiJobInfo(typeId, jsonObject(owner), owner, "https://junk.com", baseUrl() + A1eCallbacksSimulatorController.getJobStatusUrl(infoJobId)); } @@ -1426,7 +1421,7 @@ class ApplicationTest { } private Object jsonObject(String aValue) { - return toJsonObject("{ " + EI_JOB_PROPERTY + " : \"" + aValue + "\" }"); + return toJsonObject("{ " + eiJobProperty + " : \"" + aValue + "\" }"); } private Object typeSpecifcInfoObject() { @@ -1439,12 +1434,12 @@ class ApplicationTest { + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," // + "\"type\": \"object\"," // + "\"properties\": {" // - + EI_JOB_PROPERTY + " : {" // + + eiJobProperty + " : {" // + " \"type\": \"string\"" // + " }" // + "}," // + "\"required\": [" // - + EI_JOB_PROPERTY // + + eiJobProperty // + "]" // + "}"; // return toJsonObject(schemaStr); @@ -1471,9 +1466,9 @@ class ApplicationTest { } private HttpStatusCode putInfoType(String infoTypeId) - throws JsonMappingException, JsonProcessingException, ServiceException { + throws ServiceException { String url = ProducerConsts.API_ROOT + "/info-types/" + infoTypeId; - String body = gson.toJson(ProducerInfoTypeRegistrationInfo(infoTypeId)); + String body = gson.toJson(ProducerInfoTypeRegistrationInfo()); ResponseEntity resp = restClient().putForEntity(url, body).block(); this.infoTypes.getType(infoTypeId); @@ -1489,7 +1484,7 @@ class ApplicationTest { } private InfoType putInfoProducerWithOneTypeRejecting(String producerId, String infoTypeId) - throws JsonMappingException, JsonProcessingException, ServiceException { + throws ServiceException { this.putInfoType(infoTypeId); String url = ProducerConsts.API_ROOT + "/info-producers/" + producerId; String body = gson.toJson(producerEiRegistratioInfoRejecting(infoTypeId)); @@ -1498,7 +1493,7 @@ class ApplicationTest { } private InfoType putInfoProducerWithOneType(String producerId, String infoTypeId) - throws JsonMappingException, JsonProcessingException, ServiceException { + throws ServiceException { if (this.infoTypes.get(infoTypeId) == null) { this.putInfoType(infoTypeId); } diff --git a/src/test/java/org/oransc/ics/MockInformationService.java b/src/test/java/org/oransc/ics/MockInformationService.java index a2ce52b..a4c7061 100644 --- a/src/test/java/org/oransc/ics/MockInformationService.java +++ b/src/test/java/org/oransc/ics/MockInformationService.java @@ -52,9 +52,9 @@ class MockInformationService { InfoJobs infoJobs; @Test - @SuppressWarnings("squid:S2699") + @SuppressWarnings({"squid:S2699", "squid:S2925" }) void runMock() throws Exception { - logger.warn("**************** Keeping server alive! " + this.port); + logger.warn("**************** Keeping server alive! {}", this.port); synchronized (this) { while (true) { System.out.println("**** Types *** "); diff --git a/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java b/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java index 3f5f78d..0627011 100644 --- a/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java +++ b/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,7 +85,7 @@ class AsyncRestClientTest { Mono returnedMono = clientUnderTest.get(REQUEST_URL); StepVerifier.create(returnedMono) - .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify(); + .expectErrorMatches(WebClientResponseException.class::isInstance).verify(); } @Test @@ -103,7 +104,7 @@ class AsyncRestClientTest { Mono returnedMono = clientUnderTest.put(REQUEST_URL, TEST_JSON); StepVerifier.create(returnedMono) - .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify(); + .expectErrorMatches(WebClientResponseException.class::isInstance).verify(); } @Test @@ -120,7 +121,7 @@ class AsyncRestClientTest { Mono returnedMono = clientUnderTest.delete(REQUEST_URL); StepVerifier.create(returnedMono) - .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify(); + .expectErrorMatches(WebClientResponseException.class::isInstance).verify(); } @Test @@ -139,7 +140,7 @@ class AsyncRestClientTest { Mono returnedMono = clientUnderTest.post(REQUEST_URL, TEST_JSON); StepVerifier.create(returnedMono) - .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify(); + .expectErrorMatches(WebClientResponseException.class::isInstance).verify(); } @Test @@ -158,6 +159,6 @@ class AsyncRestClientTest { Mono returnedMono = clientUnderTest.postWithAuthHeader(REQUEST_URL, TEST_JSON, USERNAME, PASSWORD); StepVerifier.create(returnedMono) - .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify(); + .expectErrorMatches(WebClientResponseException.class::isInstance).verify(); } } diff --git a/src/test/java/org/oransc/ics/controller/OpenPolicyAgentSimulatorController.java b/src/test/java/org/oransc/ics/controller/OpenPolicyAgentSimulatorController.java index f711ca9..5af422d 100644 --- a/src/test/java/org/oransc/ics/controller/OpenPolicyAgentSimulatorController.java +++ b/src/test/java/org/oransc/ics/controller/OpenPolicyAgentSimulatorController.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,6 +69,7 @@ public class OpenPolicyAgentSimulatorController { Collections.synchronizedList(new ArrayList()); public TestResults() { + //empty class } public void reset() { diff --git a/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java b/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java index 76207c1..fba152f 100644 --- a/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java +++ b/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java @@ -2,7 +2,8 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2023-2025 OpenInfra Foundation Europe * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,6 +77,7 @@ public class ProducerSimulatorController { public boolean errorFound = false; public TestResults() { + // empty class } public void reset() { @@ -89,7 +91,7 @@ public class ProducerSimulatorController { } @Getter - private TestResults testResults = new TestResults(); + private final TestResults testResults = new TestResults(); @PostMapping(path = JOB_URL, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(