From b7e91e0a92ecc0254bb66d560e38cf06e6f76ebb Mon Sep 17 00:00:00 2001 From: "k.kedron" Date: Mon, 20 Sep 2021 10:06:26 +0200 Subject: Refactoring - ves to report package - fileready to pm package - according method name Issue-ID: INT-1945 Signed-off-by: Krystian Kedron Change-Id: I2f22c828145727ba772440fe111b5fde34446b3a --- .../controller/RanCellController.java | 32 +- .../controller/RanEventConfigureController.java | 18 +- .../data/fileready/RanPeriodicSendReport.java | 2 +- .../a1/SetLowRangeValuesOnPolicyAction.java | 6 +- .../service/cell/RanCellServiceImpl.java | 2 +- .../service/common/AbstractRanRunnable.java | 2 +- .../service/fileready/FileReadyEventService.java | 159 ---------- .../service/fileready/FtpServerService.java | 215 ------------- .../service/fileready/PMBulkFileService.java | 333 --------------------- .../service/fileready/RanFileReadyHolder.java | 178 ----------- .../fileready/RanSaveFileReadyRunnable.java | 54 ---- .../service/fileready/RanSendReportsRunnable.java | 28 -- .../service/pm/FileReadyEventService.java | 159 ++++++++++ .../a1pesimulator/service/pm/FtpServerService.java | 215 +++++++++++++ .../service/pm/PMBulkFileService.java | 333 +++++++++++++++++++++ .../service/pm/RanFileReadyHolder.java | 178 +++++++++++ .../service/pm/RanSaveFileReadyRunnable.java | 54 ++++ .../service/pm/RanSendReportsRunnable.java | 28 ++ .../service/report/OnEventAction.java | 22 ++ .../service/report/RanCellEventCustomizer.java | 73 +++++ .../report/RanCellFailureEventCustomizer.java | 227 ++++++++++++++ .../service/report/RanCheckCellIsDeadOnEvent.java | 126 ++++++++ .../service/report/RanEventCustomizerFactory.java | 49 +++ .../service/report/RanReportsBrokerService.java | 50 ++++ .../report/RanReportsBrokerServiceImpl.java | 128 ++++++++ .../service/report/RanSendVesRunnable.java | 43 +++ .../service/report/RanVesDataProvider.java | 108 +++++++ .../a1pesimulator/service/report/RanVesHolder.java | 240 +++++++++++++++ .../a1pesimulator/service/report/RanVesSender.java | 100 +++++++ .../a1pesimulator/service/ves/OnEventAction.java | 22 -- .../service/ves/RanCellEventCustomizer.java | 73 ----- .../service/ves/RanCellFailureEventCustomizer.java | 227 -------------- .../service/ves/RanCheckCellIsDeadOnEvent.java | 126 -------- .../service/ves/RanEventCustomizerFactory.java | 49 --- .../service/ves/RanSendVesRunnable.java | 43 --- .../service/ves/RanVesBrokerService.java | 50 ---- .../service/ves/RanVesBrokerServiceImpl.java | 128 -------- .../service/ves/RanVesDataProvider.java | 108 ------- .../a1pesimulator/service/ves/RanVesHolder.java | 240 --------------- .../a1pesimulator/service/ves/RanVesSender.java | 100 ------- .../service/VesBrokerServiceImplTest.java | 8 +- .../service/cell/RanCellStateServiceTest.java | 2 +- .../service/fileready/CommonFileReady.java | 163 ---------- .../fileready/FileReadyEventServiceTest.java | 91 ------ .../service/fileready/FtpServerServiceTest.java | 156 ---------- .../service/fileready/PMBulkFileServiceTest.java | 51 ---- .../service/fileready/RanFileReadyHolderTest.java | 154 ---------- .../fileready/RanSaveFileReadyRunnableTest.java | 74 ----- .../fileready/RanSendReportsRunnableTest.java | 55 ---- .../a1pesimulator/service/pm/CommonFileReady.java | 163 ++++++++++ .../service/pm/FileReadyEventServiceTest.java | 91 ++++++ .../service/pm/FtpServerServiceTest.java | 156 ++++++++++ .../service/pm/PMBulkFileServiceTest.java | 51 ++++ .../service/pm/RanFileReadyHolderTest.java | 154 ++++++++++ .../service/pm/RanSaveFileReadyRunnableTest.java | 74 +++++ .../service/pm/RanSendReportsRunnableTest.java | 55 ++++ .../service/report/RanVesHolderTest.java | 143 +++++++++ .../service/ves/RanVesHolderTest.java | 143 --------- 58 files changed, 3056 insertions(+), 3056 deletions(-) delete mode 100644 src/main/java/org/onap/a1pesimulator/service/fileready/FileReadyEventService.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/fileready/FtpServerService.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/fileready/PMBulkFileService.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolder.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnable.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnable.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/pm/FileReadyEventService.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/pm/FtpServerService.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/pm/PMBulkFileService.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolder.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnable.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnable.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/OnEventAction.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanCellEventCustomizer.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanCellFailureEventCustomizer.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanCheckCellIsDeadOnEvent.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanEventCustomizerFactory.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerService.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerServiceImpl.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanSendVesRunnable.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanVesDataProvider.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanVesHolder.java create mode 100644 src/main/java/org/onap/a1pesimulator/service/report/RanVesSender.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/OnEventAction.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanCellEventCustomizer.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanCellFailureEventCustomizer.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanCheckCellIsDeadOnEvent.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanEventCustomizerFactory.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanSendVesRunnable.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerService.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerServiceImpl.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanVesDataProvider.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanVesHolder.java delete mode 100644 src/main/java/org/onap/a1pesimulator/service/ves/RanVesSender.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/fileready/CommonFileReady.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/fileready/FileReadyEventServiceTest.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/fileready/FtpServerServiceTest.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/fileready/PMBulkFileServiceTest.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolderTest.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnableTest.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnableTest.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/pm/CommonFileReady.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/pm/FileReadyEventServiceTest.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/pm/FtpServerServiceTest.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/pm/PMBulkFileServiceTest.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolderTest.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnableTest.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnableTest.java create mode 100644 src/test/java/org/onap/a1pesimulator/service/report/RanVesHolderTest.java delete mode 100644 src/test/java/org/onap/a1pesimulator/service/ves/RanVesHolderTest.java diff --git a/src/main/java/org/onap/a1pesimulator/controller/RanCellController.java b/src/main/java/org/onap/a1pesimulator/controller/RanCellController.java index 10dfe2b..0074058 100644 --- a/src/main/java/org/onap/a1pesimulator/controller/RanCellController.java +++ b/src/main/java/org/onap/a1pesimulator/controller/RanCellController.java @@ -22,7 +22,7 @@ import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; import org.onap.a1pesimulator.data.ves.VesEvent; import org.onap.a1pesimulator.service.cell.RanCellService; import org.onap.a1pesimulator.service.cell.RanCellStateService; -import org.onap.a1pesimulator.service.ves.RanVesBrokerService; +import org.onap.a1pesimulator.service.report.RanReportsBrokerService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -44,13 +44,13 @@ public class RanCellController { private static final Logger log = LoggerFactory.getLogger(RanCellController.class); private final RanCellService ranCellService; private final RanCellStateService ranCellStateService; - private final RanVesBrokerService ranVesBrokerService; + private final RanReportsBrokerService ranReportsBrokerService; public RanCellController(RanCellService ranCellService, RanCellStateService ranCellStateService, - RanVesBrokerService ranVesBrokerService) { + RanReportsBrokerService ranReportsBrokerService) { this.ranCellService = ranCellService; this.ranCellStateService = ranCellStateService; - this.ranVesBrokerService = ranVesBrokerService; + this.ranReportsBrokerService = ranReportsBrokerService; } @GetMapping @@ -65,11 +65,11 @@ public class RanCellController { @ApiOperation("Start sending failure VES events for specific cell") @PostMapping(value = "/{identifier}/startFailure") - public ResponseEntity startSendingFailureVesEvents(@ApiParam(value = "Cell Id") final @PathVariable String identifier, + public ResponseEntity startSendingFailureReports(@ApiParam(value = "Cell Id") final @PathVariable String identifier, @ApiParam(value = "Reporting Method", defaultValue = "FILE_READY", required = true) final @RequestParam() ReportingMethodEnum reportingMethod) { checkIfCellExistOrThrowException(identifier); ranCellService.failure(identifier); - ranVesBrokerService.startSendingFailureVesEvents(identifier, reportingMethod); + ranReportsBrokerService.startSendingFailureReports(identifier, reportingMethod); ranCellStateService.failingState(identifier); return ResponseEntity.accepted().body("Failure VES Event sending started"); @@ -77,11 +77,11 @@ public class RanCellController { @ApiOperation("Stop sending failure VES events for specific cell") @PostMapping(value = "/{identifier}/stopFailure") - public ResponseEntity stopSendingFailureVesEvents(@ApiParam(value = "Cell Id") final @PathVariable String identifier) { + public ResponseEntity stopSendingFailureReports(@ApiParam(value = "Cell Id") final @PathVariable String identifier) { checkIfCellExistOrThrowException(identifier); ranCellService.recoverFromFailure(identifier); - Optional vesEvent = ranVesBrokerService.stopSendingVesEvents(identifier); + Optional vesEvent = ranReportsBrokerService.stopSendingReports(identifier); if (!vesEvent.isPresent()) { return ResponseEntity.notFound().build(); @@ -93,17 +93,17 @@ public class RanCellController { @ApiOperation("Start sending normal VES events for specific cell and in specific granularity period") @PostMapping(value = "/{identifier}/start") - public ResponseEntity startSendingVesEvents(@ApiParam(value = "Standard Measurement Event JSON") final @RequestBody Optional vesEventOpt, + public ResponseEntity startSendingReports(@ApiParam(value = "Standard Measurement Event JSON") final @RequestBody Optional vesEventOpt, @ApiParam(value = "Cell Id") final @PathVariable String identifier, @ApiParam(value = "Granularity period in seconds", example = "60") final @RequestParam(required = false) Integer interval, @ApiParam(value = "Reporting Method", defaultValue = "FILE_READY", required = true) final @RequestParam() ReportingMethodEnum reportingMethod) { checkIfCellExistOrThrowException(identifier); log.info("Start sending ves events every {} seconds for {} ", getInterval(interval), identifier); - VesEvent vesEvent = vesEventOpt.orElse(ranVesBrokerService.getGlobalPmVesStructure()); + VesEvent vesEvent = vesEventOpt.orElse(ranReportsBrokerService.getGlobalPmVesStructure()); ResponseEntity responseEntity = - ranVesBrokerService.startSendingVesEvents(identifier, vesEvent, getInterval(interval), reportingMethod); + ranReportsBrokerService.startSendingReports(identifier, vesEvent, getInterval(interval), reportingMethod); if (!responseEntity.getStatusCode().is2xxSuccessful()) { return responseEntity; } @@ -114,10 +114,10 @@ public class RanCellController { @ApiOperation("Stop sending normal VES events for specific cell") @PostMapping(value = "/{identifier}/stop") - public ResponseEntity stopSendingVesEvents(@ApiParam(value = "Cell Id") final @PathVariable String identifier) { + public ResponseEntity stopSendingReports(@ApiParam(value = "Cell Id") final @PathVariable String identifier) { checkIfCellExistOrThrowException(identifier); log.info("Stop sending custom ves events for {}", identifier); - Optional vesEvent = ranVesBrokerService.stopSendingVesEvents(identifier); + Optional vesEvent = ranReportsBrokerService.stopSendingReports(identifier); if (!vesEvent.isPresent()) { return ResponseEntity.notFound().build(); } @@ -129,15 +129,15 @@ public class RanCellController { @GetMapping(value = "/{identifier}/pmConfig") public ResponseEntity getPMConfig(final @PathVariable String identifier) { checkIfCellExistOrThrowException(identifier); - if (!ranVesBrokerService.getEnabledEventElementIdentifiers().contains(identifier)) { + if (!ranReportsBrokerService.getEnabledEventElementIdentifiers().contains(identifier)) { return ResponseEntity.notFound().build(); } - return ResponseEntity.ok(ranVesBrokerService.getPeriodicEvent(identifier)); + return ResponseEntity.ok(ranReportsBrokerService.getPeriodicEvent(identifier)); } private Integer getInterval(Integer requested) { if (requested == null) { - return ranVesBrokerService.getGlobalVesInterval(); + return ranReportsBrokerService.getGlobalVesInterval(); } return requested; } diff --git a/src/main/java/org/onap/a1pesimulator/controller/RanEventConfigureController.java b/src/main/java/org/onap/a1pesimulator/controller/RanEventConfigureController.java index 5b5037c..79bddf0 100644 --- a/src/main/java/org/onap/a1pesimulator/controller/RanEventConfigureController.java +++ b/src/main/java/org/onap/a1pesimulator/controller/RanEventConfigureController.java @@ -14,7 +14,7 @@ package org.onap.a1pesimulator.controller; import org.onap.a1pesimulator.data.ves.GlobalVesConfiguration; -import org.onap.a1pesimulator.service.ves.RanVesBrokerService; +import org.onap.a1pesimulator.service.report.RanReportsBrokerService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -26,24 +26,24 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping({"${restapi.version}/ran/globalPMConfig"}) public class RanEventConfigureController { - private final RanVesBrokerService ranVesBrokerService; + private final RanReportsBrokerService ranReportsBrokerService; - public RanEventConfigureController(RanVesBrokerService ranVesBrokerService) { - this.ranVesBrokerService = ranVesBrokerService; + public RanEventConfigureController(RanReportsBrokerService ranReportsBrokerService) { + this.ranReportsBrokerService = ranReportsBrokerService; } @GetMapping public ResponseEntity getGlobalPMConfig() { - GlobalVesConfiguration config = new GlobalVesConfiguration(ranVesBrokerService.getGlobalVesInterval(), - ranVesBrokerService.getGlobalPmVesStructure(), ranVesBrokerService.getGlobalReportingMethod()); + GlobalVesConfiguration config = new GlobalVesConfiguration(ranReportsBrokerService.getGlobalVesInterval(), + ranReportsBrokerService.getGlobalPmVesStructure(), ranReportsBrokerService.getGlobalReportingMethod()); return ResponseEntity.ok(config); } @PostMapping public ResponseEntity setGlobalPMConfig(final @RequestBody GlobalVesConfiguration config) { - ranVesBrokerService.setGlobalPmVesStructure(config.getEvent()); - ranVesBrokerService.setGlobalVesInterval(config.getInterval()); - ranVesBrokerService.setGlobalReportingMethod(config.getReportingMethod()); + ranReportsBrokerService.setGlobalPmVesStructure(config.getEvent()); + ranReportsBrokerService.setGlobalVesInterval(config.getInterval()); + ranReportsBrokerService.setGlobalReportingMethod(config.getReportingMethod()); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/org/onap/a1pesimulator/data/fileready/RanPeriodicSendReport.java b/src/main/java/org/onap/a1pesimulator/data/fileready/RanPeriodicSendReport.java index ca812e7..c51dc1c 100644 --- a/src/main/java/org/onap/a1pesimulator/data/fileready/RanPeriodicSendReport.java +++ b/src/main/java/org/onap/a1pesimulator/data/fileready/RanPeriodicSendReport.java @@ -15,7 +15,7 @@ package org.onap.a1pesimulator.data.fileready; import java.util.concurrent.ScheduledFuture; -import org.onap.a1pesimulator.service.fileready.RanSendReportsRunnable; +import org.onap.a1pesimulator.service.pm.RanSendReportsRunnable; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/org/onap/a1pesimulator/service/a1/SetLowRangeValuesOnPolicyAction.java b/src/main/java/org/onap/a1pesimulator/service/a1/SetLowRangeValuesOnPolicyAction.java index 29c55de..ab5002d 100644 --- a/src/main/java/org/onap/a1pesimulator/service/a1/SetLowRangeValuesOnPolicyAction.java +++ b/src/main/java/org/onap/a1pesimulator/service/a1/SetLowRangeValuesOnPolicyAction.java @@ -18,7 +18,7 @@ import java.util.List; import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; import org.onap.a1pesimulator.data.ves.VesEvent; import org.onap.a1pesimulator.data.ves.MeasurementFields.AdditionalMeasurement; -import org.onap.a1pesimulator.service.ves.RanVesBrokerService; +import org.onap.a1pesimulator.service.report.RanReportsBrokerService; import org.onap.a1pesimulator.util.JsonUtils; import org.onap.a1pesimulator.util.RanVesUtils; import org.springframework.stereotype.Service; @@ -26,9 +26,9 @@ import org.springframework.stereotype.Service; @Service public class SetLowRangeValuesOnPolicyAction implements OnPolicyAction { - private final RanVesBrokerService vesBrokerService; + private final RanReportsBrokerService vesBrokerService; - public SetLowRangeValuesOnPolicyAction(RanVesBrokerService vesBrokerService) { + public SetLowRangeValuesOnPolicyAction(RanReportsBrokerService vesBrokerService) { this.vesBrokerService = vesBrokerService; } diff --git a/src/main/java/org/onap/a1pesimulator/service/cell/RanCellServiceImpl.java b/src/main/java/org/onap/a1pesimulator/service/cell/RanCellServiceImpl.java index 0c0ab00..10a598c 100644 --- a/src/main/java/org/onap/a1pesimulator/service/cell/RanCellServiceImpl.java +++ b/src/main/java/org/onap/a1pesimulator/service/cell/RanCellServiceImpl.java @@ -23,7 +23,7 @@ import org.onap.a1pesimulator.data.cell.CellWithStatus; import org.onap.a1pesimulator.data.cell.RanCell; import org.onap.a1pesimulator.data.ue.UserEquipment; import org.onap.a1pesimulator.service.ue.RanUeHolder; -import org.onap.a1pesimulator.service.ves.RanVesHolder; +import org.onap.a1pesimulator.service.report.RanVesHolder; import org.springframework.stereotype.Service; @Service diff --git a/src/main/java/org/onap/a1pesimulator/service/common/AbstractRanRunnable.java b/src/main/java/org/onap/a1pesimulator/service/common/AbstractRanRunnable.java index bd5e2a9..700d336 100644 --- a/src/main/java/org/onap/a1pesimulator/service/common/AbstractRanRunnable.java +++ b/src/main/java/org/onap/a1pesimulator/service/common/AbstractRanRunnable.java @@ -16,7 +16,7 @@ package org.onap.a1pesimulator.service.common; import java.util.Collection; import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.service.ves.OnEventAction; +import org.onap.a1pesimulator.service.report.OnEventAction; public abstract class AbstractRanRunnable implements Runnable { diff --git a/src/main/java/org/onap/a1pesimulator/service/fileready/FileReadyEventService.java b/src/main/java/org/onap/a1pesimulator/service/fileready/FileReadyEventService.java deleted file mode 100644 index 98f0733..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/fileready/FileReadyEventService.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.onap.a1pesimulator.service.fileready.FtpServerService.deletePMBulkFile; -import static org.onap.a1pesimulator.util.Constants.FILE_READY_CHANGE_IDENTIFIER; -import static org.onap.a1pesimulator.util.Constants.FILE_READY_CHANGE_TYPE; - -import java.io.File; -import java.time.Instant; -import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.onap.a1pesimulator.data.fileready.FileData; -import org.onap.a1pesimulator.data.fileready.FileReadyEvent; -import org.onap.a1pesimulator.data.fileready.NotificationFields; -import org.onap.a1pesimulator.data.fileready.NotificationFields.ArrayOfNamedHashMap; -import org.onap.a1pesimulator.data.ves.CommonEventHeader; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import reactor.core.publisher.Mono; - -/** - * Service for PM Bulk File creation and its handling - */ - -@Service -public class FileReadyEventService { - - private final FtpServerService ftpServerService; - - @Value("${file.ready.version}") - private String version; - - @Value("${file.ready.vesEventListenerVersion}") - private String vesEventListenerVersion; - - @Value("${file.ready.domain}") - private String domain; - - @Value("${file.ready.eventName}") - private String eventName; - - @Value("${file.ready.fileFormatType}") - private String fileFormatType; - - @Value("${file.ready.fileFormatVersion}") - private String fileFormatVersion; - - @Value("${file.ready.notificationFieldsVersion}") - private String notificationFieldsVersion; - - @Value("${file.ready.priority}") - private String priority; - - @Value("${file.ready.reportingEntityName}") - private String reportingEntityName; - - public FileReadyEventService(FtpServerService ftpServerService) { - this.ftpServerService = ftpServerService; - } - - /** - * It will create FileReadyEvent.json which will go to VES Collector - * - * @return created FileReadyEvent - */ - protected Mono createFileReadyEventAndDeleteTmpFile(Mono fileMono) { - return fileMono - .map(this::createFileReadyEvent) - .doOnNext(file -> deleteTempArchivedBulkFile(file.getArchivedPmBulkFile())); - } - - /** - * Creates File Ready Event - * - * @param fileData information about PM Bulk Files created in previous steps - * @return added newly created FileReadyEvent to FileData - */ - protected FileData createFileReadyEvent(FileData fileData) { - FileReadyEvent event = new FileReadyEvent(); - CommonEventHeader commonEventHeader = getCommonHeader(); - event.setCommonEventHeader(commonEventHeader); - commonEventHeader.setStartEpochMicrosec(ChronoUnit.MICROS.between(Instant.EPOCH, fileData.getStartEventDate())); - commonEventHeader.setLastEpochMicrosec(ChronoUnit.MICROS.between(Instant.EPOCH, fileData.getEndEventDate())); - event.setNotificationFields(getNotificationFields(fileData.getArchivedPmBulkFile().getName())); - fileData.setFileReadyEvent(event); - return fileData; - } - - /** - * Creates NotificationFields section in FileReadyEvent - * - * @param fileName name of archived PM Bulk File - * @return NotificationFields object - */ - private NotificationFields getNotificationFields(String fileName) { - NotificationFields notificationFields = NotificationFields.builder() - .changeIdentifier(FILE_READY_CHANGE_IDENTIFIER) - .changeType(FILE_READY_CHANGE_TYPE) - .notificationFieldsVersion(notificationFieldsVersion).build(); - - ArrayOfNamedHashMap arrayOfNamedHashMap = new ArrayOfNamedHashMap(); - Map hashMapItems = new HashMap<>(); - hashMapItems.put("location", ftpServerService.getFtpPath() + fileName); - hashMapItems.put("compression", "gzip"); - hashMapItems.put("fileFormatType", fileFormatType); - hashMapItems.put("fileFormatVersion", fileFormatVersion); - - arrayOfNamedHashMap.setName(fileName); - arrayOfNamedHashMap.setHashMap(hashMapItems); - notificationFields.setArrayOfNamedHashMap(Collections.singletonList(arrayOfNamedHashMap)); - return notificationFields; - } - - /** - * Creates CommonEventHeader - * - * @return created CommonEventHeader - */ - private CommonEventHeader getCommonHeader() { - return CommonEventHeader.builder() - .version(version) - .vesEventListenerVersion(vesEventListenerVersion) - .domain(domain) - .eventName(eventName) - .eventId(UUID.randomUUID().toString()) - .priority(priority) - .reportingEntityName(reportingEntityName) - .sequence(0) - .timeZoneOffset(ZonedDateTime.now().getOffset().toString()) - .build(); - } - - /** - * Deletes temporary archived PM Bulk File - * - * @param fileMono temporary archived PM Bulk File - */ - private void deleteTempArchivedBulkFile(File fileMono) { - deletePMBulkFile(fileMono); - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/fileready/FtpServerService.java b/src/main/java/org/onap/a1pesimulator/service/fileready/FtpServerService.java deleted file mode 100644 index c02ffc3..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/fileready/FtpServerService.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static java.util.Objects.nonNull; -import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.util.zip.GZIPOutputStream; - - -import org.onap.a1pesimulator.data.fileready.FileData; -import org.onap.a1pesimulator.exception.NotUploadedToFtpException; -import org.onap.a1pesimulator.util.VnfConfigReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.util.FileCopyUtils; - -import net.schmizz.sshj.SSHClient; -import net.schmizz.sshj.sftp.SFTPClient; -import net.schmizz.sshj.transport.verification.PromiscuousVerifier; -import reactor.core.publisher.Mono; - -@Service -public class FtpServerService { - - private static final Logger log = LoggerFactory.getLogger(FtpServerService.class); - - //true - file will be uploaded to FTP; false - file will be copied into xmlPmLocation - @Value("${ftp.server.upload}") - private boolean ftpServerUpload; - - // location where archived file will be copied - @Value("${xml.pm.location}") - private String xmlPmLocation; - - @Value("${ftp.server.protocol}") - private String ftpServerProtocol; - - @Value("${ftp.server.filepath}") - private String ftpServerFilepath; - - @Value("${ftp.server.username}") - private String ftpServerUsername; - - @Value("${ftp.server.password}") - private String ftpServerPassword; - - private VnfConfigReader vnfConfigReader; - - public FtpServerService(VnfConfigReader vnfConfigReader) { - this.vnfConfigReader = vnfConfigReader; - } - - public Mono uploadFileToFtp(FileData fileData) { - return Mono.just(fileData) - .flatMap(this::tryToCompressFile) - .flatMap(this::tryToUploadOrSaveFileToFtp) - .onErrorResume(throwable -> resumeError(throwable, fileData)) - .doOnNext(file -> deletePMBulkFile(file.getPmBulkFile())); - } - - /** - * Trying to compress file into .gz - * - * @param fileData file to be archived - * @return archived file - */ - private Mono tryToCompressFile(FileData fileData) { - File archiveBulkFile = new File(TEMP_DIR, fileData.getPmBulkFile().getName() + ".gz"); - - try (GZIPOutputStream zos = new GZIPOutputStream( - new FileOutputStream(archiveBulkFile.getAbsolutePath())); FileInputStream inputStream = new FileInputStream(fileData.getPmBulkFile())) { - byte[] buffer = new byte[1024]; - int len; - while ((len = inputStream.read(buffer)) > 0) { - zos.write(buffer, 0, len); - } - fileData.setArchivedPmBulkFile(archiveBulkFile); - log.trace("Compressing file {}", fileData.getPmBulkFile().getName()); - return Mono.just(fileData); - } catch (IOException e) { - log.error("Could not compress file", e); - return Mono.empty(); - } - } - - /** - * Upload file to FTP or copy it to mounted location - * - * @param fileData data about file - * @return fileData for fileReadyEvent - */ - private Mono tryToUploadOrSaveFileToFtp(FileData fileData) { - if (ftpServerUpload) { - return tryToUploadFileToFtp(fileData); - } else { - File fileOnFtp = new File(xmlPmLocation, fileData.getArchivedPmBulkFile().getName()); - try { - FileCopyUtils.copy(fileData.getArchivedPmBulkFile(), fileOnFtp); - log.info("Uploading file to the location: {}", fileOnFtp); - return Mono.just(fileData); - } catch (IOException e) { - return Mono.error(new NotUploadedToFtpException("File was not copied to FTP location", e)); - } - } - } - - /** - * Upload file to FTP - * - * @param fileData archived file in Mono - * @return archived file for fileReadyEvent - */ - private Mono tryToUploadFileToFtp(FileData fileData) { - if (nonNull(fileData.getArchivedPmBulkFile())) { - SSHClient client = getSSHClient(); - if (nonNull(client)) { - try (client; SFTPClient sftpClient = client.newSFTPClient()) { - File archiveBulkFile = fileData.getArchivedPmBulkFile(); - sftpClient.put(archiveBulkFile.getAbsolutePath(), ftpServerFilepath + "/" + archiveBulkFile.getName()); - - log.info("Uploading file to FTP: {}", archiveBulkFile.getAbsoluteFile()); - return Mono.just(fileData); - } catch (IOException e) { - log.error("Exception while trying to upload a file", e); - } - } else { - log.error("Could not connect to FTP server"); - } - } else { - log.error("There is no file to upload"); - } - return Mono.error(new NotUploadedToFtpException("File was not uploaded to FTP")); - } - - /** - * Creates SSHClient instance - * - * @return SSHClient - */ - protected SSHClient getSSHClient() { - SSHClient client = new SSHClient(); - try { - client.addHostKeyVerifier(new PromiscuousVerifier()); - client.connect(vnfConfigReader.getVnfConfig().getFtpHost(), Integer.parseInt(vnfConfigReader.getVnfConfig().getFtpPort())); - client.authPassword(ftpServerUsername, ftpServerPassword); - return client; - } catch (IOException e) { - log.error("There was an error while connecting to FTP server", e); - try { - client.close(); - } catch (IOException ioException) { - log.error("There was an error while closing the connection to FTP server", e); - } - return null; - } - } - - /** - * Deletes created PM Bulk File xml from temp storage after successful upload to FTP - * - * @param file file which we gonna delete - */ - public static void deletePMBulkFile(File file) { - try { - log.trace("Deleting file: {}", file.getAbsoluteFile()); - Files.delete(file.toPath()); - } catch (IOException e) { - log.warn("Could not delete file: {}", file.getName(), e); - } - } - - /** - * Get path to FTP server - * - * @return for example: "sftp://foo:pass@106.120.119.170:2222/upload/" - */ - public String getFtpPath() { - return ftpServerProtocol + "://" + ftpServerUsername + ":" + ftpServerPassword + "@" + vnfConfigReader.getVnfConfig().getFtpHost() + ":" - + vnfConfigReader.getVnfConfig().getFtpPort() + "/" + ftpServerFilepath - + "/"; - } - - /** - * Try to clean up things after an exception - * - * @param throwable error thrown - * @param fileData data about files which needs to be deleted - * @return empty Mono object - */ - protected Mono resumeError(Throwable throwable, FileData fileData) { - log.error("Error occurs while uploading file to FTP server", throwable); - deletePMBulkFile(fileData.getPmBulkFile()); - deletePMBulkFile(fileData.getArchivedPmBulkFile()); - return Mono.empty(); - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/fileready/PMBulkFileService.java b/src/main/java/org/onap/a1pesimulator/service/fileready/PMBulkFileService.java deleted file mode 100644 index 813c8a4..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/fileready/PMBulkFileService.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static java.util.Comparator.comparing; -import static java.util.Objects.isNull; -import static org.onap.a1pesimulator.util.Constants.EMPTY_STRING; -import static org.onap.a1pesimulator.util.Constants.MEASUREMENT_FIELD_IDENTIFIER; -import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; -import static org.onap.a1pesimulator.util.Convertors.ISO_8601_DATE; -import static org.onap.a1pesimulator.util.Convertors.YYYYMMDD_PATTERN; -import static org.onap.a1pesimulator.util.Convertors.truncateToSpecifiedMinutes; -import static org.onap.a1pesimulator.util.Convertors.zonedDateTimeToString; - -import java.io.File; -import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Stream; - -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; -import org.onap.a1pesimulator.data.fileready.FileData; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.util.VnfConfigReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import reactor.core.publisher.Mono; - -/** - * Service for PM Bulk File creation and handling - */ - -@Service -public class PMBulkFileService { - - private static final Logger log = LoggerFactory.getLogger(PMBulkFileService.class); - private static Map uniqueFileNamesWithCount; - private final VnfConfigReader vnfConfigReader; - - @Value("${xml.pm.bulk.fileFormatVersion}") - private String fileFormatVersion; - - @Value("${xml.pm.bulk.vendorName}") - private String vendorName; - - @Value("${xml.pm.bulk.fileSender}") - private String fileSenderValue; - - @Value("${xml.pm.bulk.userLabel}") - private String userLabel; - - @Value("${xml.pm.bulk.domainId}") - private String domainId; - - public PMBulkFileService(VnfConfigReader vnfConfigReader) { - this.vnfConfigReader = vnfConfigReader; - } - - /** - * Generate PM Bulk File xml from stored events - * - * @param collectedEvents list of stored events - * @return generated file in Mono object - */ - public Mono generatePMBulkFileXml(List collectedEvents) { - - try { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); - - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - - //root elements - Document doc = docBuilder.newDocument(); - - Element measCollecFile = doc.createElement("measCollecFile"); - doc.appendChild(measCollecFile); - measCollecFile.setAttribute("xmlns", "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec"); - measCollecFile.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); - measCollecFile.setAttribute("xsi:schemaLocation", - "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec"); - - //fileHeader elements - Element fileHeader = doc.createElement("fileHeader"); - measCollecFile.appendChild(fileHeader); - fileHeader.setAttribute("fileFormatVersion", fileFormatVersion); - fileHeader.setAttribute("vendorName", vendorName); - - //fileSender elements - Element fileSender = doc.createElement("fileSender"); - fileHeader.appendChild(fileSender); - fileSender.setAttribute("elementType", fileSenderValue); - - //measCollec elements - Element measCollec = doc.createElement("measCollec"); - fileHeader.appendChild(measCollec); - measCollec.setAttribute("beginTime", zonedDateTimeToString(earliestEventTime(collectedEvents), ISO_8601_DATE)); - - //measData elements - Element measData = doc.createElement("measData"); - measCollecFile.appendChild(measData); - - //managedElement elements - Element managedElement = doc.createElement("managedElement"); - measData.appendChild(managedElement); - managedElement.setAttribute("userLabel", userLabel); - - //add measInfo elements - addMeansInfo(doc, measData, collectedEvents); - - //fileFooter elements - Element fileFooter = doc.createElement("fileFooter"); - measCollecFile.appendChild(fileFooter); - - Element measCollecFooter = doc.createElement("measCollec"); - fileFooter.appendChild(measCollecFooter); - measCollecFooter.setAttribute("endTime", zonedDateTimeToString(latestEventTime(collectedEvents), ISO_8601_DATE)); - - File xmlFile = writeDocumentIntoXmlFile(doc, collectedEvents); - - Mono justMono = Mono.just(FileData.builder().pmBulkFile(xmlFile).startEventDate(earliestEventTime(collectedEvents)) - .endEventDate(latestEventTime(collectedEvents)).build()); - log.trace("Removing all VES events from memory: {}", collectedEvents.size()); - collectedEvents.clear(); - return justMono; - - } catch (ParserConfigurationException | TransformerException pce) { - log.error("Error occurs while creating PM Bulk File", pce); - return Mono.empty(); - } - } - - /** - * Add measurement elements for each cell and measurement time into PM Bulk File - * - * @param doc Document - * @param measData main element of document, which stores meansData - * @param collectedEvents list of stored events - */ - private void addMeansInfo(Document doc, Element measData, List collectedEvents) { - collectedEvents.stream().sorted(comparing(EventMemoryHolder::getEventDate)).forEach(eventMemoryHolder -> { - VesEvent event = eventMemoryHolder.getEvent(); - - Element measInfo = doc.createElement("measInfo"); - measData.appendChild(measInfo); - - //job element - Element job = doc.createElement("job"); - measInfo.appendChild(job); - job.setAttribute("jobId", eventMemoryHolder.getJobId()); - - //granPeriod elements - Element granPeriod = doc.createElement("granPeriod"); - measInfo.appendChild(granPeriod); - granPeriod.setAttribute("duration", getDurationString(eventMemoryHolder.getGranPeriod())); - ZonedDateTime endDate = eventMemoryHolder.getEventDate(); - granPeriod.setAttribute("endTime", zonedDateTimeToString(endDate, ISO_8601_DATE)); - - //repPeriod elements - Element repPeriod = doc.createElement("repPeriod"); - measInfo.appendChild(repPeriod); - repPeriod.setAttribute("duration", getDurationString(vnfConfigReader.getVnfConfig().getRepPeriod())); - - //measType definition - HashMap measurmentMap = new HashMap<>(); - AtomicInteger i = new AtomicInteger(1); - event.getMeasurementFields().getAdditionalMeasurements().forEach(additionalMeasurement -> { - if (Stream.of(MEASUREMENT_FIELD_IDENTIFIER) - .noneMatch(elementName -> elementName.equalsIgnoreCase(additionalMeasurement.getName()))) { - Element measType = doc.createElement("measType"); - measInfo.appendChild(measType); - measType.setAttribute("p", String.valueOf(i)); - measType.setTextContent(additionalMeasurement.getName()); - measurmentMap.put(additionalMeasurement.getName(), String.valueOf(i)); - i.incrementAndGet(); - } - }); - - //measValue elements - Element measValue = doc.createElement("measValue"); - measInfo.appendChild(measValue); - measValue.setAttribute("measObjLdn", eventMemoryHolder.getCellId()); - event.getMeasurementFields().getAdditionalMeasurements().stream() - .filter(additionalMeasurement -> measurmentMap.containsKey(additionalMeasurement.getName())) - .forEach(additionalMeasurement -> { - if (!additionalMeasurement.getMeasurementValue().isEmpty()) { - - //r elements - Element r = doc.createElement("r"); - measValue.appendChild(r); - r.setAttribute("p", measurmentMap.get(additionalMeasurement.getName())); - r.setTextContent(additionalMeasurement.getMeasurementValue()); - } - }); - }); - } - - /** - * Converts Document into XML file and adds proper headers - * - * @param doc Document - * @param collectedEvents list of stored events - * @return newly created File in xml format - */ - private File writeDocumentIntoXmlFile(Document doc, List collectedEvents) throws TransformerException { - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); - - Transformer tr = transformerFactory.newTransformer(); - tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - tr.setOutputProperty(OutputKeys.VERSION, "1.0"); - Node pi = doc.createProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"MeasDataCollection.xsl\""); - doc.insertBefore(pi, doc.getDocumentElement()); - - File xmlFile = getXmlFile(collectedEvents); - StreamResult result = new StreamResult(xmlFile); - DOMSource source = new DOMSource(doc); - tr.transform(source, result); - return xmlFile; - } - - /** - * Generate PM Bulk File and its name - * - * @param collectedEvents list of stored events - * @return newly created File - */ - private File getXmlFile(List collectedEvents) { - StringBuilder fileNameBuilder = new StringBuilder("C"); - ZonedDateTime firstEventTime = earliestEventTime(collectedEvents); - ZonedDateTime lastEventTime = latestEventTime(collectedEvents); - fileNameBuilder.append(zonedDateTimeToString(firstEventTime, YYYYMMDD_PATTERN)).append("."); - fileNameBuilder.append(zonedDateTimeToString(truncateToSpecifiedMinutes(firstEventTime, 5), "HHmmZ")).append("-"); - fileNameBuilder.append(zonedDateTimeToString(lastEventTime, YYYYMMDD_PATTERN)).append("."); - fileNameBuilder.append(zonedDateTimeToString(truncateToSpecifiedMinutes(lastEventTime, 5), "HHmmZ")); - fileNameBuilder.append("_").append(domainId); - fileNameBuilder.append(appendRcIfNecessary(fileNameBuilder)); - fileNameBuilder.append(".xml"); - - return new File(TEMP_DIR, fileNameBuilder.toString()); - } - - /** - * The RC parameter is a running count and shall be appended only if the filename is otherwise not unique, i.e. more than one file is generated and all - * other parameters of the file name are identical. - * - * @param fileNameBuilder stringBuilder which contains currently generated file name - * @return sequence number or empty string - */ - private static String appendRcIfNecessary(StringBuilder fileNameBuilder) { - String fileName = fileNameBuilder.toString(); - int sequence = 0; - if (isNull(uniqueFileNamesWithCount)) { - uniqueFileNamesWithCount = Collections.synchronizedMap(new HashMap<>()); - } - if (uniqueFileNamesWithCount.containsKey(fileName)) { - sequence = uniqueFileNamesWithCount.get(fileName).incrementAndGet(); - } else { - uniqueFileNamesWithCount.clear(); //we have new dates, so we can clear existing list to not grow infinitely - uniqueFileNamesWithCount.put(fileName, new AtomicInteger(0)); - } - return sequence > 0 ? "_-_" + sequence : EMPTY_STRING; - } - - /** - * Get ZonedDateTime of the earliest event in that reporting period - * - * @param collectedEvents list of compared events - * @return the earliest ZonedDateTime - */ - private static ZonedDateTime earliestEventTime(List collectedEvents) { - return collectedEvents.stream() - .map(EventMemoryHolder::getEventDate) - .min(comparing(ZonedDateTime::toEpochSecond, Comparator.nullsLast(Comparator.naturalOrder()))) - .orElse(ZonedDateTime.now()); - } - - /** - * Get ZonedDateTime of the latest event in that reporting period - * - * @param collectedEvents list of compared events - * @return the latest ZonedDateTime - */ - private static ZonedDateTime latestEventTime(List collectedEvents) { - return collectedEvents.stream().map(EventMemoryHolder::getEventDate) - .max(comparing(ZonedDateTime::toEpochSecond, Comparator.nullsLast(Comparator.naturalOrder()))) - .orElse(ZonedDateTime.now()); - } - - /** - * Convert duration interval in seconds to xml element required by the specification Examples: PT10S, PT900S - * - * @param interval interval in seconds - * @return duration xml element representation - */ - private static String getDurationString(int interval) { - return "PT" + interval + "S"; - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolder.java b/src/main/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolder.java deleted file mode 100644 index cf3cf3a..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolder.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; - -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; -import org.onap.a1pesimulator.data.fileready.FileData; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.exception.VesBrokerException; -import org.onap.a1pesimulator.service.ves.RanVesSender; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import reactor.core.publisher.Mono; - -/** - * Entry point for PM Bulk File event - */ -@Service -public class RanFileReadyHolder { - - private static final Logger log = LoggerFactory.getLogger(RanFileReadyHolder.class); - - private Map> collectedEventsByCell; - private final RanVesSender ranVesSender; - private final FtpServerService ftpServerService; - private final PMBulkFileService xmlFileService; - private final FileReadyEventService fileReadyEventService; - - public RanFileReadyHolder(RanVesSender ranVesSender, FtpServerService ftpServerService, PMBulkFileService xmlFileService, - FileReadyEventService fileReadyEventService) { - this.ranVesSender = ranVesSender; - this.ftpServerService = ftpServerService; - this.xmlFileService = xmlFileService; - this.fileReadyEventService = fileReadyEventService; - } - - /** - * Run entire process for all cells collectedEventsByCell are synchronized to not be updated by other threads during PM Bulk File creation - */ - public void createPMBulkFileAndSendFileReadyMessage() { - synchronized (getCollectedEventsByCell()) { - getCollectedEventsByCell().forEach((cellId, cellEventList) -> createPMBulkFileAndSendFileReadyMessageForCell(cellEventList)); - } - } - - /** - * Run entire process for one cell collectedEventsByCell are synchronized to not be updated by other threads during PM Bulk File creation - * - * @param cellId cell identifier - */ - public void createPMBulkFileAndSendFileReadyMessageForCellId(String cellId) { - synchronized (getCollectedEventsByCell()) { - createPMBulkFileAndSendFileReadyMessageForCell(getCollectedEventsForCellId(cellId)); - } - } - - /** - * Run entire process for one cell: PM Bulk File creation-> upload to FTP -> delete temp PM Bulk File -> create File Ready Event - > send it to VES - * Collector. - * - * @param events list of events for one cell - */ - public void createPMBulkFileAndSendFileReadyMessageForCell(List events) { - Mono.justOrEmpty(events) - .filter(this::areSomeEventsStored) - .flatMap(xmlFileService::generatePMBulkFileXml) - .map(ftpServerService::uploadFileToFtp) - .flatMap(fileReadyEventService::createFileReadyEventAndDeleteTmpFile) - .doOnNext(this::sendEventToVesCollector) - .subscribe(fileData -> informAboutSuccess(), this::informAboutError); - } - - /** - * Adds current event to the memory by cell, which is Map> - * - * @param vesEvent event from specific cell - * @throws VesBrokerException in case of any problem with adding to List, it throws an exception - */ - public void saveEventToMemory(VesEvent vesEvent, String cellId, String jobId, Integer granPeriod) throws VesBrokerException { - try { - Map> events = getCollectedEventsByCell(); - if (events.containsKey(cellId)) { - events.get(cellId).add(new EventMemoryHolder(cellId, jobId, granPeriod, ZonedDateTime.now(), vesEvent)); - } else { - List cellEvents = Collections.synchronizedList( - new ArrayList<>(List.of(new EventMemoryHolder(cellId, jobId, granPeriod, ZonedDateTime.now(), vesEvent)))); - events.put(cellId, cellEvents); - } - log.trace("Saving VES event for cell {} with granularity period {} and sequence number {}", cellId, granPeriod, events.get(cellId).size()); - } catch (Exception e) { - String errorMsg = "Failed to save VES event to memory with exception:" + e; - throw new VesBrokerException(errorMsg); - } - } - - /** - * Sends FileReadyEvent to VES Collector - * - * @param fileData object with FileReadyEvent file - */ - protected void sendEventToVesCollector(FileData fileData) { - ranVesSender.send(fileData.getFileReadyEvent()); - } - - /** - * Log about successful operation - */ - private void informAboutSuccess() { - log.info("PM Bulk file was generated, uploaded to FTP and File ready event was send to VES Collector"); - } - - /** - * Log an error if occurs during the process - * - * @param throwable - error raised in some of the steps - */ - private void informAboutError(Throwable throwable) { - log.info("File ready event was unsuccessful: {}", throwable.getMessage()); - } - - /** - * Check if there are any Events stored in the memory. Used before creating PM Bulk File xml - * - * @param collectedEvents list of stored events - * @return true there is at least one event / false - no event at all - */ - private boolean areSomeEventsStored(List collectedEvents) { - return !CollectionUtils.isEmpty(collectedEvents); - } - - /** - * Factory to get Map> - * - * @return existing or newly created Map> - */ - public Map> getCollectedEventsByCell() { - if (isNull(collectedEventsByCell)) { - collectedEventsByCell = Collections.synchronizedMap(new HashMap<>()); - } - return collectedEventsByCell; - } - - /** - * Get list of events for specific CellId - * - * @param cellId cell identifier - * @return list of events - */ - public List getCollectedEventsForCellId(String cellId) { - if (nonNull(collectedEventsByCell) && collectedEventsByCell.containsKey(cellId)) { - return collectedEventsByCell.get(cellId); - } - return new ArrayList<>(); - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnable.java b/src/main/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnable.java deleted file mode 100644 index 53d4600..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnable.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import java.util.Collection; -import java.util.UUID; - -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.exception.VesBrokerException; -import org.onap.a1pesimulator.service.common.AbstractRanRunnable; -import org.onap.a1pesimulator.service.common.EventCustomizer; -import org.onap.a1pesimulator.service.ves.OnEventAction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RanSaveFileReadyRunnable extends AbstractRanRunnable { - - private static final Logger log = LoggerFactory.getLogger(RanSaveFileReadyRunnable.class); - private final Integer granPeriod; - private final String cellId; - private final String jobId; - private final RanFileReadyHolder ranFileReadyHolder; - - public RanSaveFileReadyRunnable(RanFileReadyHolder ranFileReadyHolder, String cellId, VesEvent event, EventCustomizer eventCustomizer, Integer interval, - Collection onEventActions) { - super(event, eventCustomizer, onEventActions); - this.ranFileReadyHolder = ranFileReadyHolder; - this.granPeriod = interval; - this.cellId = cellId; - this.jobId = UUID.randomUUID() + "-" + cellId; - } - - @Override - public void run() { - try { - VesEvent customizedEvent = eventCustomizer.apply(event); - onEventAction.forEach(action -> action.onEvent(customizedEvent)); - ranFileReadyHolder.saveEventToMemory(customizedEvent, cellId, jobId, granPeriod); - } catch (VesBrokerException e) { - log.error("Saving file ready event failed: {}", e.getMessage()); - } - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnable.java b/src/main/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnable.java deleted file mode 100644 index f92d479..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnable.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -public class RanSendReportsRunnable implements Runnable { - - protected final RanFileReadyHolder ranFileReadyHolder; - - public RanSendReportsRunnable(RanFileReadyHolder ranFileReadyHolder) { - this.ranFileReadyHolder = ranFileReadyHolder; - } - - @Override - public void run() { - ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessage(); - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/pm/FileReadyEventService.java b/src/main/java/org/onap/a1pesimulator/service/pm/FileReadyEventService.java new file mode 100644 index 0000000..df2ce97 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/pm/FileReadyEventService.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.onap.a1pesimulator.service.pm.FtpServerService.deletePMBulkFile; +import static org.onap.a1pesimulator.util.Constants.FILE_READY_CHANGE_IDENTIFIER; +import static org.onap.a1pesimulator.util.Constants.FILE_READY_CHANGE_TYPE; + +import java.io.File; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.onap.a1pesimulator.data.fileready.FileData; +import org.onap.a1pesimulator.data.fileready.FileReadyEvent; +import org.onap.a1pesimulator.data.fileready.NotificationFields; +import org.onap.a1pesimulator.data.fileready.NotificationFields.ArrayOfNamedHashMap; +import org.onap.a1pesimulator.data.ves.CommonEventHeader; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Mono; + +/** + * Service for PM Bulk File creation and its handling + */ + +@Service +public class FileReadyEventService { + + private final FtpServerService ftpServerService; + + @Value("${file.ready.version}") + private String version; + + @Value("${file.ready.vesEventListenerVersion}") + private String vesEventListenerVersion; + + @Value("${file.ready.domain}") + private String domain; + + @Value("${file.ready.eventName}") + private String eventName; + + @Value("${file.ready.fileFormatType}") + private String fileFormatType; + + @Value("${file.ready.fileFormatVersion}") + private String fileFormatVersion; + + @Value("${file.ready.notificationFieldsVersion}") + private String notificationFieldsVersion; + + @Value("${file.ready.priority}") + private String priority; + + @Value("${file.ready.reportingEntityName}") + private String reportingEntityName; + + public FileReadyEventService(FtpServerService ftpServerService) { + this.ftpServerService = ftpServerService; + } + + /** + * It will create FileReadyEvent.json which will go to VES Collector + * + * @return created FileReadyEvent + */ + protected Mono createFileReadyEventAndDeleteTmpFile(Mono fileMono) { + return fileMono + .map(this::createFileReadyEvent) + .doOnNext(file -> deleteTempArchivedBulkFile(file.getArchivedPmBulkFile())); + } + + /** + * Creates File Ready Event + * + * @param fileData information about PM Bulk Files created in previous steps + * @return added newly created FileReadyEvent to FileData + */ + protected FileData createFileReadyEvent(FileData fileData) { + FileReadyEvent event = new FileReadyEvent(); + CommonEventHeader commonEventHeader = getCommonHeader(); + event.setCommonEventHeader(commonEventHeader); + commonEventHeader.setStartEpochMicrosec(ChronoUnit.MICROS.between(Instant.EPOCH, fileData.getStartEventDate())); + commonEventHeader.setLastEpochMicrosec(ChronoUnit.MICROS.between(Instant.EPOCH, fileData.getEndEventDate())); + event.setNotificationFields(getNotificationFields(fileData.getArchivedPmBulkFile().getName())); + fileData.setFileReadyEvent(event); + return fileData; + } + + /** + * Creates NotificationFields section in FileReadyEvent + * + * @param fileName name of archived PM Bulk File + * @return NotificationFields object + */ + private NotificationFields getNotificationFields(String fileName) { + NotificationFields notificationFields = NotificationFields.builder() + .changeIdentifier(FILE_READY_CHANGE_IDENTIFIER) + .changeType(FILE_READY_CHANGE_TYPE) + .notificationFieldsVersion(notificationFieldsVersion).build(); + + ArrayOfNamedHashMap arrayOfNamedHashMap = new ArrayOfNamedHashMap(); + Map hashMapItems = new HashMap<>(); + hashMapItems.put("location", ftpServerService.getFtpPath() + fileName); + hashMapItems.put("compression", "gzip"); + hashMapItems.put("fileFormatType", fileFormatType); + hashMapItems.put("fileFormatVersion", fileFormatVersion); + + arrayOfNamedHashMap.setName(fileName); + arrayOfNamedHashMap.setHashMap(hashMapItems); + notificationFields.setArrayOfNamedHashMap(Collections.singletonList(arrayOfNamedHashMap)); + return notificationFields; + } + + /** + * Creates CommonEventHeader + * + * @return created CommonEventHeader + */ + private CommonEventHeader getCommonHeader() { + return CommonEventHeader.builder() + .version(version) + .vesEventListenerVersion(vesEventListenerVersion) + .domain(domain) + .eventName(eventName) + .eventId(UUID.randomUUID().toString()) + .priority(priority) + .reportingEntityName(reportingEntityName) + .sequence(0) + .timeZoneOffset(ZonedDateTime.now().getOffset().toString()) + .build(); + } + + /** + * Deletes temporary archived PM Bulk File + * + * @param fileMono temporary archived PM Bulk File + */ + private void deleteTempArchivedBulkFile(File fileMono) { + deletePMBulkFile(fileMono); + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/pm/FtpServerService.java b/src/main/java/org/onap/a1pesimulator/service/pm/FtpServerService.java new file mode 100644 index 0000000..01b0672 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/pm/FtpServerService.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static java.util.Objects.nonNull; +import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.util.zip.GZIPOutputStream; + + +import org.onap.a1pesimulator.data.fileready.FileData; +import org.onap.a1pesimulator.exception.NotUploadedToFtpException; +import org.onap.a1pesimulator.util.VnfConfigReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.FileCopyUtils; + +import net.schmizz.sshj.SSHClient; +import net.schmizz.sshj.sftp.SFTPClient; +import net.schmizz.sshj.transport.verification.PromiscuousVerifier; +import reactor.core.publisher.Mono; + +@Service +public class FtpServerService { + + private static final Logger log = LoggerFactory.getLogger(FtpServerService.class); + + //true - file will be uploaded to FTP; false - file will be copied into xmlPmLocation + @Value("${ftp.server.upload}") + private boolean ftpServerUpload; + + // location where archived file will be copied + @Value("${xml.pm.location}") + private String xmlPmLocation; + + @Value("${ftp.server.protocol}") + private String ftpServerProtocol; + + @Value("${ftp.server.filepath}") + private String ftpServerFilepath; + + @Value("${ftp.server.username}") + private String ftpServerUsername; + + @Value("${ftp.server.password}") + private String ftpServerPassword; + + private VnfConfigReader vnfConfigReader; + + public FtpServerService(VnfConfigReader vnfConfigReader) { + this.vnfConfigReader = vnfConfigReader; + } + + public Mono uploadFileToFtp(FileData fileData) { + return Mono.just(fileData) + .flatMap(this::tryToCompressFile) + .flatMap(this::tryToUploadOrSaveFileToFtp) + .onErrorResume(throwable -> resumeError(throwable, fileData)) + .doOnNext(file -> deletePMBulkFile(file.getPmBulkFile())); + } + + /** + * Trying to compress file into .gz + * + * @param fileData file to be archived + * @return archived file + */ + private Mono tryToCompressFile(FileData fileData) { + File archiveBulkFile = new File(TEMP_DIR, fileData.getPmBulkFile().getName() + ".gz"); + + try (GZIPOutputStream zos = new GZIPOutputStream( + new FileOutputStream(archiveBulkFile.getAbsolutePath())); FileInputStream inputStream = new FileInputStream(fileData.getPmBulkFile())) { + byte[] buffer = new byte[1024]; + int len; + while ((len = inputStream.read(buffer)) > 0) { + zos.write(buffer, 0, len); + } + fileData.setArchivedPmBulkFile(archiveBulkFile); + log.trace("Compressing file {}", fileData.getPmBulkFile().getName()); + return Mono.just(fileData); + } catch (IOException e) { + log.error("Could not compress file", e); + return Mono.empty(); + } + } + + /** + * Upload file to FTP or copy it to mounted location + * + * @param fileData data about file + * @return fileData for fileReadyEvent + */ + private Mono tryToUploadOrSaveFileToFtp(FileData fileData) { + if (ftpServerUpload) { + return tryToUploadFileToFtp(fileData); + } else { + File fileOnFtp = new File(xmlPmLocation, fileData.getArchivedPmBulkFile().getName()); + try { + FileCopyUtils.copy(fileData.getArchivedPmBulkFile(), fileOnFtp); + log.info("Uploading file to the location: {}", fileOnFtp); + return Mono.just(fileData); + } catch (IOException e) { + return Mono.error(new NotUploadedToFtpException("File was not copied to FTP location", e)); + } + } + } + + /** + * Upload file to FTP + * + * @param fileData archived file in Mono + * @return archived file for fileReadyEvent + */ + private Mono tryToUploadFileToFtp(FileData fileData) { + if (nonNull(fileData.getArchivedPmBulkFile())) { + SSHClient client = getSSHClient(); + if (nonNull(client)) { + try (client; SFTPClient sftpClient = client.newSFTPClient()) { + File archiveBulkFile = fileData.getArchivedPmBulkFile(); + sftpClient.put(archiveBulkFile.getAbsolutePath(), ftpServerFilepath + "/" + archiveBulkFile.getName()); + + log.info("Uploading file to FTP: {}", archiveBulkFile.getAbsoluteFile()); + return Mono.just(fileData); + } catch (IOException e) { + log.error("Exception while trying to upload a file", e); + } + } else { + log.error("Could not connect to FTP server"); + } + } else { + log.error("There is no file to upload"); + } + return Mono.error(new NotUploadedToFtpException("File was not uploaded to FTP")); + } + + /** + * Creates SSHClient instance + * + * @return SSHClient + */ + protected SSHClient getSSHClient() { + SSHClient client = new SSHClient(); + try { + client.addHostKeyVerifier(new PromiscuousVerifier()); + client.connect(vnfConfigReader.getVnfConfig().getFtpHost(), Integer.parseInt(vnfConfigReader.getVnfConfig().getFtpPort())); + client.authPassword(ftpServerUsername, ftpServerPassword); + return client; + } catch (IOException e) { + log.error("There was an error while connecting to FTP server", e); + try { + client.close(); + } catch (IOException ioException) { + log.error("There was an error while closing the connection to FTP server", e); + } + return null; + } + } + + /** + * Deletes created PM Bulk File xml from temp storage after successful upload to FTP + * + * @param file file which we gonna delete + */ + public static void deletePMBulkFile(File file) { + try { + log.trace("Deleting file: {}", file.getAbsoluteFile()); + Files.delete(file.toPath()); + } catch (IOException e) { + log.warn("Could not delete file: {}", file.getName(), e); + } + } + + /** + * Get path to FTP server + * + * @return for example: "sftp://foo:pass@106.120.119.170:2222/upload/" + */ + public String getFtpPath() { + return ftpServerProtocol + "://" + ftpServerUsername + ":" + ftpServerPassword + "@" + vnfConfigReader.getVnfConfig().getFtpHost() + ":" + + vnfConfigReader.getVnfConfig().getFtpPort() + "/" + ftpServerFilepath + + "/"; + } + + /** + * Try to clean up things after an exception + * + * @param throwable error thrown + * @param fileData data about files which needs to be deleted + * @return empty Mono object + */ + protected Mono resumeError(Throwable throwable, FileData fileData) { + log.error("Error occurs while uploading file to FTP server", throwable); + deletePMBulkFile(fileData.getPmBulkFile()); + deletePMBulkFile(fileData.getArchivedPmBulkFile()); + return Mono.empty(); + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/pm/PMBulkFileService.java b/src/main/java/org/onap/a1pesimulator/service/pm/PMBulkFileService.java new file mode 100644 index 0000000..aec473c --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/pm/PMBulkFileService.java @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static java.util.Comparator.comparing; +import static java.util.Objects.isNull; +import static org.onap.a1pesimulator.util.Constants.EMPTY_STRING; +import static org.onap.a1pesimulator.util.Constants.MEASUREMENT_FIELD_IDENTIFIER; +import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; +import static org.onap.a1pesimulator.util.Convertors.ISO_8601_DATE; +import static org.onap.a1pesimulator.util.Convertors.YYYYMMDD_PATTERN; +import static org.onap.a1pesimulator.util.Convertors.truncateToSpecifiedMinutes; +import static org.onap.a1pesimulator.util.Convertors.zonedDateTimeToString; + +import java.io.File; +import java.time.ZonedDateTime; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; +import org.onap.a1pesimulator.data.fileready.FileData; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.util.VnfConfigReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import reactor.core.publisher.Mono; + +/** + * Service for PM Bulk File creation and handling + */ + +@Service +public class PMBulkFileService { + + private static final Logger log = LoggerFactory.getLogger(PMBulkFileService.class); + private static Map uniqueFileNamesWithCount; + private final VnfConfigReader vnfConfigReader; + + @Value("${xml.pm.bulk.fileFormatVersion}") + private String fileFormatVersion; + + @Value("${xml.pm.bulk.vendorName}") + private String vendorName; + + @Value("${xml.pm.bulk.fileSender}") + private String fileSenderValue; + + @Value("${xml.pm.bulk.userLabel}") + private String userLabel; + + @Value("${xml.pm.bulk.domainId}") + private String domainId; + + public PMBulkFileService(VnfConfigReader vnfConfigReader) { + this.vnfConfigReader = vnfConfigReader; + } + + /** + * Generate PM Bulk File xml from stored events + * + * @param collectedEvents list of stored events + * @return generated file in Mono object + */ + public Mono generatePMBulkFileXml(List collectedEvents) { + + try { + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + + //root elements + Document doc = docBuilder.newDocument(); + + Element measCollecFile = doc.createElement("measCollecFile"); + doc.appendChild(measCollecFile); + measCollecFile.setAttribute("xmlns", "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec"); + measCollecFile.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + measCollecFile.setAttribute("xsi:schemaLocation", + "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec"); + + //fileHeader elements + Element fileHeader = doc.createElement("fileHeader"); + measCollecFile.appendChild(fileHeader); + fileHeader.setAttribute("fileFormatVersion", fileFormatVersion); + fileHeader.setAttribute("vendorName", vendorName); + + //fileSender elements + Element fileSender = doc.createElement("fileSender"); + fileHeader.appendChild(fileSender); + fileSender.setAttribute("elementType", fileSenderValue); + + //measCollec elements + Element measCollec = doc.createElement("measCollec"); + fileHeader.appendChild(measCollec); + measCollec.setAttribute("beginTime", zonedDateTimeToString(earliestEventTime(collectedEvents), ISO_8601_DATE)); + + //measData elements + Element measData = doc.createElement("measData"); + measCollecFile.appendChild(measData); + + //managedElement elements + Element managedElement = doc.createElement("managedElement"); + measData.appendChild(managedElement); + managedElement.setAttribute("userLabel", userLabel); + + //add measInfo elements + addMeansInfo(doc, measData, collectedEvents); + + //fileFooter elements + Element fileFooter = doc.createElement("fileFooter"); + measCollecFile.appendChild(fileFooter); + + Element measCollecFooter = doc.createElement("measCollec"); + fileFooter.appendChild(measCollecFooter); + measCollecFooter.setAttribute("endTime", zonedDateTimeToString(latestEventTime(collectedEvents), ISO_8601_DATE)); + + File xmlFile = writeDocumentIntoXmlFile(doc, collectedEvents); + + Mono justMono = Mono.just(FileData.builder().pmBulkFile(xmlFile).startEventDate(earliestEventTime(collectedEvents)) + .endEventDate(latestEventTime(collectedEvents)).build()); + log.trace("Removing all VES events from memory: {}", collectedEvents.size()); + collectedEvents.clear(); + return justMono; + + } catch (ParserConfigurationException | TransformerException pce) { + log.error("Error occurs while creating PM Bulk File", pce); + return Mono.empty(); + } + } + + /** + * Add measurement elements for each cell and measurement time into PM Bulk File + * + * @param doc Document + * @param measData main element of document, which stores meansData + * @param collectedEvents list of stored events + */ + private void addMeansInfo(Document doc, Element measData, List collectedEvents) { + collectedEvents.stream().sorted(comparing(EventMemoryHolder::getEventDate)).forEach(eventMemoryHolder -> { + VesEvent event = eventMemoryHolder.getEvent(); + + Element measInfo = doc.createElement("measInfo"); + measData.appendChild(measInfo); + + //job element + Element job = doc.createElement("job"); + measInfo.appendChild(job); + job.setAttribute("jobId", eventMemoryHolder.getJobId()); + + //granPeriod elements + Element granPeriod = doc.createElement("granPeriod"); + measInfo.appendChild(granPeriod); + granPeriod.setAttribute("duration", getDurationString(eventMemoryHolder.getGranPeriod())); + ZonedDateTime endDate = eventMemoryHolder.getEventDate(); + granPeriod.setAttribute("endTime", zonedDateTimeToString(endDate, ISO_8601_DATE)); + + //repPeriod elements + Element repPeriod = doc.createElement("repPeriod"); + measInfo.appendChild(repPeriod); + repPeriod.setAttribute("duration", getDurationString(vnfConfigReader.getVnfConfig().getRepPeriod())); + + //measType definition + HashMap measurmentMap = new HashMap<>(); + AtomicInteger i = new AtomicInteger(1); + event.getMeasurementFields().getAdditionalMeasurements().forEach(additionalMeasurement -> { + if (Stream.of(MEASUREMENT_FIELD_IDENTIFIER) + .noneMatch(elementName -> elementName.equalsIgnoreCase(additionalMeasurement.getName()))) { + Element measType = doc.createElement("measType"); + measInfo.appendChild(measType); + measType.setAttribute("p", String.valueOf(i)); + measType.setTextContent(additionalMeasurement.getName()); + measurmentMap.put(additionalMeasurement.getName(), String.valueOf(i)); + i.incrementAndGet(); + } + }); + + //measValue elements + Element measValue = doc.createElement("measValue"); + measInfo.appendChild(measValue); + measValue.setAttribute("measObjLdn", eventMemoryHolder.getCellId()); + event.getMeasurementFields().getAdditionalMeasurements().stream() + .filter(additionalMeasurement -> measurmentMap.containsKey(additionalMeasurement.getName())) + .forEach(additionalMeasurement -> { + if (!additionalMeasurement.getMeasurementValue().isEmpty()) { + + //r elements + Element r = doc.createElement("r"); + measValue.appendChild(r); + r.setAttribute("p", measurmentMap.get(additionalMeasurement.getName())); + r.setTextContent(additionalMeasurement.getMeasurementValue()); + } + }); + }); + } + + /** + * Converts Document into XML file and adds proper headers + * + * @param doc Document + * @param collectedEvents list of stored events + * @return newly created File in xml format + */ + private File writeDocumentIntoXmlFile(Document doc, List collectedEvents) throws TransformerException { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + + Transformer tr = transformerFactory.newTransformer(); + tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + tr.setOutputProperty(OutputKeys.VERSION, "1.0"); + Node pi = doc.createProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"MeasDataCollection.xsl\""); + doc.insertBefore(pi, doc.getDocumentElement()); + + File xmlFile = getXmlFile(collectedEvents); + StreamResult result = new StreamResult(xmlFile); + DOMSource source = new DOMSource(doc); + tr.transform(source, result); + return xmlFile; + } + + /** + * Generate PM Bulk File and its name + * + * @param collectedEvents list of stored events + * @return newly created File + */ + private File getXmlFile(List collectedEvents) { + StringBuilder fileNameBuilder = new StringBuilder("C"); + ZonedDateTime firstEventTime = earliestEventTime(collectedEvents); + ZonedDateTime lastEventTime = latestEventTime(collectedEvents); + fileNameBuilder.append(zonedDateTimeToString(firstEventTime, YYYYMMDD_PATTERN)).append("."); + fileNameBuilder.append(zonedDateTimeToString(truncateToSpecifiedMinutes(firstEventTime, 5), "HHmmZ")).append("-"); + fileNameBuilder.append(zonedDateTimeToString(lastEventTime, YYYYMMDD_PATTERN)).append("."); + fileNameBuilder.append(zonedDateTimeToString(truncateToSpecifiedMinutes(lastEventTime, 5), "HHmmZ")); + fileNameBuilder.append("_").append(domainId); + fileNameBuilder.append(appendRcIfNecessary(fileNameBuilder)); + fileNameBuilder.append(".xml"); + + return new File(TEMP_DIR, fileNameBuilder.toString()); + } + + /** + * The RC parameter is a running count and shall be appended only if the filename is otherwise not unique, i.e. more than one file is generated and all + * other parameters of the file name are identical. + * + * @param fileNameBuilder stringBuilder which contains currently generated file name + * @return sequence number or empty string + */ + private static String appendRcIfNecessary(StringBuilder fileNameBuilder) { + String fileName = fileNameBuilder.toString(); + int sequence = 0; + if (isNull(uniqueFileNamesWithCount)) { + uniqueFileNamesWithCount = Collections.synchronizedMap(new HashMap<>()); + } + if (uniqueFileNamesWithCount.containsKey(fileName)) { + sequence = uniqueFileNamesWithCount.get(fileName).incrementAndGet(); + } else { + uniqueFileNamesWithCount.clear(); //we have new dates, so we can clear existing list to not grow infinitely + uniqueFileNamesWithCount.put(fileName, new AtomicInteger(0)); + } + return sequence > 0 ? "_-_" + sequence : EMPTY_STRING; + } + + /** + * Get ZonedDateTime of the earliest event in that reporting period + * + * @param collectedEvents list of compared events + * @return the earliest ZonedDateTime + */ + private static ZonedDateTime earliestEventTime(List collectedEvents) { + return collectedEvents.stream() + .map(EventMemoryHolder::getEventDate) + .min(comparing(ZonedDateTime::toEpochSecond, Comparator.nullsLast(Comparator.naturalOrder()))) + .orElse(ZonedDateTime.now()); + } + + /** + * Get ZonedDateTime of the latest event in that reporting period + * + * @param collectedEvents list of compared events + * @return the latest ZonedDateTime + */ + private static ZonedDateTime latestEventTime(List collectedEvents) { + return collectedEvents.stream().map(EventMemoryHolder::getEventDate) + .max(comparing(ZonedDateTime::toEpochSecond, Comparator.nullsLast(Comparator.naturalOrder()))) + .orElse(ZonedDateTime.now()); + } + + /** + * Convert duration interval in seconds to xml element required by the specification Examples: PT10S, PT900S + * + * @param interval interval in seconds + * @return duration xml element representation + */ + private static String getDurationString(int interval) { + return "PT" + interval + "S"; + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolder.java b/src/main/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolder.java new file mode 100644 index 0000000..d3a7970 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolder.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; +import org.onap.a1pesimulator.data.fileready.FileData; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.exception.VesBrokerException; +import org.onap.a1pesimulator.service.report.RanVesSender; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import reactor.core.publisher.Mono; + +/** + * Entry point for PM Bulk File event + */ +@Service +public class RanFileReadyHolder { + + private static final Logger log = LoggerFactory.getLogger(RanFileReadyHolder.class); + + private Map> collectedEventsByCell; + private final RanVesSender ranVesSender; + private final FtpServerService ftpServerService; + private final PMBulkFileService xmlFileService; + private final FileReadyEventService fileReadyEventService; + + public RanFileReadyHolder(RanVesSender ranVesSender, FtpServerService ftpServerService, PMBulkFileService xmlFileService, + FileReadyEventService fileReadyEventService) { + this.ranVesSender = ranVesSender; + this.ftpServerService = ftpServerService; + this.xmlFileService = xmlFileService; + this.fileReadyEventService = fileReadyEventService; + } + + /** + * Run entire process for all cells collectedEventsByCell are synchronized to not be updated by other threads during PM Bulk File creation + */ + public void createPMBulkFileAndSendFileReadyMessage() { + synchronized (getCollectedEventsByCell()) { + getCollectedEventsByCell().forEach((cellId, cellEventList) -> createPMBulkFileAndSendFileReadyMessageForCell(cellEventList)); + } + } + + /** + * Run entire process for one cell collectedEventsByCell are synchronized to not be updated by other threads during PM Bulk File creation + * + * @param cellId cell identifier + */ + public void createPMBulkFileAndSendFileReadyMessageForCellId(String cellId) { + synchronized (getCollectedEventsByCell()) { + createPMBulkFileAndSendFileReadyMessageForCell(getCollectedEventsForCellId(cellId)); + } + } + + /** + * Run entire process for one cell: PM Bulk File creation-> upload to FTP -> delete temp PM Bulk File -> create File Ready Event - > send it to VES + * Collector. + * + * @param events list of events for one cell + */ + public void createPMBulkFileAndSendFileReadyMessageForCell(List events) { + Mono.justOrEmpty(events) + .filter(this::areSomeEventsStored) + .flatMap(xmlFileService::generatePMBulkFileXml) + .map(ftpServerService::uploadFileToFtp) + .flatMap(fileReadyEventService::createFileReadyEventAndDeleteTmpFile) + .doOnNext(this::sendEventToVesCollector) + .subscribe(fileData -> informAboutSuccess(), this::informAboutError); + } + + /** + * Adds current event to the memory by cell, which is Map> + * + * @param vesEvent event from specific cell + * @throws VesBrokerException in case of any problem with adding to List, it throws an exception + */ + public void saveEventToMemory(VesEvent vesEvent, String cellId, String jobId, Integer granPeriod) throws VesBrokerException { + try { + Map> events = getCollectedEventsByCell(); + if (events.containsKey(cellId)) { + events.get(cellId).add(new EventMemoryHolder(cellId, jobId, granPeriod, ZonedDateTime.now(), vesEvent)); + } else { + List cellEvents = Collections.synchronizedList( + new ArrayList<>(List.of(new EventMemoryHolder(cellId, jobId, granPeriod, ZonedDateTime.now(), vesEvent)))); + events.put(cellId, cellEvents); + } + log.trace("Saving VES event for cell {} with granularity period {} and sequence number {}", cellId, granPeriod, events.get(cellId).size()); + } catch (Exception e) { + String errorMsg = "Failed to save VES event to memory with exception:" + e; + throw new VesBrokerException(errorMsg); + } + } + + /** + * Sends FileReadyEvent to VES Collector + * + * @param fileData object with FileReadyEvent file + */ + protected void sendEventToVesCollector(FileData fileData) { + ranVesSender.send(fileData.getFileReadyEvent()); + } + + /** + * Log about successful operation + */ + private void informAboutSuccess() { + log.info("PM Bulk file was generated, uploaded to FTP and File ready event was send to VES Collector"); + } + + /** + * Log an error if occurs during the process + * + * @param throwable - error raised in some of the steps + */ + private void informAboutError(Throwable throwable) { + log.info("File ready event was unsuccessful: {}", throwable.getMessage()); + } + + /** + * Check if there are any Events stored in the memory. Used before creating PM Bulk File xml + * + * @param collectedEvents list of stored events + * @return true there is at least one event / false - no event at all + */ + private boolean areSomeEventsStored(List collectedEvents) { + return !CollectionUtils.isEmpty(collectedEvents); + } + + /** + * Factory to get Map> + * + * @return existing or newly created Map> + */ + public Map> getCollectedEventsByCell() { + if (isNull(collectedEventsByCell)) { + collectedEventsByCell = Collections.synchronizedMap(new HashMap<>()); + } + return collectedEventsByCell; + } + + /** + * Get list of events for specific CellId + * + * @param cellId cell identifier + * @return list of events + */ + public List getCollectedEventsForCellId(String cellId) { + if (nonNull(collectedEventsByCell) && collectedEventsByCell.containsKey(cellId)) { + return collectedEventsByCell.get(cellId); + } + return new ArrayList<>(); + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnable.java b/src/main/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnable.java new file mode 100644 index 0000000..222680f --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnable.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import java.util.Collection; +import java.util.UUID; + +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.exception.VesBrokerException; +import org.onap.a1pesimulator.service.common.AbstractRanRunnable; +import org.onap.a1pesimulator.service.common.EventCustomizer; +import org.onap.a1pesimulator.service.report.OnEventAction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RanSaveFileReadyRunnable extends AbstractRanRunnable { + + private static final Logger log = LoggerFactory.getLogger(RanSaveFileReadyRunnable.class); + private final Integer granPeriod; + private final String cellId; + private final String jobId; + private final RanFileReadyHolder ranFileReadyHolder; + + public RanSaveFileReadyRunnable(RanFileReadyHolder ranFileReadyHolder, String cellId, VesEvent event, EventCustomizer eventCustomizer, Integer interval, + Collection onEventActions) { + super(event, eventCustomizer, onEventActions); + this.ranFileReadyHolder = ranFileReadyHolder; + this.granPeriod = interval; + this.cellId = cellId; + this.jobId = UUID.randomUUID() + "-" + cellId; + } + + @Override + public void run() { + try { + VesEvent customizedEvent = eventCustomizer.apply(event); + onEventAction.forEach(action -> action.onEvent(customizedEvent)); + ranFileReadyHolder.saveEventToMemory(customizedEvent, cellId, jobId, granPeriod); + } catch (VesBrokerException e) { + log.error("Saving file ready event failed: {}", e.getMessage()); + } + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnable.java b/src/main/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnable.java new file mode 100644 index 0000000..88cb5a2 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnable.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +public class RanSendReportsRunnable implements Runnable { + + protected final RanFileReadyHolder ranFileReadyHolder; + + public RanSendReportsRunnable(RanFileReadyHolder ranFileReadyHolder) { + this.ranFileReadyHolder = ranFileReadyHolder; + } + + @Override + public void run() { + ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessage(); + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/OnEventAction.java b/src/main/java/org/onap/a1pesimulator/service/report/OnEventAction.java new file mode 100644 index 0000000..f95f749 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/OnEventAction.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import org.onap.a1pesimulator.data.ves.VesEvent; + +@FunctionalInterface +public interface OnEventAction { + + void onEvent(VesEvent event); +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanCellEventCustomizer.java b/src/main/java/org/onap/a1pesimulator/service/report/RanCellEventCustomizer.java new file mode 100644 index 0000000..f16e29c --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanCellEventCustomizer.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import java.util.List; +import java.util.Optional; + +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.data.ves.MeasurementFields.AdditionalMeasurement; +import org.onap.a1pesimulator.service.common.EventCustomizer; +import org.onap.a1pesimulator.service.ue.RanUeHolder; +import org.onap.a1pesimulator.util.Constants; +import org.onap.a1pesimulator.util.JsonUtils; +import org.onap.a1pesimulator.util.RanVesUtils; +import org.springframework.stereotype.Service; + +@Service +public class RanCellEventCustomizer implements EventCustomizer { + + private static final String UE_PARAM_TRAFFIC_MODEL_RANGE = "[[20-50]]"; + private final RanUeHolder ranUeHolder; + + public RanCellEventCustomizer(RanUeHolder ueHolder) { + this.ranUeHolder = ueHolder; + } + + @Override + public VesEvent apply(VesEvent t) { + VesEvent event = JsonUtils.INSTANCE.clone(t); + return customizeEvent(event); + } + + private VesEvent customizeEvent(VesEvent event) { + RanVesUtils.updateHeader(event); + enrichWithUeData(event); + randomizeEvent(event); + return event; + } + + private void randomizeEvent(VesEvent event) { + List additionalMeasurementsToRandomize = + event.getMeasurementFields().getAdditionalMeasurements(); + event.getMeasurementFields().setAdditionalMeasurements( + RanVesUtils.randomizeAdditionalMeasurements(additionalMeasurementsToRandomize)); + } + + private void enrichWithUeData(VesEvent event) { + + Optional identity = event.getMeasurementFields().getAdditionalMeasurements().stream() + .filter(msrmnt -> Constants.MEASUREMENT_FIELD_IDENTIFIER + .equalsIgnoreCase( + msrmnt.getName())) + .findAny(); + identity.ifPresent(m -> addTrafficModelMeasurement(event)); + } + + private void addTrafficModelMeasurement(VesEvent event) { + AdditionalMeasurement trafficModelMeasurement = + RanVesUtils.buildTrafficModelMeasurement( ranUeHolder, UE_PARAM_TRAFFIC_MODEL_RANGE); + event.getMeasurementFields().getAdditionalMeasurements().add(trafficModelMeasurement); + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanCellFailureEventCustomizer.java b/src/main/java/org/onap/a1pesimulator/service/report/RanCellFailureEventCustomizer.java new file mode 100644 index 0000000..6d62f33 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanCellFailureEventCustomizer.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import java.text.MessageFormat; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; + +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.data.ves.MeasurementFields.AdditionalMeasurement; +import org.onap.a1pesimulator.service.common.EventCustomizer; +import org.onap.a1pesimulator.service.ue.RanUeHolder; +import org.onap.a1pesimulator.util.Constants; +import org.onap.a1pesimulator.util.JsonUtils; +import org.onap.a1pesimulator.util.RanVesUtils; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; + +public class RanCellFailureEventCustomizer implements EventCustomizer { + + private static final String UE_PARAM_TRAFFIC_MODEL_RANGE = "[[50->10]]"; + private final RanUeHolder ranUeHolder; + private final VesEvent event; + + private final Map additionalMeasurementsValues = new HashMap<>(); + private final ValueFactory valueFactory; + + public RanCellFailureEventCustomizer(VesEvent event, RanUeHolder ranUeHolder) { + this.ranUeHolder = ranUeHolder; + this.event = event; + valueFactory = new ValueFactory(); + collectAdditionalMeasurementValues(event); + } + + @Override + public VesEvent apply(VesEvent t) { + return customizeEvent(JsonUtils.INSTANCE.clone(this.event)); + } + + private void collectAdditionalMeasurementValues(VesEvent event) { + Collection additionalMeasurementsToResolve = + event.getMeasurementFields().getAdditionalMeasurements(); + additionalMeasurementsToResolve.forEach(this::collectAdditionalMeasurementValue); + } + + private void collectAdditionalMeasurementValue(AdditionalMeasurement m) { + for (Entry entry : m.getHashMap().entrySet()) { + if (!RanVesUtils.isRange(entry.getValue())) { + continue; + } + additionalMeasurementsValues + .putIfAbsent(new Key(m.getName(), entry.getKey()), valueFactory.getInstance(entry.getValue())); + } + } + + private VesEvent customizeEvent(VesEvent event) { + RanVesUtils.updateHeader(event); + enrichWithUeData(event); + resolveRanges(event); + return event; + } + + private void resolveRanges(VesEvent event) { + List additionalMeasurementsToResolve = + event.getMeasurementFields().getAdditionalMeasurements(); + + additionalMeasurementsToResolve.forEach(this::resolveRanges); + event.getMeasurementFields().setAdditionalMeasurements(additionalMeasurementsToResolve); + } + + private void resolveRanges(AdditionalMeasurement m) { + for (Entry entry : m.getHashMap().entrySet()) { + Key key = new Key(m.getName(), entry.getKey()); + if (!additionalMeasurementsValues.containsKey(key)) { + continue; + } + Value value = additionalMeasurementsValues.get(key); + value.current = value.calculateCurrentValue(); + entry.setValue(value.current.toString()); + } + } + + private void enrichWithUeData(VesEvent event) { + + Optional identity = event.getMeasurementFields().getAdditionalMeasurements().stream() + .filter(msrmnt -> Constants.MEASUREMENT_FIELD_IDENTIFIER + .equalsIgnoreCase( + msrmnt.getName())) + .findAny(); + identity.ifPresent(m -> addTrafficModelMeasurement(event)); + } + + private void addTrafficModelMeasurement(VesEvent event) { + AdditionalMeasurement trafficModelMeasurement = + RanVesUtils.buildTrafficModelMeasurement(ranUeHolder, UE_PARAM_TRAFFIC_MODEL_RANGE); + event.getMeasurementFields().getAdditionalMeasurements().add(trafficModelMeasurement); + + collectAdditionalMeasurementValue(trafficModelMeasurement); + } + + // -----------helper classes + + private static class ValueFactory { + + public Value getInstance(String value) { + String[] split; + if (RanVesUtils.isRandomRange(value)) { + split = RanVesUtils.splitRandomRange(value); + return new RandomValue(Integer.valueOf(split[0]), Integer.valueOf(split[1])); + } + if (RanVesUtils.isTrandingRange(value)) { + split = RanVesUtils.splitTrendingRange(value); + Integer start = Integer.valueOf(split[0]); + Integer end = Integer.valueOf(split[1]); + if (start < end) { + return new RaisingValue(start, end); + } else if (start > end) { + return new DecreasingValue(start, end); + } + } + throw new RuntimeException(MessageFormat.format("Cannot instantiate Value from string: {0}", value)); + } + } + + private abstract static class Value { + + protected Integer start; + protected Integer end; + protected Integer current; + + public Value(Integer start, Integer end) { + this.start = start; + this.end = end; + } + + public abstract Integer calculateCurrentValue(); + } + + private static class RaisingValue extends Value { + + private int increment; + + public RaisingValue(Integer start, Integer end) { + super(start, end); + } + + @Override + public Integer calculateCurrentValue() { + if (current == null) { + return start; + } + if (increment == 0) { + increment = 1; + } else { + increment = increment * 2; + } + Integer result = start + increment; + if (result > end) { + increment = 1; + return end; + } + return result; + } + } + + private static class DecreasingValue extends Value { + + private int decrement; + + public DecreasingValue(Integer start, Integer end) { + super(start, end); + } + + @Override + public Integer calculateCurrentValue() { + if (current == null) { + return start; + } + if (decrement == 0) { + decrement = 1; + } else { + decrement = decrement * 2; + } + Integer result = start - decrement; + if (result < end) { + return end; + } + return result; + } + } + + private static class RandomValue extends Value { + + public RandomValue(Integer start, Integer end) { + super(start, end); + } + + @Override + public Integer calculateCurrentValue() { + return RanVesUtils.getRandomNumber(start, end); + } + } + + @AllArgsConstructor + @EqualsAndHashCode + private static class Key { + + private String paramName; + private String mapKey; + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanCheckCellIsDeadOnEvent.java b/src/main/java/org/onap/a1pesimulator/service/report/RanCheckCellIsDeadOnEvent.java new file mode 100644 index 0000000..a3fc3da --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanCheckCellIsDeadOnEvent.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import static org.onap.a1pesimulator.service.cell.RanCellStateService.TOPIC_CELL; + +import java.util.Optional; +import org.onap.a1pesimulator.data.cell.CellDetails; +import org.onap.a1pesimulator.data.cell.state.CellStateEnum; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.data.ves.MeasurementFields; +import org.onap.a1pesimulator.service.cell.RanCellsHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Service; + +@Service +public class RanCheckCellIsDeadOnEvent implements OnEventAction { + + private static final Logger log = LoggerFactory.getLogger(RanCheckCellIsDeadOnEvent.class); + + private final RanCellsHolder ranCellsHolder; + private final SimpMessagingTemplate messagingTemplate; + + private final Integer failingModeThroughputValue; + private final Integer failingModeLatencyValue; + private final Integer failingCheckoutDelayTimeInSec; + + private static final int TO_MICRO_SEC = 1_000_000; + + public RanCheckCellIsDeadOnEvent(RanCellsHolder ranCellsHolder, SimpMessagingTemplate messagingTemplate, + @Value("${ves.failing.throughput}") Integer failingModeThroughputValue, + @Value("${ves.failing.latency}") Integer failingModeLatencyValue, + @Value("${ves.failing.checkout.delay}") Integer failingCheckoutDelayTimeInSec) { + this.ranCellsHolder = ranCellsHolder; + this.messagingTemplate = messagingTemplate; + + this.failingModeThroughputValue = failingModeThroughputValue; + this.failingModeLatencyValue = failingModeLatencyValue; + this.failingCheckoutDelayTimeInSec = failingCheckoutDelayTimeInSec; + } + + @Override + public void onEvent(VesEvent event) { + Optional cellId = getCellIdentifier(event); + Optional throughput = getCellThroughput(event); + Optional latency = getCellLatency(event); + + if (cellId.isPresent() && throughput.isPresent() && latency.isPresent()) { + checkCell(cellId.get(), Integer.parseInt(throughput.get()), Integer.parseInt(latency.get()), + event.getCommonEventHeader().getLastEpochMicrosec()); + } + } + + private void checkCell(String cellId, Integer throughput, Integer latency, Long lastEpochMicrosec) { + if (throughput <= failingModeThroughputValue && latency >= failingModeLatencyValue) { + log.info("Failure mode detected for cell {}", cellId); + processSleepingMode(cellId, lastEpochMicrosec); + } + } + + private void processSleepingMode(String cellId, Long lastEpochMicrosec) { + CellDetails cell = ranCellsHolder.getCellById(cellId); + if (cell.getCellStateMachine().getState() == CellStateEnum.GOING_TO_SLEEP) { + Optional cellInFailureModeOpt = + ranCellsHolder.getCellsInFailureMode(cellId); + if (cellInFailureModeOpt.isPresent()) { + RanCellsHolder.CellInFailureMode cellInFailureMode = cellInFailureModeOpt.get(); + if (cellInFailureMode.getSleepingModeDetectedTime() == null) { + cellInFailureMode.setSleepingModeDetectedTime(lastEpochMicrosec); + } else { + long waitingEpochMicrosec = addDelayTime(cellInFailureMode.getSleepingModeDetectedTime()); + if (lastEpochMicrosec >= waitingEpochMicrosec) { + log.info("Cell {} is sleeping!", cellId); + cell.nextState(); + messagingTemplate.convertAndSend(TOPIC_CELL, cell); + } + } + } + } + } + + private Optional getCellIdentifier(VesEvent event) { + return getValueFromAdditionalMeasurement(event, "identifier"); + } + + private Optional getCellThroughput(VesEvent event) { + return getValueFromAdditionalMeasurement(event, "throughput"); + } + + private Optional getCellLatency(VesEvent event) { + return getValueFromAdditionalMeasurement(event, "latency"); + } + + private Optional getValueFromAdditionalMeasurement(VesEvent event, String key) { + Optional measurement = getAdditionalMeasurement(event, key); + return measurement.map(this::getValueFromAdditionalMeasurement); + } + + private String getValueFromAdditionalMeasurement(MeasurementFields.AdditionalMeasurement measurement) { + return measurement.getHashMap().get("value"); + } + + private Optional getAdditionalMeasurement(VesEvent event, + String additionalMeasurement) { + return event.getMeasurementFields().getAdditionalMeasurements().stream() + .filter(e -> e.getName().equals(additionalMeasurement)).findFirst(); + } + + private long addDelayTime(long epoch) { + return epoch + failingCheckoutDelayTimeInSec * TO_MICRO_SEC; + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanEventCustomizerFactory.java b/src/main/java/org/onap/a1pesimulator/service/report/RanEventCustomizerFactory.java new file mode 100644 index 0000000..26ec13a --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanEventCustomizerFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import java.text.MessageFormat; + +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.service.common.EventCustomizer; +import org.onap.a1pesimulator.service.ue.RanUeHolder; +import org.springframework.stereotype.Component; + +@Component +public class RanEventCustomizerFactory { + + private final EventCustomizer regularEventCustomizer; + private final RanUeHolder ranUeHolder; + + public RanEventCustomizerFactory(EventCustomizer regularEventCustomizer, RanUeHolder ranUeHolder) { + this.ranUeHolder = ranUeHolder; + this.regularEventCustomizer = regularEventCustomizer; + } + + public EventCustomizer getEventCustomizer(VesEvent event, Mode mode) { + switch (mode) { + case REGULAR: + return regularEventCustomizer; + case FAILURE: + return new RanCellFailureEventCustomizer(event, ranUeHolder); + default: + throw new RuntimeException( + MessageFormat.format("Cannot construct event customizer for mode: {0}", mode)); + } + } + + public enum Mode { + REGULAR, FAILURE + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerService.java b/src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerService.java new file mode 100644 index 0000000..a1af9ac --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerService.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +import org.onap.a1pesimulator.data.ReportingMethodEnum; +import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.springframework.http.ResponseEntity; + +public interface RanReportsBrokerService { + + ResponseEntity startSendingReports(String identifier, VesEvent vesEvent, Integer interval, ReportingMethodEnum reportingMethods); + + Optional stopSendingReports(String identifier); + + Map getPeriodicEventsCache(); + + Collection getEnabledEventElementIdentifiers(); + + RanPeriodicEvent getPeriodicEvent(String identifier); + + VesEvent startSendingFailureReports(String identifier, ReportingMethodEnum reportingMethods); + + VesEvent getGlobalPmVesStructure(); + + void setGlobalPmVesStructure(VesEvent event); + + Integer getGlobalVesInterval(); + + void setGlobalVesInterval(Integer interval); + + String getGlobalReportingMethod(); + + void setGlobalReportingMethod(String reportingMethod); +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerServiceImpl.java b/src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerServiceImpl.java new file mode 100644 index 0000000..b441164 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanReportsBrokerServiceImpl.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +import org.onap.a1pesimulator.data.ReportingMethodEnum; +import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.data.ves.MeasurementFields.AdditionalMeasurement; +import org.onap.a1pesimulator.util.Constants; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +@Service +public class RanReportsBrokerServiceImpl implements RanReportsBrokerService { + + private final RanVesDataProvider vesDataProvider; + + private final RanVesHolder vesHolder; + + public RanReportsBrokerServiceImpl(RanVesDataProvider vesDataProvider, RanVesHolder vesHolder) { + this.vesDataProvider = vesDataProvider; + this.vesHolder = vesHolder; + } + + @Override + public Map getPeriodicEventsCache() { + return vesHolder.getPeriodicEventsCache(); + } + + @Override + public ResponseEntity startSendingReports(String identifier, VesEvent vesEvent, Integer interval, ReportingMethodEnum reportingMethod) { + enrichWithIdentifier(identifier, vesEvent); + ResponseEntity response = vesHolder.startSendingVesEvents(identifier, vesEvent, interval, reportingMethod); + return ResponseEntity.accepted().body(response.getBody()); + } + + @Override + public VesEvent startSendingFailureReports(String identifier, ReportingMethodEnum reportingMethod) { + + var vesEvent = vesDataProvider.getFailurePmVesEvent(); + + enrichWithIdentifier(identifier, vesEvent); + vesHolder.startSendingFailureVesEvents(identifier, vesEvent, reportingMethod); + return vesEvent; + } + + @Override + public Optional stopSendingReports(String identifier) { + return vesHolder.stopSendingVesEvents(identifier); + } + + @Override + public Collection getEnabledEventElementIdentifiers() { + return vesHolder.getEnabledEventElementIdentifiers(); + } + + @Override + public RanPeriodicEvent getPeriodicEvent(String identifier) { + return vesHolder.getPeriodicEventForCell(identifier); + } + + @Override + public VesEvent getGlobalPmVesStructure() { + return vesDataProvider.getPmVesEvent(); + } + + @Override + public void setGlobalPmVesStructure(VesEvent event) { + vesDataProvider.setPmVesEvent(event); + } + + @Override + public Integer getGlobalVesInterval() { + return vesDataProvider.getRegularVesInterval(); + } + + @Override + public void setGlobalVesInterval(Integer interval) { + vesDataProvider.setInterval(interval); + } + + @Override + public String getGlobalReportingMethod() { + return vesDataProvider.getReportingMethod(); + } + + @Override + public void setGlobalReportingMethod(String reportingMethod) { + vesDataProvider.setReportingMethod(reportingMethod); + } + + private void enrichWithIdentifier(String identifier, VesEvent event) { + if (event.getMeasurementFields() == null || event.getMeasurementFields().getAdditionalMeasurements() == null) { + return; + } + Collection additionalMeasurements = + event.getMeasurementFields().getAdditionalMeasurements(); + Optional identityOpt = additionalMeasurements.stream() + .filter(m -> Constants.MEASUREMENT_FIELD_IDENTIFIER + .equalsIgnoreCase(m.getName())) + .findAny(); + if (identityOpt.isPresent()) { + identityOpt.get().getHashMap().put(Constants.MEASUREMENT_FIELD_IDENTIFIER, identifier); + } else { + var measurement = new AdditionalMeasurement(); + measurement.setName(Constants.MEASUREMENT_FIELD_IDENTIFIER); + measurement.setHashMap(Collections.singletonMap(Constants.MEASUREMENT_FIELD_VALUE, identifier)); + additionalMeasurements.add(measurement); + } + } + +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanSendVesRunnable.java b/src/main/java/org/onap/a1pesimulator/service/report/RanSendVesRunnable.java new file mode 100644 index 0000000..e982417 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanSendVesRunnable.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import java.util.Collection; + +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.service.common.AbstractRanRunnable; +import org.onap.a1pesimulator.service.common.EventCustomizer; + +public class RanSendVesRunnable extends AbstractRanRunnable { + + private final RanVesSender vesSender; + + public RanSendVesRunnable(RanVesSender vesSender, VesEvent event, EventCustomizer eventCustomizer, + Collection onEventActions) { + super(event, eventCustomizer, onEventActions); + this.vesSender = vesSender; + } + + @Override + public void run() { + VesEvent customizedEvent = eventCustomizer.apply(event); + onEventAction.forEach(action -> action.onEvent(customizedEvent)); + vesSender.send(customizedEvent); + } + + @Override + public void updateEvent(VesEvent event) { + this.event = event; + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanVesDataProvider.java b/src/main/java/org/onap/a1pesimulator/service/report/RanVesDataProvider.java new file mode 100644 index 0000000..35f2773 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanVesDataProvider.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import java.io.IOException; +import java.net.URL; + +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.util.JsonUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Service; + +import lombok.Setter; + +@Service +public class RanVesDataProvider { + + private static final String PM_VES_LOCATION = "classpath:pmVes.json"; + private static final String PM_FAILURE_VES_LOCATION = "classpath:failurePmVes.json"; + + @Setter + private VesEvent pmVesEvent; + @Setter + private VesEvent failurePmVesEvent; + @Setter + private Integer interval; + @Setter + private String reportingMethod; + + private final Integer defaultInterval; + private final String defaultReportingMethod; + private final ResourceLoader resourceLoader; + + public RanVesDataProvider(@Value("${ves.defaultInterval}") Integer defaultInterval, + @Value("${ves.defaultReportingMethod}") String defaultReportingMethod, + ResourceLoader resourceLoader) { + this.defaultInterval = defaultInterval; + this.defaultReportingMethod = defaultReportingMethod; + this.resourceLoader = resourceLoader; + } + + @Cacheable("pmVes") + public VesEvent loadPmVesEvent() { + URL resourceUrl = getResourceURL(resourceLoader.getResource(PM_VES_LOCATION)); + return JsonUtils.INSTANCE.deserializeFromFileUrl(resourceUrl, VesEvent.class); + } + + @Cacheable("failurePmVes") + public VesEvent loadFailurePmVesEvent() { + URL resourceUrl = getResourceURL(resourceLoader.getResource(PM_FAILURE_VES_LOCATION)); + return JsonUtils.INSTANCE.deserializeFromFileUrl(resourceUrl, VesEvent.class); + } + + public Integer getRegularVesInterval() { + if (interval == null) { + return defaultInterval; + } + return interval; + } + + public String getReportingMethod() { + if (reportingMethod == null) { + return defaultReportingMethod; + } + + return reportingMethod; + } + + public Integer getFailureVesInterval() { + return defaultInterval; + } + + public VesEvent getPmVesEvent() { + if (pmVesEvent == null) { + return loadPmVesEvent(); + } + return pmVesEvent; + } + + public VesEvent getFailurePmVesEvent() { + if (failurePmVesEvent == null) { + return loadFailurePmVesEvent(); + } + return failurePmVesEvent; + } + + private URL getResourceURL(Resource resource) { + try { + return resource.getURL(); + } catch (IOException e) { + throw new RuntimeException("Cannot get resource URL for: " + resource.getFilename()); + } + } +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanVesHolder.java b/src/main/java/org/onap/a1pesimulator/service/report/RanVesHolder.java new file mode 100644 index 0000000..dba7898 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanVesHolder.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; + +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.function.BiFunction; + +import org.onap.a1pesimulator.data.ReportingMethodEnum; +import org.onap.a1pesimulator.data.RequestParameters; +import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; +import org.onap.a1pesimulator.data.fileready.RanPeriodicSendReport; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.service.common.AbstractRanRunnable; +import org.onap.a1pesimulator.service.common.EventCustomizer; +import org.onap.a1pesimulator.service.pm.RanFileReadyHolder; +import org.onap.a1pesimulator.service.pm.RanSaveFileReadyRunnable; +import org.onap.a1pesimulator.service.pm.RanSendReportsRunnable; +import org.onap.a1pesimulator.service.report.RanEventCustomizerFactory.Mode; +import org.onap.a1pesimulator.util.VnfConfigReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.stereotype.Service; + +import lombok.Getter; + +@Service +public class RanVesHolder { + + private static final Logger log = LoggerFactory.getLogger(RanVesHolder.class); + private final Map periodicEventsCache = new ConcurrentHashMap<>(); + + private final RanVesDataProvider vesDataProvider; + private final RanEventCustomizerFactory eventCustomizerFactory; + private final ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler; + private final Collection onEventActions; + private final RanFileReadyHolder ranFileReadyHolder; + private final RanVesSender vesSender; + private final VnfConfigReader vnfConfigReader; + private ThreadSendReportFunction threadSendReportFunction; + + public RanVesHolder(ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler, RanFileReadyHolder ranFileReadyHolder, RanVesSender vesSender, + VnfConfigReader vnfConfigReader, + RanEventCustomizerFactory eventCustomizerFactory, RanVesDataProvider vesDataProvider, + Collection onEventActions) { + this.vesPmThreadPoolTaskScheduler = vesPmThreadPoolTaskScheduler; + this.ranFileReadyHolder = ranFileReadyHolder; + this.vesSender = vesSender; + this.vnfConfigReader = vnfConfigReader; + this.eventCustomizerFactory = eventCustomizerFactory; + this.vesDataProvider = vesDataProvider; + this.onEventActions = onEventActions; + } + + /** + * Thread for periodical sending of PM Bulk Files and fileReady Events + */ + private void startSendingReports() { + if (isNull(threadSendReportFunction) || !threadSendReportFunction.isProcessRunning()) { + int repPeriod = vnfConfigReader.getVnfConfig().getRepPeriod(); + threadSendReportFunction = new ThreadSendReportFunction(vesPmThreadPoolTaskScheduler, repPeriod, ranFileReadyHolder); + threadSendReportFunction.startEvent(); + log.info("Start sending reports every {} seconds", repPeriod); + } + } + + /** + * Stops sending the report after the last cell was stopped. It send the last report before stop completely + */ + private void stopSendingReports(String cellId) { + sendLastReport(cellId); + if (nonNull(threadSendReportFunction) && !isAnyEventRunning()) { + threadSendReportFunction.getRanPeriodicVesEvent().getScheduledFuture().cancel(false); + log.info("Stop sending reports every {} seconds", vnfConfigReader.getVnfConfig().getRepPeriod()); + } + } + + /** + * Sends the last report after specific cell was stopped + */ + private void sendLastReport(String cellId) { + if (nonNull(threadSendReportFunction)) { + log.trace("Send last report after stop for cell: {}", cellId); + ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessageForCellId(cellId); + } + } + + Map getPeriodicEventsCache() { + return periodicEventsCache; + } + + ResponseEntity startSendingVesEvents(String identifier, VesEvent vesEvent, Integer interval, ReportingMethodEnum reportingMethod) { + + periodicEventsCache.compute(identifier, + new ThreadCacheUpdateFunction(vesPmThreadPoolTaskScheduler, eventCustomizerFactory.getEventCustomizer(vesEvent, Mode.REGULAR), onEventActions, + ranFileReadyHolder, vesSender, RequestParameters.builder() + .vesEvent(vesEvent).identifier(identifier).reportingMethod(reportingMethod).interval(interval).build())); + if (ReportingMethodEnum.FILE_READY.equals(reportingMethod)) { + startSendingReports(); + } + return ResponseEntity.accepted().body("VES Event sending started"); + } + + ResponseEntity startSendingFailureVesEvents(String identifier, VesEvent vesEvent, ReportingMethodEnum reportingMethod) { + + periodicEventsCache.compute(identifier, + new ThreadCacheUpdateFunction(vesPmThreadPoolTaskScheduler, eventCustomizerFactory.getEventCustomizer(vesEvent, Mode.FAILURE), onEventActions, + ranFileReadyHolder, + vesSender, RequestParameters.builder().vesEvent(vesEvent).identifier(identifier).interval(vesDataProvider.getFailureVesInterval()) + .reportingMethod(reportingMethod).build())); + if (ReportingMethodEnum.FILE_READY.equals(reportingMethod)) { + startSendingReports(); + } + return ResponseEntity.accepted().body("Failure VES Event sending started"); + } + + Optional stopSendingVesEvents(String identifier) { + RanPeriodicEvent periodicEvent = periodicEventsCache.remove(identifier); + if (periodicEvent == null) { + return Optional.empty(); + } + periodicEvent.getScheduledFuture().cancel(false); + stopSendingReports(identifier); + return Optional.of(periodicEvent); + } + + Collection getEnabledEventElementIdentifiers() { + return periodicEventsCache.keySet(); + } + + public boolean isEventEnabled(String identifier) { + return periodicEventsCache.containsKey(identifier); + } + + public boolean isAnyEventRunning() { + return !periodicEventsCache.isEmpty(); + } + + RanPeriodicEvent getPeriodicEventForCell(String identifier) { + if (!periodicEventsCache.containsKey(identifier)) { + throw new IllegalArgumentException( + MessageFormat.format("Cannot find event for given source {0}", identifier)); + } + return periodicEventsCache.get(identifier); + } + + private static class ThreadCacheUpdateFunction + implements BiFunction { + + private final Integer interval; + private final ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler; + private final VesEvent vesEvent; + private final EventCustomizer eventCustomizer; + private final Collection onEventActions; + private final RanFileReadyHolder fileReadyHolder; + private final RanVesSender vesSender; + private final String cellId; + private final ReportingMethodEnum reportingMethod; + + public ThreadCacheUpdateFunction(ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler, EventCustomizer eventCustomizer, + Collection onEventActions, + RanFileReadyHolder fileReadyHolder, RanVesSender vesSender, RequestParameters requestParameters) { + this.vesPmThreadPoolTaskScheduler = vesPmThreadPoolTaskScheduler; + this.vesEvent = requestParameters.getVesEvent(); + this.interval = requestParameters.getInterval(); + this.eventCustomizer = eventCustomizer; + this.onEventActions = onEventActions; + this.fileReadyHolder = fileReadyHolder; + this.vesSender = vesSender; + this.cellId = requestParameters.getIdentifier(); + this.reportingMethod = requestParameters.getReportingMethod(); + } + + @Override + public RanPeriodicEvent apply(String key, RanPeriodicEvent value) { + if (value != null) { + // if thread is registered then cancel it and schedule a new one + value.getScheduledFuture().cancel(false); + } + AbstractRanRunnable ranRunnable = (ReportingMethodEnum.FILE_READY.equals(reportingMethod)) ? + new RanSaveFileReadyRunnable(fileReadyHolder, cellId, vesEvent, eventCustomizer, interval, onEventActions) : + new RanSendVesRunnable(vesSender, vesEvent, eventCustomizer, onEventActions); + + ScheduledFuture scheduledFuture = + vesPmThreadPoolTaskScheduler.scheduleAtFixedRate(ranRunnable, interval * 1000L); + return RanPeriodicEvent.builder().event(vesEvent).interval(interval).reportingMethod(reportingMethod.getValue()).scheduledFuture(scheduledFuture) + .ranRunnable(ranRunnable).build(); + } + + } + + @Getter + private static class ThreadSendReportFunction { + + protected final Integer interval; + protected final ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler; + protected RanPeriodicSendReport ranPeriodicVesEvent; + protected ScheduledFuture scheduledFuture; + protected final RanFileReadyHolder ranFileReadyHolder; + + public ThreadSendReportFunction(ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler, Integer interval, RanFileReadyHolder ranFileReadyHolder) { + this.vesPmThreadPoolTaskScheduler = vesPmThreadPoolTaskScheduler; + this.interval = interval; + this.ranFileReadyHolder = ranFileReadyHolder; + } + + public void startEvent() { + RanSendReportsRunnable ranSendReportsRunnable = + new RanSendReportsRunnable(ranFileReadyHolder); + scheduledFuture = vesPmThreadPoolTaskScheduler.scheduleAtFixedRate(ranSendReportsRunnable, interval * 1000L); + this.ranPeriodicVesEvent = RanPeriodicSendReport.builder().interval(interval).scheduledFuture(scheduledFuture) + .ranSendReportsRunnable(ranSendReportsRunnable).build(); + } + + public boolean isProcessRunning() { + return (nonNull(scheduledFuture) && !(scheduledFuture.isCancelled() || scheduledFuture.isDone())); + } + } + +} diff --git a/src/main/java/org/onap/a1pesimulator/service/report/RanVesSender.java b/src/main/java/org/onap/a1pesimulator/service/report/RanVesSender.java new file mode 100644 index 0000000..d12abd8 --- /dev/null +++ b/src/main/java/org/onap/a1pesimulator/service/report/RanVesSender.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import static java.util.Objects.nonNull; + +import org.onap.a1pesimulator.data.Event; +import org.onap.a1pesimulator.data.VnfConfig; +import org.onap.a1pesimulator.data.ves.CommonEventHeader; +import org.onap.a1pesimulator.exception.VesBrokerException; +import org.onap.a1pesimulator.util.JsonUtils; +import org.onap.a1pesimulator.util.VnfConfigReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import reactor.core.publisher.Mono; + +@Service +public class RanVesSender { + + private static final Logger log = LoggerFactory.getLogger(RanVesSender.class); + + private RestTemplate restTemplate; + + private String vesCollectorProtocol; + + private String vesCollectorPath; + + private VnfConfigReader vnfConfigReader; + + public RanVesSender(RestTemplate restTemplate, VnfConfigReader vnfConfigReader, + @Value("${ves.collector.protocol}") String vesCollectorProtocol, + @Value("${ves.collector.endpoint}") String vesCollectorPath) { + this.restTemplate = restTemplate; + this.vnfConfigReader = vnfConfigReader; + this.vesCollectorProtocol = vesCollectorProtocol; + this.vesCollectorPath = vesCollectorPath; + } + + public Mono send(Event event) { + if (nonNull(event)) { + VnfConfig vnfConfig = vnfConfigReader.getVnfConfig(); + String url = getVesCollectorUrl(vnfConfig); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setBasicAuth(vnfConfig.getVesUser(), vnfConfig.getVesPassword()); + + setVnfInfo(event, vnfConfig); + String eventInJson = JsonUtils.INSTANCE.objectToPrettyString(event); + + log.trace("Sending following event: {} ", eventInJson); + + HttpEntity entity = new HttpEntity<>(eventInJson, headers); + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); + + log.debug("Response received: {}", response); + + if (response.getStatusCode() == HttpStatus.OK || response.getStatusCode() == HttpStatus.ACCEPTED) { + return Mono.just(response.getStatusCode()); + } else { + String errorMsg = + "Failed to send VES event to the collector with response status code:" + response.getStatusCode(); + return Mono.error(new VesBrokerException(errorMsg)); + } + } + return Mono.error(new VesBrokerException("There is no event to send to the collector.")); + } + + private String getVesCollectorUrl(VnfConfig vnfConfig) { + return vesCollectorProtocol + "://" + vnfConfig.getVesHost() + ":" + vnfConfig.getVesPort() + vesCollectorPath; + } + + private void setVnfInfo(Event vesEvent, VnfConfig vnfConfig) { + CommonEventHeader header = vesEvent.getCommonEventHeader(); + header.setSourceId(vnfConfig.getVnfId()); + header.setSourceName(vnfConfig.getVnfName()); + vesEvent.setCommonEventHeader(header); + } + +} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/OnEventAction.java b/src/main/java/org/onap/a1pesimulator/service/ves/OnEventAction.java deleted file mode 100644 index ba1ddab..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/OnEventAction.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import org.onap.a1pesimulator.data.ves.VesEvent; - -@FunctionalInterface -public interface OnEventAction { - - void onEvent(VesEvent event); -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanCellEventCustomizer.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanCellEventCustomizer.java deleted file mode 100644 index 7cb375f..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanCellEventCustomizer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import java.util.List; -import java.util.Optional; - -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.data.ves.MeasurementFields.AdditionalMeasurement; -import org.onap.a1pesimulator.service.common.EventCustomizer; -import org.onap.a1pesimulator.service.ue.RanUeHolder; -import org.onap.a1pesimulator.util.Constants; -import org.onap.a1pesimulator.util.JsonUtils; -import org.onap.a1pesimulator.util.RanVesUtils; -import org.springframework.stereotype.Service; - -@Service -public class RanCellEventCustomizer implements EventCustomizer { - - private static final String UE_PARAM_TRAFFIC_MODEL_RANGE = "[[20-50]]"; - private final RanUeHolder ranUeHolder; - - public RanCellEventCustomizer(RanUeHolder ueHolder) { - this.ranUeHolder = ueHolder; - } - - @Override - public VesEvent apply(VesEvent t) { - VesEvent event = JsonUtils.INSTANCE.clone(t); - return customizeEvent(event); - } - - private VesEvent customizeEvent(VesEvent event) { - RanVesUtils.updateHeader(event); - enrichWithUeData(event); - randomizeEvent(event); - return event; - } - - private void randomizeEvent(VesEvent event) { - List additionalMeasurementsToRandomize = - event.getMeasurementFields().getAdditionalMeasurements(); - event.getMeasurementFields().setAdditionalMeasurements( - RanVesUtils.randomizeAdditionalMeasurements(additionalMeasurementsToRandomize)); - } - - private void enrichWithUeData(VesEvent event) { - - Optional identity = event.getMeasurementFields().getAdditionalMeasurements().stream() - .filter(msrmnt -> Constants.MEASUREMENT_FIELD_IDENTIFIER - .equalsIgnoreCase( - msrmnt.getName())) - .findAny(); - identity.ifPresent(m -> addTrafficModelMeasurement(event)); - } - - private void addTrafficModelMeasurement(VesEvent event) { - AdditionalMeasurement trafficModelMeasurement = - RanVesUtils.buildTrafficModelMeasurement( ranUeHolder, UE_PARAM_TRAFFIC_MODEL_RANGE); - event.getMeasurementFields().getAdditionalMeasurements().add(trafficModelMeasurement); - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanCellFailureEventCustomizer.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanCellFailureEventCustomizer.java deleted file mode 100644 index a21d1ad..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanCellFailureEventCustomizer.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import java.text.MessageFormat; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; - -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.data.ves.MeasurementFields.AdditionalMeasurement; -import org.onap.a1pesimulator.service.common.EventCustomizer; -import org.onap.a1pesimulator.service.ue.RanUeHolder; -import org.onap.a1pesimulator.util.Constants; -import org.onap.a1pesimulator.util.JsonUtils; -import org.onap.a1pesimulator.util.RanVesUtils; - -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; - -public class RanCellFailureEventCustomizer implements EventCustomizer { - - private static final String UE_PARAM_TRAFFIC_MODEL_RANGE = "[[50->10]]"; - private final RanUeHolder ranUeHolder; - private final VesEvent event; - - private final Map additionalMeasurementsValues = new HashMap<>(); - private final ValueFactory valueFactory; - - public RanCellFailureEventCustomizer(VesEvent event, RanUeHolder ranUeHolder) { - this.ranUeHolder = ranUeHolder; - this.event = event; - valueFactory = new ValueFactory(); - collectAdditionalMeasurementValues(event); - } - - @Override - public VesEvent apply(VesEvent t) { - return customizeEvent(JsonUtils.INSTANCE.clone(this.event)); - } - - private void collectAdditionalMeasurementValues(VesEvent event) { - Collection additionalMeasurementsToResolve = - event.getMeasurementFields().getAdditionalMeasurements(); - additionalMeasurementsToResolve.forEach(this::collectAdditionalMeasurementValue); - } - - private void collectAdditionalMeasurementValue(AdditionalMeasurement m) { - for (Entry entry : m.getHashMap().entrySet()) { - if (!RanVesUtils.isRange(entry.getValue())) { - continue; - } - additionalMeasurementsValues - .putIfAbsent(new Key(m.getName(), entry.getKey()), valueFactory.getInstance(entry.getValue())); - } - } - - private VesEvent customizeEvent(VesEvent event) { - RanVesUtils.updateHeader(event); - enrichWithUeData(event); - resolveRanges(event); - return event; - } - - private void resolveRanges(VesEvent event) { - List additionalMeasurementsToResolve = - event.getMeasurementFields().getAdditionalMeasurements(); - - additionalMeasurementsToResolve.forEach(this::resolveRanges); - event.getMeasurementFields().setAdditionalMeasurements(additionalMeasurementsToResolve); - } - - private void resolveRanges(AdditionalMeasurement m) { - for (Entry entry : m.getHashMap().entrySet()) { - Key key = new Key(m.getName(), entry.getKey()); - if (!additionalMeasurementsValues.containsKey(key)) { - continue; - } - Value value = additionalMeasurementsValues.get(key); - value.current = value.calculateCurrentValue(); - entry.setValue(value.current.toString()); - } - } - - private void enrichWithUeData(VesEvent event) { - - Optional identity = event.getMeasurementFields().getAdditionalMeasurements().stream() - .filter(msrmnt -> Constants.MEASUREMENT_FIELD_IDENTIFIER - .equalsIgnoreCase( - msrmnt.getName())) - .findAny(); - identity.ifPresent(m -> addTrafficModelMeasurement(event)); - } - - private void addTrafficModelMeasurement(VesEvent event) { - AdditionalMeasurement trafficModelMeasurement = - RanVesUtils.buildTrafficModelMeasurement(ranUeHolder, UE_PARAM_TRAFFIC_MODEL_RANGE); - event.getMeasurementFields().getAdditionalMeasurements().add(trafficModelMeasurement); - - collectAdditionalMeasurementValue(trafficModelMeasurement); - } - - // -----------helper classes - - private static class ValueFactory { - - public Value getInstance(String value) { - String[] split; - if (RanVesUtils.isRandomRange(value)) { - split = RanVesUtils.splitRandomRange(value); - return new RandomValue(Integer.valueOf(split[0]), Integer.valueOf(split[1])); - } - if (RanVesUtils.isTrandingRange(value)) { - split = RanVesUtils.splitTrendingRange(value); - Integer start = Integer.valueOf(split[0]); - Integer end = Integer.valueOf(split[1]); - if (start < end) { - return new RaisingValue(start, end); - } else if (start > end) { - return new DecreasingValue(start, end); - } - } - throw new RuntimeException(MessageFormat.format("Cannot instantiate Value from string: {0}", value)); - } - } - - private abstract static class Value { - - protected Integer start; - protected Integer end; - protected Integer current; - - public Value(Integer start, Integer end) { - this.start = start; - this.end = end; - } - - public abstract Integer calculateCurrentValue(); - } - - private static class RaisingValue extends Value { - - private int increment; - - public RaisingValue(Integer start, Integer end) { - super(start, end); - } - - @Override - public Integer calculateCurrentValue() { - if (current == null) { - return start; - } - if (increment == 0) { - increment = 1; - } else { - increment = increment * 2; - } - Integer result = start + increment; - if (result > end) { - increment = 1; - return end; - } - return result; - } - } - - private static class DecreasingValue extends Value { - - private int decrement; - - public DecreasingValue(Integer start, Integer end) { - super(start, end); - } - - @Override - public Integer calculateCurrentValue() { - if (current == null) { - return start; - } - if (decrement == 0) { - decrement = 1; - } else { - decrement = decrement * 2; - } - Integer result = start - decrement; - if (result < end) { - return end; - } - return result; - } - } - - private static class RandomValue extends Value { - - public RandomValue(Integer start, Integer end) { - super(start, end); - } - - @Override - public Integer calculateCurrentValue() { - return RanVesUtils.getRandomNumber(start, end); - } - } - - @AllArgsConstructor - @EqualsAndHashCode - private static class Key { - - private String paramName; - private String mapKey; - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanCheckCellIsDeadOnEvent.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanCheckCellIsDeadOnEvent.java deleted file mode 100644 index 3d0c400..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanCheckCellIsDeadOnEvent.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import static org.onap.a1pesimulator.service.cell.RanCellStateService.TOPIC_CELL; - -import java.util.Optional; -import org.onap.a1pesimulator.data.cell.CellDetails; -import org.onap.a1pesimulator.data.cell.state.CellStateEnum; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.data.ves.MeasurementFields; -import org.onap.a1pesimulator.service.cell.RanCellsHolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.messaging.simp.SimpMessagingTemplate; -import org.springframework.stereotype.Service; - -@Service -public class RanCheckCellIsDeadOnEvent implements OnEventAction { - - private static final Logger log = LoggerFactory.getLogger(RanCheckCellIsDeadOnEvent.class); - - private final RanCellsHolder ranCellsHolder; - private final SimpMessagingTemplate messagingTemplate; - - private final Integer failingModeThroughputValue; - private final Integer failingModeLatencyValue; - private final Integer failingCheckoutDelayTimeInSec; - - private static final int TO_MICRO_SEC = 1_000_000; - - public RanCheckCellIsDeadOnEvent(RanCellsHolder ranCellsHolder, SimpMessagingTemplate messagingTemplate, - @Value("${ves.failing.throughput}") Integer failingModeThroughputValue, - @Value("${ves.failing.latency}") Integer failingModeLatencyValue, - @Value("${ves.failing.checkout.delay}") Integer failingCheckoutDelayTimeInSec) { - this.ranCellsHolder = ranCellsHolder; - this.messagingTemplate = messagingTemplate; - - this.failingModeThroughputValue = failingModeThroughputValue; - this.failingModeLatencyValue = failingModeLatencyValue; - this.failingCheckoutDelayTimeInSec = failingCheckoutDelayTimeInSec; - } - - @Override - public void onEvent(VesEvent event) { - Optional cellId = getCellIdentifier(event); - Optional throughput = getCellThroughput(event); - Optional latency = getCellLatency(event); - - if (cellId.isPresent() && throughput.isPresent() && latency.isPresent()) { - checkCell(cellId.get(), Integer.parseInt(throughput.get()), Integer.parseInt(latency.get()), - event.getCommonEventHeader().getLastEpochMicrosec()); - } - } - - private void checkCell(String cellId, Integer throughput, Integer latency, Long lastEpochMicrosec) { - if (throughput <= failingModeThroughputValue && latency >= failingModeLatencyValue) { - log.info("Failure mode detected for cell {}", cellId); - processSleepingMode(cellId, lastEpochMicrosec); - } - } - - private void processSleepingMode(String cellId, Long lastEpochMicrosec) { - CellDetails cell = ranCellsHolder.getCellById(cellId); - if (cell.getCellStateMachine().getState() == CellStateEnum.GOING_TO_SLEEP) { - Optional cellInFailureModeOpt = - ranCellsHolder.getCellsInFailureMode(cellId); - if (cellInFailureModeOpt.isPresent()) { - RanCellsHolder.CellInFailureMode cellInFailureMode = cellInFailureModeOpt.get(); - if (cellInFailureMode.getSleepingModeDetectedTime() == null) { - cellInFailureMode.setSleepingModeDetectedTime(lastEpochMicrosec); - } else { - long waitingEpochMicrosec = addDelayTime(cellInFailureMode.getSleepingModeDetectedTime()); - if (lastEpochMicrosec >= waitingEpochMicrosec) { - log.info("Cell {} is sleeping!", cellId); - cell.nextState(); - messagingTemplate.convertAndSend(TOPIC_CELL, cell); - } - } - } - } - } - - private Optional getCellIdentifier(VesEvent event) { - return getValueFromAdditionalMeasurement(event, "identifier"); - } - - private Optional getCellThroughput(VesEvent event) { - return getValueFromAdditionalMeasurement(event, "throughput"); - } - - private Optional getCellLatency(VesEvent event) { - return getValueFromAdditionalMeasurement(event, "latency"); - } - - private Optional getValueFromAdditionalMeasurement(VesEvent event, String key) { - Optional measurement = getAdditionalMeasurement(event, key); - return measurement.map(this::getValueFromAdditionalMeasurement); - } - - private String getValueFromAdditionalMeasurement(MeasurementFields.AdditionalMeasurement measurement) { - return measurement.getHashMap().get("value"); - } - - private Optional getAdditionalMeasurement(VesEvent event, - String additionalMeasurement) { - return event.getMeasurementFields().getAdditionalMeasurements().stream() - .filter(e -> e.getName().equals(additionalMeasurement)).findFirst(); - } - - private long addDelayTime(long epoch) { - return epoch + failingCheckoutDelayTimeInSec * TO_MICRO_SEC; - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanEventCustomizerFactory.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanEventCustomizerFactory.java deleted file mode 100644 index c7c2ee9..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanEventCustomizerFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import java.text.MessageFormat; - -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.service.common.EventCustomizer; -import org.onap.a1pesimulator.service.ue.RanUeHolder; -import org.springframework.stereotype.Component; - -@Component -public class RanEventCustomizerFactory { - - private final EventCustomizer regularEventCustomizer; - private final RanUeHolder ranUeHolder; - - public RanEventCustomizerFactory(EventCustomizer regularEventCustomizer, RanUeHolder ranUeHolder) { - this.ranUeHolder = ranUeHolder; - this.regularEventCustomizer = regularEventCustomizer; - } - - public EventCustomizer getEventCustomizer(VesEvent event, Mode mode) { - switch (mode) { - case REGULAR: - return regularEventCustomizer; - case FAILURE: - return new RanCellFailureEventCustomizer(event, ranUeHolder); - default: - throw new RuntimeException( - MessageFormat.format("Cannot construct event customizer for mode: {0}", mode)); - } - } - - public enum Mode { - REGULAR, FAILURE - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanSendVesRunnable.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanSendVesRunnable.java deleted file mode 100644 index c537a5f..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanSendVesRunnable.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import java.util.Collection; - -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.service.common.AbstractRanRunnable; -import org.onap.a1pesimulator.service.common.EventCustomizer; - -public class RanSendVesRunnable extends AbstractRanRunnable { - - private final RanVesSender vesSender; - - public RanSendVesRunnable(RanVesSender vesSender, VesEvent event, EventCustomizer eventCustomizer, - Collection onEventActions) { - super(event, eventCustomizer, onEventActions); - this.vesSender = vesSender; - } - - @Override - public void run() { - VesEvent customizedEvent = eventCustomizer.apply(event); - onEventAction.forEach(action -> action.onEvent(customizedEvent)); - vesSender.send(customizedEvent); - } - - @Override - public void updateEvent(VesEvent event) { - this.event = event; - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerService.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerService.java deleted file mode 100644 index 1b92fbf..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerService.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import java.util.Collection; -import java.util.Map; -import java.util.Optional; - -import org.onap.a1pesimulator.data.ReportingMethodEnum; -import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.springframework.http.ResponseEntity; - -public interface RanVesBrokerService { - - ResponseEntity startSendingVesEvents(String identifier, VesEvent vesEvent, Integer interval, ReportingMethodEnum reportingMethods); - - Optional stopSendingVesEvents(String identifier); - - Map getPeriodicEventsCache(); - - Collection getEnabledEventElementIdentifiers(); - - RanPeriodicEvent getPeriodicEvent(String identifier); - - VesEvent startSendingFailureVesEvents(String identifier, ReportingMethodEnum reportingMethods); - - VesEvent getGlobalPmVesStructure(); - - void setGlobalPmVesStructure(VesEvent event); - - Integer getGlobalVesInterval(); - - void setGlobalVesInterval(Integer interval); - - String getGlobalReportingMethod(); - - void setGlobalReportingMethod(String reportingMethod); -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerServiceImpl.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerServiceImpl.java deleted file mode 100644 index ea4b46d..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesBrokerServiceImpl.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; - -import org.onap.a1pesimulator.data.ReportingMethodEnum; -import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.data.ves.MeasurementFields.AdditionalMeasurement; -import org.onap.a1pesimulator.util.Constants; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; - -@Service -public class RanVesBrokerServiceImpl implements RanVesBrokerService { - - private final RanVesDataProvider vesDataProvider; - - private final RanVesHolder vesHolder; - - public RanVesBrokerServiceImpl(RanVesDataProvider vesDataProvider, RanVesHolder vesHolder) { - this.vesDataProvider = vesDataProvider; - this.vesHolder = vesHolder; - } - - @Override - public Map getPeriodicEventsCache() { - return vesHolder.getPeriodicEventsCache(); - } - - @Override - public ResponseEntity startSendingVesEvents(String identifier, VesEvent vesEvent, Integer interval, ReportingMethodEnum reportingMethod) { - enrichWithIdentifier(identifier, vesEvent); - ResponseEntity response = vesHolder.startSendingVesEvents(identifier, vesEvent, interval, reportingMethod); - return ResponseEntity.accepted().body(response.getBody()); - } - - @Override - public VesEvent startSendingFailureVesEvents(String identifier, ReportingMethodEnum reportingMethod) { - - var vesEvent = vesDataProvider.getFailurePmVesEvent(); - - enrichWithIdentifier(identifier, vesEvent); - vesHolder.startSendingFailureVesEvents(identifier, vesEvent, reportingMethod); - return vesEvent; - } - - @Override - public Optional stopSendingVesEvents(String identifier) { - return vesHolder.stopSendingVesEvents(identifier); - } - - @Override - public Collection getEnabledEventElementIdentifiers() { - return vesHolder.getEnabledEventElementIdentifiers(); - } - - @Override - public RanPeriodicEvent getPeriodicEvent(String identifier) { - return vesHolder.getPeriodicEventForCell(identifier); - } - - @Override - public VesEvent getGlobalPmVesStructure() { - return vesDataProvider.getPmVesEvent(); - } - - @Override - public void setGlobalPmVesStructure(VesEvent event) { - vesDataProvider.setPmVesEvent(event); - } - - @Override - public Integer getGlobalVesInterval() { - return vesDataProvider.getRegularVesInterval(); - } - - @Override - public void setGlobalVesInterval(Integer interval) { - vesDataProvider.setInterval(interval); - } - - @Override - public String getGlobalReportingMethod() { - return vesDataProvider.getReportingMethod(); - } - - @Override - public void setGlobalReportingMethod(String reportingMethod) { - vesDataProvider.setReportingMethod(reportingMethod); - } - - private void enrichWithIdentifier(String identifier, VesEvent event) { - if (event.getMeasurementFields() == null || event.getMeasurementFields().getAdditionalMeasurements() == null) { - return; - } - Collection additionalMeasurements = - event.getMeasurementFields().getAdditionalMeasurements(); - Optional identityOpt = additionalMeasurements.stream() - .filter(m -> Constants.MEASUREMENT_FIELD_IDENTIFIER - .equalsIgnoreCase(m.getName())) - .findAny(); - if (identityOpt.isPresent()) { - identityOpt.get().getHashMap().put(Constants.MEASUREMENT_FIELD_IDENTIFIER, identifier); - } else { - var measurement = new AdditionalMeasurement(); - measurement.setName(Constants.MEASUREMENT_FIELD_IDENTIFIER); - measurement.setHashMap(Collections.singletonMap(Constants.MEASUREMENT_FIELD_VALUE, identifier)); - additionalMeasurements.add(measurement); - } - } - -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesDataProvider.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanVesDataProvider.java deleted file mode 100644 index 931b258..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesDataProvider.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import java.io.IOException; -import java.net.URL; - -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.util.JsonUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.stereotype.Service; - -import lombok.Setter; - -@Service -public class RanVesDataProvider { - - private static final String PM_VES_LOCATION = "classpath:pmVes.json"; - private static final String PM_FAILURE_VES_LOCATION = "classpath:failurePmVes.json"; - - @Setter - private VesEvent pmVesEvent; - @Setter - private VesEvent failurePmVesEvent; - @Setter - private Integer interval; - @Setter - private String reportingMethod; - - private final Integer defaultInterval; - private final String defaultReportingMethod; - private final ResourceLoader resourceLoader; - - public RanVesDataProvider(@Value("${ves.defaultInterval}") Integer defaultInterval, - @Value("${ves.defaultReportingMethod}") String defaultReportingMethod, - ResourceLoader resourceLoader) { - this.defaultInterval = defaultInterval; - this.defaultReportingMethod = defaultReportingMethod; - this.resourceLoader = resourceLoader; - } - - @Cacheable("pmVes") - public VesEvent loadPmVesEvent() { - URL resourceUrl = getResourceURL(resourceLoader.getResource(PM_VES_LOCATION)); - return JsonUtils.INSTANCE.deserializeFromFileUrl(resourceUrl, VesEvent.class); - } - - @Cacheable("failurePmVes") - public VesEvent loadFailurePmVesEvent() { - URL resourceUrl = getResourceURL(resourceLoader.getResource(PM_FAILURE_VES_LOCATION)); - return JsonUtils.INSTANCE.deserializeFromFileUrl(resourceUrl, VesEvent.class); - } - - public Integer getRegularVesInterval() { - if (interval == null) { - return defaultInterval; - } - return interval; - } - - public String getReportingMethod() { - if (reportingMethod == null) { - return defaultReportingMethod; - } - - return reportingMethod; - } - - public Integer getFailureVesInterval() { - return defaultInterval; - } - - public VesEvent getPmVesEvent() { - if (pmVesEvent == null) { - return loadPmVesEvent(); - } - return pmVesEvent; - } - - public VesEvent getFailurePmVesEvent() { - if (failurePmVesEvent == null) { - return loadFailurePmVesEvent(); - } - return failurePmVesEvent; - } - - private URL getResourceURL(Resource resource) { - try { - return resource.getURL(); - } catch (IOException e) { - throw new RuntimeException("Cannot get resource URL for: " + resource.getFilename()); - } - } -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesHolder.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanVesHolder.java deleted file mode 100644 index 92d30e4..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesHolder.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; - -import java.text.MessageFormat; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.function.BiFunction; - -import org.onap.a1pesimulator.data.ReportingMethodEnum; -import org.onap.a1pesimulator.data.RequestParameters; -import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; -import org.onap.a1pesimulator.data.fileready.RanPeriodicSendReport; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.service.common.AbstractRanRunnable; -import org.onap.a1pesimulator.service.common.EventCustomizer; -import org.onap.a1pesimulator.service.fileready.RanFileReadyHolder; -import org.onap.a1pesimulator.service.fileready.RanSaveFileReadyRunnable; -import org.onap.a1pesimulator.service.fileready.RanSendReportsRunnable; -import org.onap.a1pesimulator.service.ves.RanEventCustomizerFactory.Mode; -import org.onap.a1pesimulator.util.VnfConfigReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.stereotype.Service; - -import lombok.Getter; - -@Service -public class RanVesHolder { - - private static final Logger log = LoggerFactory.getLogger(RanVesHolder.class); - private final Map periodicEventsCache = new ConcurrentHashMap<>(); - - private final RanVesDataProvider vesDataProvider; - private final RanEventCustomizerFactory eventCustomizerFactory; - private final ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler; - private final Collection onEventActions; - private final RanFileReadyHolder ranFileReadyHolder; - private final RanVesSender vesSender; - private final VnfConfigReader vnfConfigReader; - private ThreadSendReportFunction threadSendReportFunction; - - public RanVesHolder(ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler, RanFileReadyHolder ranFileReadyHolder, RanVesSender vesSender, - VnfConfigReader vnfConfigReader, - RanEventCustomizerFactory eventCustomizerFactory, RanVesDataProvider vesDataProvider, - Collection onEventActions) { - this.vesPmThreadPoolTaskScheduler = vesPmThreadPoolTaskScheduler; - this.ranFileReadyHolder = ranFileReadyHolder; - this.vesSender = vesSender; - this.vnfConfigReader = vnfConfigReader; - this.eventCustomizerFactory = eventCustomizerFactory; - this.vesDataProvider = vesDataProvider; - this.onEventActions = onEventActions; - } - - /** - * Thread for periodical sending of PM Bulk Files and fileReady Events - */ - private void startSendingReports() { - if (isNull(threadSendReportFunction) || !threadSendReportFunction.isProcessRunning()) { - int repPeriod = vnfConfigReader.getVnfConfig().getRepPeriod(); - threadSendReportFunction = new ThreadSendReportFunction(vesPmThreadPoolTaskScheduler, repPeriod, ranFileReadyHolder); - threadSendReportFunction.startEvent(); - log.info("Start sending reports every {} seconds", repPeriod); - } - } - - /** - * Stops sending the report after the last cell was stopped. It send the last report before stop completely - */ - private void stopSendingReports(String cellId) { - sendLastReport(cellId); - if (nonNull(threadSendReportFunction) && !isAnyEventRunning()) { - threadSendReportFunction.getRanPeriodicVesEvent().getScheduledFuture().cancel(false); - log.info("Stop sending reports every {} seconds", vnfConfigReader.getVnfConfig().getRepPeriod()); - } - } - - /** - * Sends the last report after specific cell was stopped - */ - private void sendLastReport(String cellId) { - if (nonNull(threadSendReportFunction)) { - log.trace("Send last report after stop for cell: {}", cellId); - ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessageForCellId(cellId); - } - } - - Map getPeriodicEventsCache() { - return periodicEventsCache; - } - - ResponseEntity startSendingVesEvents(String identifier, VesEvent vesEvent, Integer interval, ReportingMethodEnum reportingMethod) { - - periodicEventsCache.compute(identifier, - new ThreadCacheUpdateFunction(vesPmThreadPoolTaskScheduler, eventCustomizerFactory.getEventCustomizer(vesEvent, Mode.REGULAR), onEventActions, - ranFileReadyHolder, vesSender, RequestParameters.builder() - .vesEvent(vesEvent).identifier(identifier).reportingMethod(reportingMethod).interval(interval).build())); - if (ReportingMethodEnum.FILE_READY.equals(reportingMethod)) { - startSendingReports(); - } - return ResponseEntity.accepted().body("VES Event sending started"); - } - - ResponseEntity startSendingFailureVesEvents(String identifier, VesEvent vesEvent, ReportingMethodEnum reportingMethod) { - - periodicEventsCache.compute(identifier, - new ThreadCacheUpdateFunction(vesPmThreadPoolTaskScheduler, eventCustomizerFactory.getEventCustomizer(vesEvent, Mode.FAILURE), onEventActions, - ranFileReadyHolder, - vesSender, RequestParameters.builder().vesEvent(vesEvent).identifier(identifier).interval(vesDataProvider.getFailureVesInterval()) - .reportingMethod(reportingMethod).build())); - if (ReportingMethodEnum.FILE_READY.equals(reportingMethod)) { - startSendingReports(); - } - return ResponseEntity.accepted().body("Failure VES Event sending started"); - } - - Optional stopSendingVesEvents(String identifier) { - RanPeriodicEvent periodicEvent = periodicEventsCache.remove(identifier); - if (periodicEvent == null) { - return Optional.empty(); - } - periodicEvent.getScheduledFuture().cancel(false); - stopSendingReports(identifier); - return Optional.of(periodicEvent); - } - - Collection getEnabledEventElementIdentifiers() { - return periodicEventsCache.keySet(); - } - - public boolean isEventEnabled(String identifier) { - return periodicEventsCache.containsKey(identifier); - } - - public boolean isAnyEventRunning() { - return !periodicEventsCache.isEmpty(); - } - - RanPeriodicEvent getPeriodicEventForCell(String identifier) { - if (!periodicEventsCache.containsKey(identifier)) { - throw new IllegalArgumentException( - MessageFormat.format("Cannot find event for given source {0}", identifier)); - } - return periodicEventsCache.get(identifier); - } - - private static class ThreadCacheUpdateFunction - implements BiFunction { - - private final Integer interval; - private final ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler; - private final VesEvent vesEvent; - private final EventCustomizer eventCustomizer; - private final Collection onEventActions; - private final RanFileReadyHolder fileReadyHolder; - private final RanVesSender vesSender; - private final String cellId; - private final ReportingMethodEnum reportingMethod; - - public ThreadCacheUpdateFunction(ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler, EventCustomizer eventCustomizer, - Collection onEventActions, - RanFileReadyHolder fileReadyHolder, RanVesSender vesSender, RequestParameters requestParameters) { - this.vesPmThreadPoolTaskScheduler = vesPmThreadPoolTaskScheduler; - this.vesEvent = requestParameters.getVesEvent(); - this.interval = requestParameters.getInterval(); - this.eventCustomizer = eventCustomizer; - this.onEventActions = onEventActions; - this.fileReadyHolder = fileReadyHolder; - this.vesSender = vesSender; - this.cellId = requestParameters.getIdentifier(); - this.reportingMethod = requestParameters.getReportingMethod(); - } - - @Override - public RanPeriodicEvent apply(String key, RanPeriodicEvent value) { - if (value != null) { - // if thread is registered then cancel it and schedule a new one - value.getScheduledFuture().cancel(false); - } - AbstractRanRunnable ranRunnable = (ReportingMethodEnum.FILE_READY.equals(reportingMethod)) ? - new RanSaveFileReadyRunnable(fileReadyHolder, cellId, vesEvent, eventCustomizer, interval, onEventActions) : - new RanSendVesRunnable(vesSender, vesEvent, eventCustomizer, onEventActions); - - ScheduledFuture scheduledFuture = - vesPmThreadPoolTaskScheduler.scheduleAtFixedRate(ranRunnable, interval * 1000L); - return RanPeriodicEvent.builder().event(vesEvent).interval(interval).reportingMethod(reportingMethod.getValue()).scheduledFuture(scheduledFuture) - .ranRunnable(ranRunnable).build(); - } - - } - - @Getter - private static class ThreadSendReportFunction { - - protected final Integer interval; - protected final ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler; - protected RanPeriodicSendReport ranPeriodicVesEvent; - protected ScheduledFuture scheduledFuture; - protected final RanFileReadyHolder ranFileReadyHolder; - - public ThreadSendReportFunction(ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler, Integer interval, RanFileReadyHolder ranFileReadyHolder) { - this.vesPmThreadPoolTaskScheduler = vesPmThreadPoolTaskScheduler; - this.interval = interval; - this.ranFileReadyHolder = ranFileReadyHolder; - } - - public void startEvent() { - RanSendReportsRunnable ranSendReportsRunnable = - new RanSendReportsRunnable(ranFileReadyHolder); - scheduledFuture = vesPmThreadPoolTaskScheduler.scheduleAtFixedRate(ranSendReportsRunnable, interval * 1000L); - this.ranPeriodicVesEvent = RanPeriodicSendReport.builder().interval(interval).scheduledFuture(scheduledFuture) - .ranSendReportsRunnable(ranSendReportsRunnable).build(); - } - - public boolean isProcessRunning() { - return (nonNull(scheduledFuture) && !(scheduledFuture.isCancelled() || scheduledFuture.isDone())); - } - } - -} diff --git a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesSender.java b/src/main/java/org/onap/a1pesimulator/service/ves/RanVesSender.java deleted file mode 100644 index 85bccbb..0000000 --- a/src/main/java/org/onap/a1pesimulator/service/ves/RanVesSender.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import static java.util.Objects.nonNull; - -import org.onap.a1pesimulator.data.Event; -import org.onap.a1pesimulator.data.VnfConfig; -import org.onap.a1pesimulator.data.ves.CommonEventHeader; -import org.onap.a1pesimulator.exception.VesBrokerException; -import org.onap.a1pesimulator.util.JsonUtils; -import org.onap.a1pesimulator.util.VnfConfigReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -import reactor.core.publisher.Mono; - -@Service -public class RanVesSender { - - private static final Logger log = LoggerFactory.getLogger(RanVesSender.class); - - private RestTemplate restTemplate; - - private String vesCollectorProtocol; - - private String vesCollectorPath; - - private VnfConfigReader vnfConfigReader; - - public RanVesSender(RestTemplate restTemplate, VnfConfigReader vnfConfigReader, - @Value("${ves.collector.protocol}") String vesCollectorProtocol, - @Value("${ves.collector.endpoint}") String vesCollectorPath) { - this.restTemplate = restTemplate; - this.vnfConfigReader = vnfConfigReader; - this.vesCollectorProtocol = vesCollectorProtocol; - this.vesCollectorPath = vesCollectorPath; - } - - public Mono send(Event event) { - if (nonNull(event)) { - VnfConfig vnfConfig = vnfConfigReader.getVnfConfig(); - String url = getVesCollectorUrl(vnfConfig); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setBasicAuth(vnfConfig.getVesUser(), vnfConfig.getVesPassword()); - - setVnfInfo(event, vnfConfig); - String eventInJson = JsonUtils.INSTANCE.objectToPrettyString(event); - - log.trace("Sending following event: {} ", eventInJson); - - HttpEntity entity = new HttpEntity<>(eventInJson, headers); - ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); - - log.debug("Response received: {}", response); - - if (response.getStatusCode() == HttpStatus.OK || response.getStatusCode() == HttpStatus.ACCEPTED) { - return Mono.just(response.getStatusCode()); - } else { - String errorMsg = - "Failed to send VES event to the collector with response status code:" + response.getStatusCode(); - return Mono.error(new VesBrokerException(errorMsg)); - } - } - return Mono.error(new VesBrokerException("There is no event to send to the collector.")); - } - - private String getVesCollectorUrl(VnfConfig vnfConfig) { - return vesCollectorProtocol + "://" + vnfConfig.getVesHost() + ":" + vnfConfig.getVesPort() + vesCollectorPath; - } - - private void setVnfInfo(Event vesEvent, VnfConfig vnfConfig) { - CommonEventHeader header = vesEvent.getCommonEventHeader(); - header.setSourceId(vnfConfig.getVnfId()); - header.setSourceName(vnfConfig.getVnfName()); - vesEvent.setCommonEventHeader(header); - } - -} diff --git a/src/test/java/org/onap/a1pesimulator/service/VesBrokerServiceImplTest.java b/src/test/java/org/onap/a1pesimulator/service/VesBrokerServiceImplTest.java index 2c2d9ff..1df8820 100644 --- a/src/test/java/org/onap/a1pesimulator/service/VesBrokerServiceImplTest.java +++ b/src/test/java/org/onap/a1pesimulator/service/VesBrokerServiceImplTest.java @@ -29,8 +29,8 @@ import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.onap.a1pesimulator.data.ReportingMethodEnum; import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.service.ves.RanVesBrokerService; -import org.onap.a1pesimulator.service.ves.RanVesSender; +import org.onap.a1pesimulator.service.report.RanReportsBrokerService; +import org.onap.a1pesimulator.service.report.RanVesSender; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpEntity; @@ -50,7 +50,7 @@ public class VesBrokerServiceImplTest { private static final String VES_COLLECTOR_URL = "someProtocol://someVesCollectorIP:someVesCollectorPort/somePath"; @Autowired - private RanVesBrokerService vesBrokerService; + private RanReportsBrokerService vesBrokerService; @Autowired private RanVesSender vesSender; @Autowired @@ -70,7 +70,7 @@ public class VesBrokerServiceImplTest { when(restTemplate.exchange(ArgumentMatchers.eq(VES_COLLECTOR_URL), ArgumentMatchers.eq(HttpMethod.POST), ArgumentMatchers.any(HttpEntity.class), ArgumentMatchers.eq(String.class))).thenReturn(responseEntity); - ResponseEntity response = vesBrokerService.startSendingVesEvents("CustomIdentifier", + ResponseEntity response = vesBrokerService.startSendingReports("CustomIdentifier", loadEventFromFile("VesBrokerControllerTest_pm_ves.json"), 10, ReportingMethodEnum.VES); Assert.assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); diff --git a/src/test/java/org/onap/a1pesimulator/service/cell/RanCellStateServiceTest.java b/src/test/java/org/onap/a1pesimulator/service/cell/RanCellStateServiceTest.java index 3aefcb7..ee68836 100644 --- a/src/test/java/org/onap/a1pesimulator/service/cell/RanCellStateServiceTest.java +++ b/src/test/java/org/onap/a1pesimulator/service/cell/RanCellStateServiceTest.java @@ -19,7 +19,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.onap.a1pesimulator.service.fileready.CommonFileReady.TEST_CELL_ID; +import static org.onap.a1pesimulator.service.pm.CommonFileReady.TEST_CELL_ID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/org/onap/a1pesimulator/service/fileready/CommonFileReady.java b/src/test/java/org/onap/a1pesimulator/service/fileready/CommonFileReady.java deleted file mode 100644 index 9727777..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/fileready/CommonFileReady.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.onap.a1pesimulator.TestHelpers.deleteTempFiles; -import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; -import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.service.VesBrokerServiceImplTest; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; - -public class CommonFileReady { - - public List filesToDelete; //we collect files created during testing and then delete them - public static final String PM_BULK_FILE = "pmBulkFile.xml"; - public static final String ARCHIVED_PM_BULK_FILE = "pmBulkFile.xml.gz"; - public static final String TEST_CELL_ID = "Cell1"; - public static final Integer NO_OF_EVENTS = 3; - public static final Integer NO_OF_CELLS = 2; - - @InjectMocks - private ObjectMapper mapper; - - - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); - filesToDelete = Collections.synchronizedList(new ArrayList<>()); - } - - @AfterEach - void cleanUpFiles() { - deleteTempFiles(filesToDelete); - } - - /** - * Create temp file with simple text and adds it to filesToDelete list - * - * @param fileName name of file - * @return created file - */ - public File createTempFile(String fileName) { - try { - File tmpFile = new File(TEMP_DIR, fileName); - tmpFile.createNewFile(); - Files.write(tmpFile.toPath(), "sample text".getBytes()); - filesToDelete.add(tmpFile); - return tmpFile; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - /** - * Generate NO_OF_EVENTS test EventMemoryHolder list - * - * @return EventMemoryHolder list - */ - protected List getTestEvents() { - List collectedEvents = new ArrayList<>(); - for (int i = 0; i < NO_OF_EVENTS; i++) { - EventMemoryHolder eventMemoryHolder = new EventMemoryHolder(TEST_CELL_ID, UUID.randomUUID().toString(), 10, ZonedDateTime.now(), - loadEventFromFile()); - collectedEvents.add(eventMemoryHolder); - } - return collectedEvents; - } - - /** - * Generate events by CellId - * - * @return Map by CellId and list of events - */ - protected Map> getTestEventsByCells(List eventList) { - Map> collectedEventsByCell = new HashMap<>(); - for (int cellId = 0; cellId < NO_OF_CELLS; cellId++) { - collectedEventsByCell.put("Cell" + cellId, eventList); - } - return collectedEventsByCell; - } - - /** - * Converts json to VESEvent object - * - * @return created VESEvent - */ - protected VesEvent loadEventFromFile() { - try { - return mapper.readValue(loadFileContent("VesBrokerControllerTest_pm_ves.json"), VesEvent.class); - } catch (JsonProcessingException e) { - e.printStackTrace(); - return null; - } - } - - /** - * Get json string from specified json file - * - * @param fileName name of test json file - * @return json file as string - */ - private String loadFileContent(String fileName) { - Path path; - try { - path = Paths.get(VesBrokerServiceImplTest.class.getResource(fileName).toURI()); - return new String(Files.readAllBytes(path)); - } catch (URISyntaxException | IOException e) { - e.printStackTrace(); - return null; - } - } - - /** - * Create common log - * - * @return ListAppender - */ - protected ListAppender createCommonLog(Class clazz) { - Logger testLog = (Logger) LoggerFactory.getLogger(clazz); - ListAppender appender = new ListAppender<>(); - appender.start(); - testLog.addAppender(appender); - return appender; - } -} diff --git a/src/test/java/org/onap/a1pesimulator/service/fileready/FileReadyEventServiceTest.java b/src/test/java/org/onap/a1pesimulator/service/fileready/FileReadyEventServiceTest.java deleted file mode 100644 index 21794a2..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/fileready/FileReadyEventServiceTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.nio.file.InvalidPathException; -import java.time.ZonedDateTime; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.onap.a1pesimulator.data.fileready.FileData; - -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -class FileReadyEventServiceTest extends CommonFileReady { - - @Mock - private FtpServerService ftpServerService; - - @InjectMocks - private FileReadyEventService fileReadyEventService; - - @BeforeEach - void setUp() { - super.setUp(); - when(ftpServerService.getFtpPath()).thenReturn(""); - } - - @Test - void createFileReadyEventAndDeleteTmpFile() { - FileData testData = getTestFileData(); - Mono fileMono = Mono.just(testData); - FileData expectedFileData = fileReadyEventService.createFileReadyEvent(testData); - StepVerifier.create(fileReadyEventService.createFileReadyEventAndDeleteTmpFile(fileMono)) - .expectNext(expectedFileData) - .verifyComplete(); - Mono resultFileData = fileReadyEventService.createFileReadyEventAndDeleteTmpFile(fileMono); - assertFileDataResults(resultFileData.block()); - verify(ftpServerService, times(3)).getFtpPath(); - } - - @Test - void createFileReadyEvent() { - FileData resultFileData = fileReadyEventService.createFileReadyEvent(getTestFileData()); - assertFileDataResults(resultFileData); - verify(ftpServerService, times(1)).getFtpPath(); - } - - /** - * Common asserst for all tests here - */ - private void assertFileDataResults(FileData fileData) { - assertNotNull(fileData); - assertNotNull(fileData.getFileReadyEvent()); - assertEquals(ARCHIVED_PM_BULK_FILE, fileData.getFileReadyEvent().getNotificationFields().getArrayOfNamedHashMap().get(0).getHashMap().get("location")); - } - - /** - * Creates FileData object for test cases - * - * @return test FileData object - */ - private FileData getTestFileData() { - try { - return FileData.builder().pmBulkFile(createTempFile(PM_BULK_FILE)).startEventDate(ZonedDateTime.now()) - .endEventDate(ZonedDateTime.now().plusMinutes(5)).archivedPmBulkFile(createTempFile(ARCHIVED_PM_BULK_FILE)).build(); - } catch (InvalidPathException e) { - e.printStackTrace(); - } - return null; - } -} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/fileready/FtpServerServiceTest.java b/src/test/java/org/onap/a1pesimulator/service/fileready/FtpServerServiceTest.java deleted file mode 100644 index 48515a8..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/fileready/FtpServerServiceTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.onap.a1pesimulator.service.fileready.FtpServerService.deletePMBulkFile; -import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.onap.a1pesimulator.data.fileready.FileData; -import org.onap.a1pesimulator.util.VnfConfigReader; -import org.springframework.test.util.ReflectionTestUtils; - -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import net.schmizz.sshj.SSHClient; -import net.schmizz.sshj.sftp.SFTPClient; -import reactor.test.StepVerifier; - - -class FtpServerServiceTest extends CommonFileReady { - - private FtpServerService ftpServerService; - - @Mock - SSHClient sshClient; - - @Mock - SFTPClient sftpClient; - - @InjectMocks - VnfConfigReader vnfConfigReader; - - @BeforeEach - void setUp() { - super.setUp(); - ReflectionTestUtils.setField(vnfConfigReader, "vnfConfigFile", "src/test/resources/vnf.config"); - ftpServerService = spy(new FtpServerService(vnfConfigReader)); - } - - /** - * Test to save archived PM Bulk File into specify directory - */ - @Test - void saveFileToFtp() { - ReflectionTestUtils.setField(ftpServerService, "xmlPmLocation", TEMP_DIR); - File archivedPmBulkFile = createTempFile(ARCHIVED_PM_BULK_FILE); - FileData testFileData = getTestFileData(); - FileData expectedFileData = FileData.builder().archivedPmBulkFile(archivedPmBulkFile).pmBulkFile(testFileData.getPmBulkFile()).build(); - expectedFileData.setArchivedPmBulkFile(archivedPmBulkFile); - - StepVerifier.create(ftpServerService.uploadFileToFtp(testFileData)) - .expectNext(expectedFileData) - .verifyComplete(); - } - - /** - * Test successful FTP upload - */ - @Test - void uploadFileToFtp() { - ReflectionTestUtils.setField(ftpServerService, "ftpServerUpload", true); - doReturn(sshClient).when(ftpServerService).getSSHClient(); - try { - doReturn(sftpClient).when(sshClient).newSFTPClient(); - doNothing().when(sftpClient).put(anyString(), anyString()); - } catch (IOException e) { - e.printStackTrace(); - } - - File archivedPmBulkFile = createTempFile(ARCHIVED_PM_BULK_FILE); - FileData testFileData = getTestFileData(); - FileData expectedFileData = FileData.builder().archivedPmBulkFile(archivedPmBulkFile).pmBulkFile(testFileData.getPmBulkFile()).build(); - expectedFileData.setArchivedPmBulkFile(archivedPmBulkFile); - - StepVerifier.create(ftpServerService.uploadFileToFtp(testFileData)) - .expectNext(expectedFileData).verifyComplete(); - } - - /** - * Test error while trying to upload archived PM Bulk File - */ - @Test - void errorWhileUploadingFileToFtp() { - ReflectionTestUtils.setField(ftpServerService, "ftpServerUpload", true); - FileData testFileData = getTestFileData(); - StepVerifier.create(ftpServerService.uploadFileToFtp(testFileData)) - .verifyComplete(); - verify(ftpServerService, times(1)).resumeError(any(), any()); - } - - /** - * Test error while trying to delete not existing file - */ - @Test - void errorWhileDeletingFile() { - ListAppender appender = createCommonLog(FtpServerService.class); - - deletePMBulkFile(new File("test.txt")); - assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage).containsExactly("Could not delete file: test.txt"); - } - - /** - * Test if path to FTP is created correctly - */ - @Test - void getFtpPath() { - List ftpPathVars = new ArrayList<>(); - ftpPathVars.add("ftpServerProtocol"); - ftpPathVars.add("ftpServerUsername"); - ftpPathVars.add("ftpServerPassword"); - ftpPathVars.add("ftpServerFilepath"); - - ftpPathVars.forEach(var -> ReflectionTestUtils.setField(ftpServerService, var, var)); - String ftpPath = ftpServerService.getFtpPath(); - - assertTrue(ftpPathVars.stream().allMatch(ftpPath::contains)); - } - - /** - * Creates FileData object for test cases - * - * @return test FileData object - */ - private FileData getTestFileData() { - return FileData.builder().pmBulkFile(createTempFile(PM_BULK_FILE)).build(); - } - -} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/fileready/PMBulkFileServiceTest.java b/src/test/java/org/onap/a1pesimulator/service/fileready/PMBulkFileServiceTest.java deleted file mode 100644 index 8133266..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/fileready/PMBulkFileServiceTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.onap.a1pesimulator.data.fileready.FileData; -import org.onap.a1pesimulator.util.VnfConfigReader; -import org.springframework.test.util.ReflectionTestUtils; - -import reactor.core.publisher.Mono; - -class PMBulkFileServiceTest extends CommonFileReady { - - private PMBulkFileService pmBulkFileService; - - @InjectMocks - VnfConfigReader vnfConfigReader; - - - @BeforeEach - void setUp() { - super.setUp(); - ReflectionTestUtils.setField(vnfConfigReader, "vnfConfigFile", "src/test/resources/vnf.config"); - pmBulkFileService = new PMBulkFileService(vnfConfigReader); - } - - @Test - void generatePMBulkFileXml() { - Mono monoFileData = pmBulkFileService.generatePMBulkFileXml(getTestEvents()); - FileData fileData = monoFileData.block(); - assertNotNull(fileData); - assertNotNull(fileData.getPmBulkFile()); - } - - -} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolderTest.java b/src/test/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolderTest.java deleted file mode 100644 index d6fa574..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/fileready/RanFileReadyHolderTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.spy; - -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.apache.http.HttpStatus; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; -import org.onap.a1pesimulator.data.fileready.FileData; -import org.onap.a1pesimulator.data.fileready.FileReadyEvent; -import org.onap.a1pesimulator.exception.VesBrokerException; -import org.onap.a1pesimulator.service.ves.RanVesSender; - -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import reactor.core.publisher.Mono; - -class RanFileReadyHolderTest extends CommonFileReady { - - private RanFileReadyHolder ranFileReadyHolder; - - @Mock - PMBulkFileService pmBulkFileService; - - @Mock - RanVesSender ranVesSender; - - @Mock - FtpServerService ftpServerService; - - @Mock - FileReadyEventService fileReadyEventService; - - @BeforeEach - void setUp() { - super.setUp(); - ranFileReadyHolder = spy(new RanFileReadyHolder(ranVesSender, ftpServerService, pmBulkFileService, fileReadyEventService)); - } - - @Test - void createPMBulkFileAndSendFileReadyMessage() { - ListAppender appender = createCommonLogAndMock(); - - ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessage(); - assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage) - .contains("PM Bulk file was generated, uploaded to FTP and File ready event was send to VES Collector"); - } - - @Test - void createPMBulkFileAndSendFileReadyMessageForOneCell() { - ListAppender appender = createCommonLogAndMock(); - - ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessageForCellId(TEST_CELL_ID); - assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage) - .contains("PM Bulk file was generated, uploaded to FTP and File ready event was send to VES Collector"); - } - - @Test - void errorCreatePMBulkFileAndSendFileReadyMessage() { - ListAppender appender = createCommonLogAndMock(); - doReturn(Mono.error(new Exception("error"))).when(fileReadyEventService).createFileReadyEventAndDeleteTmpFile(any()); - - ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessage(); - assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage).contains("File ready event was unsuccessful: error"); - } - - @Test - void saveEventToMemory() { - ranFileReadyHolder = spy(new RanFileReadyHolder(ranVesSender, ftpServerService, pmBulkFileService, fileReadyEventService)); - try { - ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30); - ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30); - } catch (VesBrokerException e) { - e.printStackTrace(); - } - assertThat(ranFileReadyHolder.getCollectedEventsByCell().get(TEST_CELL_ID)).hasSize(2); - } - - @Test - void errorSaveEventToMemory() throws VesBrokerException { - doThrow(new VesBrokerException("error")).when(ranFileReadyHolder).saveEventToMemory(any(), any(), any(), any()); - - Throwable exception = assertThrows(VesBrokerException.class, - () -> ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30)); - assertThat(exception.getMessage()).contains("error"); - assertThat(ranFileReadyHolder.getCollectedEventsByCell()).isEmpty(); - } - - @Test - void getCollectedEventsByCell() { - Map> collectedEvents = ranFileReadyHolder.getCollectedEventsByCell(); - assertNotNull(collectedEvents); - } - - @Test - void getCollectedEvents() { - List collectedEvents = ranFileReadyHolder.getCollectedEventsForCellId(TEST_CELL_ID); - assertNotNull(collectedEvents); - try { - ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30); - collectedEvents = ranFileReadyHolder.getCollectedEventsForCellId(TEST_CELL_ID); - assertNotNull(collectedEvents); - } catch (VesBrokerException e) { - e.printStackTrace(); - } - } - - /** - * Creates common Log and Mocks - * - * @return ListAppender - */ - private ListAppender createCommonLogAndMock() { - ListAppender appender = createCommonLog(RanFileReadyHolder.class); - - List collectedEvents = getTestEvents(); - Map> collectedEventsByCell = getTestEventsByCells(collectedEvents); - FileData testFileData = FileData.builder().pmBulkFile(createTempFile(PM_BULK_FILE)).build(); - - doReturn(collectedEventsByCell).when(ranFileReadyHolder).getCollectedEventsByCell(); - doReturn(collectedEvents).when(ranFileReadyHolder).getCollectedEventsForCellId(any()); - doReturn(Mono.just(testFileData)).when(pmBulkFileService).generatePMBulkFileXml(collectedEvents); - testFileData.setArchivedPmBulkFile(createTempFile(ARCHIVED_PM_BULK_FILE)); - doReturn(Mono.just(testFileData)).when(ftpServerService).uploadFileToFtp(any()); - testFileData.setFileReadyEvent(new FileReadyEvent()); - doReturn(Mono.just(testFileData)).when(fileReadyEventService).createFileReadyEventAndDeleteTmpFile(any()); - doReturn(Mono.just(HttpStatus.SC_ACCEPTED)).when(ranVesSender).send(any()); - return appender; - } -} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnableTest.java b/src/test/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnableTest.java deleted file mode 100644 index 9b94107..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/fileready/RanSaveFileReadyRunnableTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.Collections; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.exception.VesBrokerException; -import org.onap.a1pesimulator.service.ue.RanUeHolder; -import org.onap.a1pesimulator.service.ves.RanCellEventCustomizer; -import org.onap.a1pesimulator.service.ves.RanEventCustomizerFactory; -import org.onap.a1pesimulator.service.ves.RanEventCustomizerFactory.Mode; - -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; - -class RanSaveFileReadyRunnableTest extends CommonFileReady { - - private RanSaveFileReadyRunnable ranSaveFileReadyRunnable; - - @Mock - RanFileReadyHolder ranFileReadyHolder; - - @Mock - RanEventCustomizerFactory ranEventCustomizerFactory; - - @Mock - RanUeHolder ranUeHolder; - - @BeforeEach - void setUp() { - super.setUp(); - doReturn(new RanCellEventCustomizer(ranUeHolder)).when(ranEventCustomizerFactory).getEventCustomizer(any(), any()); - ranSaveFileReadyRunnable = spy( - new RanSaveFileReadyRunnable(ranFileReadyHolder, TEST_CELL_ID, loadEventFromFile(), ranEventCustomizerFactory.getEventCustomizer(new VesEvent(), - Mode.REGULAR), 60, Collections.emptyList())); - } - - @Test - void successfulRun() throws VesBrokerException { - ranSaveFileReadyRunnable.run(); - verify(ranFileReadyHolder, times(1)).saveEventToMemory(any(), any(), any(), any()); - } - - @Test - void errorRun() throws VesBrokerException { - ListAppender appender = createCommonLog(RanSaveFileReadyRunnable.class); - doThrow(new VesBrokerException("error")).when(ranFileReadyHolder).saveEventToMemory(any(), any(), any(), any()); - ranSaveFileReadyRunnable.run(); - assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage).containsExactly("Saving file ready event failed: error"); - } -} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnableTest.java b/src/test/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnableTest.java deleted file mode 100644 index d2e8da8..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/fileready/RanSendReportsRunnableTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.fileready; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.onap.a1pesimulator.service.ue.RanUeHolder; -import org.onap.a1pesimulator.service.ves.RanCellEventCustomizer; -import org.onap.a1pesimulator.service.ves.RanEventCustomizerFactory; - -class RanSendReportsRunnableTest extends CommonFileReady { - - private RanSendReportsRunnable ranSendReportsRunnable; - - @Mock - RanFileReadyHolder ranFileReadyHolder; - - @Mock - RanEventCustomizerFactory ranEventCustomizerFactory; - - @Mock - RanUeHolder ranUeHolder; - - @BeforeEach - void setUp() { - super.setUp(); - doReturn(new RanCellEventCustomizer(ranUeHolder)).when(ranEventCustomizerFactory).getEventCustomizer(any(), any()); - ranSendReportsRunnable = spy( - new RanSendReportsRunnable(ranFileReadyHolder)); - } - - @Test - void successfulRun() { - ranSendReportsRunnable.run(); - verify(ranFileReadyHolder, times(1)).createPMBulkFileAndSendFileReadyMessage(); - } -} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/pm/CommonFileReady.java b/src/test/java/org/onap/a1pesimulator/service/pm/CommonFileReady.java new file mode 100644 index 0000000..aae5e53 --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/pm/CommonFileReady.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.onap.a1pesimulator.TestHelpers.deleteTempFiles; +import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.service.VesBrokerServiceImplTest; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; + +public class CommonFileReady { + + public List filesToDelete; //we collect files created during testing and then delete them + public static final String PM_BULK_FILE = "pmBulkFile.xml"; + public static final String ARCHIVED_PM_BULK_FILE = "pmBulkFile.xml.gz"; + public static final String TEST_CELL_ID = "Cell1"; + public static final Integer NO_OF_EVENTS = 3; + public static final Integer NO_OF_CELLS = 2; + + @InjectMocks + private ObjectMapper mapper; + + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + filesToDelete = Collections.synchronizedList(new ArrayList<>()); + } + + @AfterEach + void cleanUpFiles() { + deleteTempFiles(filesToDelete); + } + + /** + * Create temp file with simple text and adds it to filesToDelete list + * + * @param fileName name of file + * @return created file + */ + public File createTempFile(String fileName) { + try { + File tmpFile = new File(TEMP_DIR, fileName); + tmpFile.createNewFile(); + Files.write(tmpFile.toPath(), "sample text".getBytes()); + filesToDelete.add(tmpFile); + return tmpFile; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Generate NO_OF_EVENTS test EventMemoryHolder list + * + * @return EventMemoryHolder list + */ + protected List getTestEvents() { + List collectedEvents = new ArrayList<>(); + for (int i = 0; i < NO_OF_EVENTS; i++) { + EventMemoryHolder eventMemoryHolder = new EventMemoryHolder(TEST_CELL_ID, UUID.randomUUID().toString(), 10, ZonedDateTime.now(), + loadEventFromFile()); + collectedEvents.add(eventMemoryHolder); + } + return collectedEvents; + } + + /** + * Generate events by CellId + * + * @return Map by CellId and list of events + */ + protected Map> getTestEventsByCells(List eventList) { + Map> collectedEventsByCell = new HashMap<>(); + for (int cellId = 0; cellId < NO_OF_CELLS; cellId++) { + collectedEventsByCell.put("Cell" + cellId, eventList); + } + return collectedEventsByCell; + } + + /** + * Converts json to VESEvent object + * + * @return created VESEvent + */ + protected VesEvent loadEventFromFile() { + try { + return mapper.readValue(loadFileContent("VesBrokerControllerTest_pm_ves.json"), VesEvent.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Get json string from specified json file + * + * @param fileName name of test json file + * @return json file as string + */ + private String loadFileContent(String fileName) { + Path path; + try { + path = Paths.get(VesBrokerServiceImplTest.class.getResource(fileName).toURI()); + return new String(Files.readAllBytes(path)); + } catch (URISyntaxException | IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Create common log + * + * @return ListAppender + */ + protected ListAppender createCommonLog(Class clazz) { + Logger testLog = (Logger) LoggerFactory.getLogger(clazz); + ListAppender appender = new ListAppender<>(); + appender.start(); + testLog.addAppender(appender); + return appender; + } +} diff --git a/src/test/java/org/onap/a1pesimulator/service/pm/FileReadyEventServiceTest.java b/src/test/java/org/onap/a1pesimulator/service/pm/FileReadyEventServiceTest.java new file mode 100644 index 0000000..141d455 --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/pm/FileReadyEventServiceTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.nio.file.InvalidPathException; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.onap.a1pesimulator.data.fileready.FileData; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +class FileReadyEventServiceTest extends CommonFileReady { + + @Mock + private FtpServerService ftpServerService; + + @InjectMocks + private FileReadyEventService fileReadyEventService; + + @BeforeEach + void setUp() { + super.setUp(); + when(ftpServerService.getFtpPath()).thenReturn(""); + } + + @Test + void createFileReadyEventAndDeleteTmpFile() { + FileData testData = getTestFileData(); + Mono fileMono = Mono.just(testData); + FileData expectedFileData = fileReadyEventService.createFileReadyEvent(testData); + StepVerifier.create(fileReadyEventService.createFileReadyEventAndDeleteTmpFile(fileMono)) + .expectNext(expectedFileData) + .verifyComplete(); + Mono resultFileData = fileReadyEventService.createFileReadyEventAndDeleteTmpFile(fileMono); + assertFileDataResults(resultFileData.block()); + verify(ftpServerService, times(3)).getFtpPath(); + } + + @Test + void createFileReadyEvent() { + FileData resultFileData = fileReadyEventService.createFileReadyEvent(getTestFileData()); + assertFileDataResults(resultFileData); + verify(ftpServerService, times(1)).getFtpPath(); + } + + /** + * Common asserst for all tests here + */ + private void assertFileDataResults(FileData fileData) { + assertNotNull(fileData); + assertNotNull(fileData.getFileReadyEvent()); + assertEquals(ARCHIVED_PM_BULK_FILE, fileData.getFileReadyEvent().getNotificationFields().getArrayOfNamedHashMap().get(0).getHashMap().get("location")); + } + + /** + * Creates FileData object for test cases + * + * @return test FileData object + */ + private FileData getTestFileData() { + try { + return FileData.builder().pmBulkFile(createTempFile(PM_BULK_FILE)).startEventDate(ZonedDateTime.now()) + .endEventDate(ZonedDateTime.now().plusMinutes(5)).archivedPmBulkFile(createTempFile(ARCHIVED_PM_BULK_FILE)).build(); + } catch (InvalidPathException e) { + e.printStackTrace(); + } + return null; + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/pm/FtpServerServiceTest.java b/src/test/java/org/onap/a1pesimulator/service/pm/FtpServerServiceTest.java new file mode 100644 index 0000000..4284e33 --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/pm/FtpServerServiceTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.onap.a1pesimulator.service.pm.FtpServerService.deletePMBulkFile; +import static org.onap.a1pesimulator.util.Constants.TEMP_DIR; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.onap.a1pesimulator.data.fileready.FileData; +import org.onap.a1pesimulator.util.VnfConfigReader; +import org.springframework.test.util.ReflectionTestUtils; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; +import net.schmizz.sshj.SSHClient; +import net.schmizz.sshj.sftp.SFTPClient; +import reactor.test.StepVerifier; + + +class FtpServerServiceTest extends CommonFileReady { + + private FtpServerService ftpServerService; + + @Mock + SSHClient sshClient; + + @Mock + SFTPClient sftpClient; + + @InjectMocks + VnfConfigReader vnfConfigReader; + + @BeforeEach + void setUp() { + super.setUp(); + ReflectionTestUtils.setField(vnfConfigReader, "vnfConfigFile", "src/test/resources/vnf.config"); + ftpServerService = spy(new FtpServerService(vnfConfigReader)); + } + + /** + * Test to save archived PM Bulk File into specify directory + */ + @Test + void saveFileToFtp() { + ReflectionTestUtils.setField(ftpServerService, "xmlPmLocation", TEMP_DIR); + File archivedPmBulkFile = createTempFile(ARCHIVED_PM_BULK_FILE); + FileData testFileData = getTestFileData(); + FileData expectedFileData = FileData.builder().archivedPmBulkFile(archivedPmBulkFile).pmBulkFile(testFileData.getPmBulkFile()).build(); + expectedFileData.setArchivedPmBulkFile(archivedPmBulkFile); + + StepVerifier.create(ftpServerService.uploadFileToFtp(testFileData)) + .expectNext(expectedFileData) + .verifyComplete(); + } + + /** + * Test successful FTP upload + */ + @Test + void uploadFileToFtp() { + ReflectionTestUtils.setField(ftpServerService, "ftpServerUpload", true); + doReturn(sshClient).when(ftpServerService).getSSHClient(); + try { + doReturn(sftpClient).when(sshClient).newSFTPClient(); + doNothing().when(sftpClient).put(anyString(), anyString()); + } catch (IOException e) { + e.printStackTrace(); + } + + File archivedPmBulkFile = createTempFile(ARCHIVED_PM_BULK_FILE); + FileData testFileData = getTestFileData(); + FileData expectedFileData = FileData.builder().archivedPmBulkFile(archivedPmBulkFile).pmBulkFile(testFileData.getPmBulkFile()).build(); + expectedFileData.setArchivedPmBulkFile(archivedPmBulkFile); + + StepVerifier.create(ftpServerService.uploadFileToFtp(testFileData)) + .expectNext(expectedFileData).verifyComplete(); + } + + /** + * Test error while trying to upload archived PM Bulk File + */ + @Test + void errorWhileUploadingFileToFtp() { + ReflectionTestUtils.setField(ftpServerService, "ftpServerUpload", true); + FileData testFileData = getTestFileData(); + StepVerifier.create(ftpServerService.uploadFileToFtp(testFileData)) + .verifyComplete(); + verify(ftpServerService, times(1)).resumeError(any(), any()); + } + + /** + * Test error while trying to delete not existing file + */ + @Test + void errorWhileDeletingFile() { + ListAppender appender = createCommonLog(FtpServerService.class); + + deletePMBulkFile(new File("test.txt")); + assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage).containsExactly("Could not delete file: test.txt"); + } + + /** + * Test if path to FTP is created correctly + */ + @Test + void getFtpPath() { + List ftpPathVars = new ArrayList<>(); + ftpPathVars.add("ftpServerProtocol"); + ftpPathVars.add("ftpServerUsername"); + ftpPathVars.add("ftpServerPassword"); + ftpPathVars.add("ftpServerFilepath"); + + ftpPathVars.forEach(var -> ReflectionTestUtils.setField(ftpServerService, var, var)); + String ftpPath = ftpServerService.getFtpPath(); + + assertTrue(ftpPathVars.stream().allMatch(ftpPath::contains)); + } + + /** + * Creates FileData object for test cases + * + * @return test FileData object + */ + private FileData getTestFileData() { + return FileData.builder().pmBulkFile(createTempFile(PM_BULK_FILE)).build(); + } + +} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/pm/PMBulkFileServiceTest.java b/src/test/java/org/onap/a1pesimulator/service/pm/PMBulkFileServiceTest.java new file mode 100644 index 0000000..ea9326e --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/pm/PMBulkFileServiceTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.onap.a1pesimulator.data.fileready.FileData; +import org.onap.a1pesimulator.util.VnfConfigReader; +import org.springframework.test.util.ReflectionTestUtils; + +import reactor.core.publisher.Mono; + +class PMBulkFileServiceTest extends CommonFileReady { + + private PMBulkFileService pmBulkFileService; + + @InjectMocks + VnfConfigReader vnfConfigReader; + + + @BeforeEach + void setUp() { + super.setUp(); + ReflectionTestUtils.setField(vnfConfigReader, "vnfConfigFile", "src/test/resources/vnf.config"); + pmBulkFileService = new PMBulkFileService(vnfConfigReader); + } + + @Test + void generatePMBulkFileXml() { + Mono monoFileData = pmBulkFileService.generatePMBulkFileXml(getTestEvents()); + FileData fileData = monoFileData.block(); + assertNotNull(fileData); + assertNotNull(fileData.getPmBulkFile()); + } + + +} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolderTest.java b/src/test/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolderTest.java new file mode 100644 index 0000000..dd82065 --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/pm/RanFileReadyHolderTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.spy; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.onap.a1pesimulator.data.fileready.EventMemoryHolder; +import org.onap.a1pesimulator.data.fileready.FileData; +import org.onap.a1pesimulator.data.fileready.FileReadyEvent; +import org.onap.a1pesimulator.exception.VesBrokerException; +import org.onap.a1pesimulator.service.report.RanVesSender; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; +import reactor.core.publisher.Mono; + +class RanFileReadyHolderTest extends CommonFileReady { + + private RanFileReadyHolder ranFileReadyHolder; + + @Mock + PMBulkFileService pmBulkFileService; + + @Mock + RanVesSender ranVesSender; + + @Mock + FtpServerService ftpServerService; + + @Mock + FileReadyEventService fileReadyEventService; + + @BeforeEach + void setUp() { + super.setUp(); + ranFileReadyHolder = spy(new RanFileReadyHolder(ranVesSender, ftpServerService, pmBulkFileService, fileReadyEventService)); + } + + @Test + void createPMBulkFileAndSendFileReadyMessage() { + ListAppender appender = createCommonLogAndMock(); + + ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessage(); + assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage) + .contains("PM Bulk file was generated, uploaded to FTP and File ready event was send to VES Collector"); + } + + @Test + void createPMBulkFileAndSendFileReadyMessageForOneCell() { + ListAppender appender = createCommonLogAndMock(); + + ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessageForCellId(TEST_CELL_ID); + assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage) + .contains("PM Bulk file was generated, uploaded to FTP and File ready event was send to VES Collector"); + } + + @Test + void errorCreatePMBulkFileAndSendFileReadyMessage() { + ListAppender appender = createCommonLogAndMock(); + doReturn(Mono.error(new Exception("error"))).when(fileReadyEventService).createFileReadyEventAndDeleteTmpFile(any()); + + ranFileReadyHolder.createPMBulkFileAndSendFileReadyMessage(); + assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage).contains("File ready event was unsuccessful: error"); + } + + @Test + void saveEventToMemory() { + ranFileReadyHolder = spy(new RanFileReadyHolder(ranVesSender, ftpServerService, pmBulkFileService, fileReadyEventService)); + try { + ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30); + ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30); + } catch (VesBrokerException e) { + e.printStackTrace(); + } + assertThat(ranFileReadyHolder.getCollectedEventsByCell().get(TEST_CELL_ID)).hasSize(2); + } + + @Test + void errorSaveEventToMemory() throws VesBrokerException { + doThrow(new VesBrokerException("error")).when(ranFileReadyHolder).saveEventToMemory(any(), any(), any(), any()); + + Throwable exception = assertThrows(VesBrokerException.class, + () -> ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30)); + assertThat(exception.getMessage()).contains("error"); + assertThat(ranFileReadyHolder.getCollectedEventsByCell()).isEmpty(); + } + + @Test + void getCollectedEventsByCell() { + Map> collectedEvents = ranFileReadyHolder.getCollectedEventsByCell(); + assertNotNull(collectedEvents); + } + + @Test + void getCollectedEvents() { + List collectedEvents = ranFileReadyHolder.getCollectedEventsForCellId(TEST_CELL_ID); + assertNotNull(collectedEvents); + try { + ranFileReadyHolder.saveEventToMemory(loadEventFromFile(), TEST_CELL_ID, UUID.randomUUID().toString(), 30); + collectedEvents = ranFileReadyHolder.getCollectedEventsForCellId(TEST_CELL_ID); + assertNotNull(collectedEvents); + } catch (VesBrokerException e) { + e.printStackTrace(); + } + } + + /** + * Creates common Log and Mocks + * + * @return ListAppender + */ + private ListAppender createCommonLogAndMock() { + ListAppender appender = createCommonLog(RanFileReadyHolder.class); + + List collectedEvents = getTestEvents(); + Map> collectedEventsByCell = getTestEventsByCells(collectedEvents); + FileData testFileData = FileData.builder().pmBulkFile(createTempFile(PM_BULK_FILE)).build(); + + doReturn(collectedEventsByCell).when(ranFileReadyHolder).getCollectedEventsByCell(); + doReturn(collectedEvents).when(ranFileReadyHolder).getCollectedEventsForCellId(any()); + doReturn(Mono.just(testFileData)).when(pmBulkFileService).generatePMBulkFileXml(collectedEvents); + testFileData.setArchivedPmBulkFile(createTempFile(ARCHIVED_PM_BULK_FILE)); + doReturn(Mono.just(testFileData)).when(ftpServerService).uploadFileToFtp(any()); + testFileData.setFileReadyEvent(new FileReadyEvent()); + doReturn(Mono.just(testFileData)).when(fileReadyEventService).createFileReadyEventAndDeleteTmpFile(any()); + doReturn(Mono.just(HttpStatus.SC_ACCEPTED)).when(ranVesSender).send(any()); + return appender; + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnableTest.java b/src/test/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnableTest.java new file mode 100644 index 0000000..198d46c --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/pm/RanSaveFileReadyRunnableTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.util.Collections; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.exception.VesBrokerException; +import org.onap.a1pesimulator.service.ue.RanUeHolder; +import org.onap.a1pesimulator.service.report.RanCellEventCustomizer; +import org.onap.a1pesimulator.service.report.RanEventCustomizerFactory; +import org.onap.a1pesimulator.service.report.RanEventCustomizerFactory.Mode; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; + +class RanSaveFileReadyRunnableTest extends CommonFileReady { + + private RanSaveFileReadyRunnable ranSaveFileReadyRunnable; + + @Mock + RanFileReadyHolder ranFileReadyHolder; + + @Mock + RanEventCustomizerFactory ranEventCustomizerFactory; + + @Mock + RanUeHolder ranUeHolder; + + @BeforeEach + void setUp() { + super.setUp(); + doReturn(new RanCellEventCustomizer(ranUeHolder)).when(ranEventCustomizerFactory).getEventCustomizer(any(), any()); + ranSaveFileReadyRunnable = spy( + new RanSaveFileReadyRunnable(ranFileReadyHolder, TEST_CELL_ID, loadEventFromFile(), ranEventCustomizerFactory.getEventCustomizer(new VesEvent(), + Mode.REGULAR), 60, Collections.emptyList())); + } + + @Test + void successfulRun() throws VesBrokerException { + ranSaveFileReadyRunnable.run(); + verify(ranFileReadyHolder, times(1)).saveEventToMemory(any(), any(), any(), any()); + } + + @Test + void errorRun() throws VesBrokerException { + ListAppender appender = createCommonLog(RanSaveFileReadyRunnable.class); + doThrow(new VesBrokerException("error")).when(ranFileReadyHolder).saveEventToMemory(any(), any(), any(), any()); + ranSaveFileReadyRunnable.run(); + assertThat(appender.list).extracting(ILoggingEvent::getFormattedMessage).containsExactly("Saving file ready event failed: error"); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnableTest.java b/src/test/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnableTest.java new file mode 100644 index 0000000..b7de25b --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/pm/RanSendReportsRunnableTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.pm; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.onap.a1pesimulator.service.ue.RanUeHolder; +import org.onap.a1pesimulator.service.report.RanCellEventCustomizer; +import org.onap.a1pesimulator.service.report.RanEventCustomizerFactory; + +class RanSendReportsRunnableTest extends CommonFileReady { + + private RanSendReportsRunnable ranSendReportsRunnable; + + @Mock + RanFileReadyHolder ranFileReadyHolder; + + @Mock + RanEventCustomizerFactory ranEventCustomizerFactory; + + @Mock + RanUeHolder ranUeHolder; + + @BeforeEach + void setUp() { + super.setUp(); + doReturn(new RanCellEventCustomizer(ranUeHolder)).when(ranEventCustomizerFactory).getEventCustomizer(any(), any()); + ranSendReportsRunnable = spy( + new RanSendReportsRunnable(ranFileReadyHolder)); + } + + @Test + void successfulRun() { + ranSendReportsRunnable.run(); + verify(ranFileReadyHolder, times(1)).createPMBulkFileAndSendFileReadyMessage(); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/report/RanVesHolderTest.java b/src/test/java/org/onap/a1pesimulator/service/report/RanVesHolderTest.java new file mode 100644 index 0000000..94a2b18 --- /dev/null +++ b/src/test/java/org/onap/a1pesimulator/service/report/RanVesHolderTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2021 Samsung Electronics + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package org.onap.a1pesimulator.service.report; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.a1pesimulator.data.ReportingMethodEnum; +import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; +import org.onap.a1pesimulator.data.ves.VesEvent; +import org.onap.a1pesimulator.service.common.EventCustomizer; +import org.onap.a1pesimulator.service.pm.CommonFileReady; +import org.onap.a1pesimulator.service.pm.RanFileReadyHolder; +import org.onap.a1pesimulator.service.ue.RanUeHolder; +import org.onap.a1pesimulator.util.VnfConfigReader; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.test.util.ReflectionTestUtils; + +class RanVesHolderTest extends CommonFileReady { + + private RanVesHolder ranCellsHolder; + + @Mock + RanVesDataProvider vesDataProvider; + + @Mock + Collection onEventActions; + + @Mock + RanFileReadyHolder ranFileReadyHolder; + + @Mock + RanVesSender vesSender; + + @Mock + EventCustomizer regularEventCustomizer; + + @Mock + RanUeHolder ranUeHolder; + + @InjectMocks + VnfConfigReader vnfConfigReader; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + ReflectionTestUtils.setField(vnfConfigReader, "vnfConfigFile", "src/test/resources/vnf.config"); + ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler = spy(new ThreadPoolTaskScheduler()); + vesPmThreadPoolTaskScheduler.initialize(); + RanEventCustomizerFactory eventCustomizerFactory = spy(new RanEventCustomizerFactory(regularEventCustomizer, ranUeHolder)); + ranCellsHolder = spy(new RanVesHolder(vesPmThreadPoolTaskScheduler, ranFileReadyHolder, vesSender, + vnfConfigReader, eventCustomizerFactory, vesDataProvider, onEventActions)); + } + + @Test + void getPeriodicEventsCache() { + ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); + Map periodicEventsCache = ranCellsHolder.getPeriodicEventsCache(); + assertThat(periodicEventsCache).containsKey(TEST_CELL_ID); + } + + @Test + void startSendingVesEvents() { + ResponseEntity response = ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); + assertThat(response.getStatusCode()).isEqualByComparingTo(HttpStatus.ACCEPTED); + assertThat(response.getBody()).contains("VES Event sending started"); + } + + @Test + void startSendingFailureVesEvents() { + doReturn(10).when(vesDataProvider).getFailureVesInterval(); + ResponseEntity response = ranCellsHolder.startSendingFailureVesEvents(TEST_CELL_ID, loadEventFromFile(), ReportingMethodEnum.FILE_READY); + assertThat(response.getStatusCode()).isEqualByComparingTo(HttpStatus.ACCEPTED); + assertThat(response.getBody()).contains("Failure VES Event sending started"); + } + + @Test + void stopSendingVesEvents() { + ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); + Optional response = ranCellsHolder.stopSendingVesEvents(TEST_CELL_ID); + assertThat(response).isPresent(); + } + + @Test + void getEnabledEventElementIdentifiers() { + ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.VES); + Collection elements = ranCellsHolder.getEnabledEventElementIdentifiers(); + assertThat(elements).isNotEmpty(); + } + + @Test + void isEventEnabled() { + ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); + boolean enabled = ranCellsHolder.isEventEnabled(TEST_CELL_ID); + assertThat(enabled).isTrue(); + } + + @Test + void isAnyEventRunning() { + ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); + boolean isRunning = ranCellsHolder.isAnyEventRunning(); + assertThat(isRunning).isTrue(); + } + + @Test + void getPMConfiguration() { + VesEvent testedEvent = loadEventFromFile(); + ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, testedEvent, 10, ReportingMethodEnum.FILE_READY); + RanPeriodicEvent event = ranCellsHolder.getPeriodicEventForCell(TEST_CELL_ID); + assertThat(event.getEvent()).isEqualTo(testedEvent); + assertThat(event.getInterval()).isEqualTo(10); + assertThat(event.getReportingMethod()).isEqualTo(ReportingMethodEnum.FILE_READY.getValue()); + } + + @Test + void getPMConfigurationError() { + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> ranCellsHolder.getPeriodicEventForCell(TEST_CELL_ID)); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/a1pesimulator/service/ves/RanVesHolderTest.java b/src/test/java/org/onap/a1pesimulator/service/ves/RanVesHolderTest.java deleted file mode 100644 index 7f6258c..0000000 --- a/src/test/java/org/onap/a1pesimulator/service/ves/RanVesHolderTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2021 Samsung Electronics - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package org.onap.a1pesimulator.service.ves; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; - -import java.util.Collection; -import java.util.Map; -import java.util.Optional; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.onap.a1pesimulator.data.ReportingMethodEnum; -import org.onap.a1pesimulator.data.fileready.RanPeriodicEvent; -import org.onap.a1pesimulator.data.ves.VesEvent; -import org.onap.a1pesimulator.service.common.EventCustomizer; -import org.onap.a1pesimulator.service.fileready.CommonFileReady; -import org.onap.a1pesimulator.service.fileready.RanFileReadyHolder; -import org.onap.a1pesimulator.service.ue.RanUeHolder; -import org.onap.a1pesimulator.util.VnfConfigReader; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.test.util.ReflectionTestUtils; - -class RanVesHolderTest extends CommonFileReady { - - private RanVesHolder ranCellsHolder; - - @Mock - RanVesDataProvider vesDataProvider; - - @Mock - Collection onEventActions; - - @Mock - RanFileReadyHolder ranFileReadyHolder; - - @Mock - RanVesSender vesSender; - - @Mock - EventCustomizer regularEventCustomizer; - - @Mock - RanUeHolder ranUeHolder; - - @InjectMocks - VnfConfigReader vnfConfigReader; - - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); - ReflectionTestUtils.setField(vnfConfigReader, "vnfConfigFile", "src/test/resources/vnf.config"); - ThreadPoolTaskScheduler vesPmThreadPoolTaskScheduler = spy(new ThreadPoolTaskScheduler()); - vesPmThreadPoolTaskScheduler.initialize(); - RanEventCustomizerFactory eventCustomizerFactory = spy(new RanEventCustomizerFactory(regularEventCustomizer, ranUeHolder)); - ranCellsHolder = spy(new RanVesHolder(vesPmThreadPoolTaskScheduler, ranFileReadyHolder, vesSender, - vnfConfigReader, eventCustomizerFactory, vesDataProvider, onEventActions)); - } - - @Test - void getPeriodicEventsCache() { - ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); - Map periodicEventsCache = ranCellsHolder.getPeriodicEventsCache(); - assertThat(periodicEventsCache).containsKey(TEST_CELL_ID); - } - - @Test - void startSendingVesEvents() { - ResponseEntity response = ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); - assertThat(response.getStatusCode()).isEqualByComparingTo(HttpStatus.ACCEPTED); - assertThat(response.getBody()).contains("VES Event sending started"); - } - - @Test - void startSendingFailureVesEvents() { - doReturn(10).when(vesDataProvider).getFailureVesInterval(); - ResponseEntity response = ranCellsHolder.startSendingFailureVesEvents(TEST_CELL_ID, loadEventFromFile(), ReportingMethodEnum.FILE_READY); - assertThat(response.getStatusCode()).isEqualByComparingTo(HttpStatus.ACCEPTED); - assertThat(response.getBody()).contains("Failure VES Event sending started"); - } - - @Test - void stopSendingVesEvents() { - ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); - Optional response = ranCellsHolder.stopSendingVesEvents(TEST_CELL_ID); - assertThat(response).isPresent(); - } - - @Test - void getEnabledEventElementIdentifiers() { - ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.VES); - Collection elements = ranCellsHolder.getEnabledEventElementIdentifiers(); - assertThat(elements).isNotEmpty(); - } - - @Test - void isEventEnabled() { - ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); - boolean enabled = ranCellsHolder.isEventEnabled(TEST_CELL_ID); - assertThat(enabled).isTrue(); - } - - @Test - void isAnyEventRunning() { - ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, loadEventFromFile(), 10, ReportingMethodEnum.FILE_READY); - boolean isRunning = ranCellsHolder.isAnyEventRunning(); - assertThat(isRunning).isTrue(); - } - - @Test - void getEventStructure() { - VesEvent testedEvent = loadEventFromFile(); - ranCellsHolder.startSendingVesEvents(TEST_CELL_ID, testedEvent, 10, ReportingMethodEnum.FILE_READY); - RanPeriodicEvent event = ranCellsHolder.getPeriodicEventForCell(TEST_CELL_ID); - assertThat(event.getEvent()).isEqualTo(testedEvent); - assertThat(event.getInterval()).isEqualTo(10); - assertThat(event.getReportingMethod()).isEqualTo(ReportingMethodEnum.FILE_READY.getValue()); - } - - @Test - void getEventStructureError() { - assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> ranCellsHolder.getPeriodicEventForCell(TEST_CELL_ID)); - } -} \ No newline at end of file -- cgit 1.2.3-korg