diff --git a/Dockerfile b/Dockerfile index 5d9a1d4f60cd7487c9de71a8f0057930e7637841..0d36bebfba4211f93135f2c7121da6a3fad9ad28 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM ibm-semeru-runtimes:open-17.0.7_7-jdk # RUN mkdir /opt/shareclasses RUN mkdir -p /opt/openslice/lib/ -COPY target/org.etsi.osl.tmf.api-1.1.0-exec.jar /opt/openslice/lib/ -CMD ["java", "-Xshareclasses:cacheDir=/opt/shareclasses", "-jar", "/opt/openslice/lib/org.etsi.osl.tmf.api-1.1.0-exec.jar"] +COPY target/org.etsi.osl.tmf.api-1.2.0-SNAPSHOT-exec.jar /opt/openslice/lib/ +CMD ["java", "-Xshareclasses:cacheDir=/opt/shareclasses", "-jar", "/opt/openslice/lib/org.etsi.osl.tmf.api-1.2.0-SNAPSHOT-exec.jar"] EXPOSE 13082 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3184b3aa8216683e03259ec2967b84fd4309139e..6308aa4165a644ea5e9202bea4d8ee76537e5f64 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.etsi.osl org.etsi.osl.main - 2024Q4 + 2025Q2-SNAPSHOT ../org.etsi.osl.main @@ -305,7 +305,7 @@ com.h2database h2 - test + 2.3.232 org.apache.activemq diff --git a/src/main/java/org/etsi/osl/tmf/configuration/SwaggerDocumentationConfig.java b/src/main/java/org/etsi/osl/tmf/configuration/SwaggerDocumentationConfig.java index b8e5b11ab5d362a73dc607ebe8a56453a7d04132..796d26a3a83f5b72bd160c3f6664b812b9220294 100644 --- a/src/main/java/org/etsi/osl/tmf/configuration/SwaggerDocumentationConfig.java +++ b/src/main/java/org/etsi/osl/tmf/configuration/SwaggerDocumentationConfig.java @@ -830,7 +830,7 @@ public GroupedOpenApi pim637() { SpringDocUtils.getConfig().replaceWithClass(java.time.OffsetDateTime.class, java.util.Date.class); return GroupedOpenApi.builder() - .group("OpensliceLCMRulesspecificationAPI") + .group("OpenSliceLCMRulesspecificationAPI") .addOpenApiCustomizer( this.lcmOpenAPI() ) .packagesToScan("org.etsi.osl.tmf.lcm.api") .build(); @@ -947,6 +947,39 @@ public GroupedOpenApi pim637() { .build(); } + + + /** + * Metrics + * @return + */ + @Bean + public OpenApiCustomizer metricsOpenAPI() { + return openApi -> openApi + .specVersion( SpecVersion.V30 ).addSecurityItem(new SecurityRequirement().addList("security_auth")) + .info(new Info().title("OpenSlice Metrics API") + .description("OpenAPI environment for OpenSlice Metrics") + .version("4.0.0") + .license(new License() + .name("Apache 2.0") + .url("https://osl.etsi.org"))) + .externalDocs(new ExternalDocumentation() + .description("OpenSlice Metrics") + .url("https://osl.etsi.org")); + } + + @Bean + public GroupedOpenApi metrics(){ + + SpringDocUtils.getConfig().replaceWithClass(java.time.LocalDate.class, java.sql.Date.class); + SpringDocUtils.getConfig().replaceWithClass(java.time.OffsetDateTime.class, java.util.Date.class); + return GroupedOpenApi.builder() + .group("OpenSliceMetricsAPI") + .addOpenApiCustomizer( this.metricsOpenAPI() ) + .packagesToScan("org.etsi.osl.tmf.metrics.api") + .build(); + + } // @Bean diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/GeneralMetricsApi.java b/src/main/java/org/etsi/osl/tmf/metrics/api/GeneralMetricsApi.java new file mode 100644 index 0000000000000000000000000000000000000000..4c3714c563937337897bf35da9c21f4b9b56ed8e --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/GeneralMetricsApi.java @@ -0,0 +1,49 @@ +package org.etsi.osl.tmf.metrics.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.etsi.osl.tmf.metrics.PublishedServiceSpecifications; +import org.etsi.osl.tmf.metrics.RegisteredIndividuals; +import org.etsi.osl.tmf.metrics.RegisteredResourceSpecifications; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import java.util.Map; + +@Tag(name = "GeneralMetricsApi", description = "The General Metrics API") +public interface GeneralMetricsApi { + + Logger log = LoggerFactory.getLogger(GeneralMetricsApi.class); + + @Operation(summary = "Get total number of registered individuals", operationId = "getRegisteredIndividuals") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/registeredIndividuals", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getRegisteredIndividuals(); + + @Operation(summary = "Get total number of published service specifications", operationId = "getPublishedServiceSpecifications") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/publishedServiceSpecifications", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getPublishedServiceSpecifications(); + + @Operation(summary = "Get total number of registered resource specifications", operationId = "getRegisteredResourceSpecifications") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/registeredResourceSpecifications", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getRegisteredResourceSpecifications(); +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/GeneralMetricsApiController.java b/src/main/java/org/etsi/osl/tmf/metrics/api/GeneralMetricsApiController.java new file mode 100644 index 0000000000000000000000000000000000000000..187920b39606571c595d93d3acd804d3ed7c833f --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/GeneralMetricsApiController.java @@ -0,0 +1,64 @@ +package org.etsi.osl.tmf.metrics.api; + +import org.etsi.osl.tmf.metrics.PublishedServiceSpecifications; +import org.etsi.osl.tmf.metrics.RegisteredIndividuals; +import org.etsi.osl.tmf.metrics.RegisteredResourceSpecifications; +import org.etsi.osl.tmf.metrics.reposervices.GeneralMetricsRepoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; + +import java.util.HashMap; +import java.util.Map; + +@Controller +public class GeneralMetricsApiController implements GeneralMetricsApi { + + private static final Logger log = LoggerFactory.getLogger(GeneralMetricsApiController.class); + + private final GeneralMetricsRepoService generalMetricsRepoService; + + @Autowired + public GeneralMetricsApiController(GeneralMetricsRepoService generalMetricsRepoService) { + this.generalMetricsRepoService = generalMetricsRepoService; + } + + @Override + public ResponseEntity getRegisteredIndividuals() { + try { + int totalIndividuals = generalMetricsRepoService.countRegisteredIndividuals(); + RegisteredIndividuals response = new RegisteredIndividuals(totalIndividuals); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + log.error("Couldn't retrieve total registered individuals. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + public ResponseEntity getPublishedServiceSpecifications() { + try { + int totalSpecifications = generalMetricsRepoService.countPublishedServiceSpecifications(); + PublishedServiceSpecifications response = new PublishedServiceSpecifications(totalSpecifications); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + log.error("Couldn't retrieve total published service specifications. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + public ResponseEntity getRegisteredResourceSpecifications() { + try { + int totalResourceSpecifications = generalMetricsRepoService.countRegisteredResourceSpecifications(); + RegisteredResourceSpecifications response = new RegisteredResourceSpecifications(totalResourceSpecifications); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + log.error("Couldn't retrieve total registered resource specifications. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApi.java b/src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApi.java new file mode 100644 index 0000000000000000000000000000000000000000..8f0016979b961f47f980234faa1366f034d71988 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApi.java @@ -0,0 +1,49 @@ +package org.etsi.osl.tmf.metrics.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.etsi.osl.tmf.metrics.ResourcesGroupByState; +import org.etsi.osl.tmf.metrics.TotalResources; +import org.etsi.osl.tmf.ri639.model.ResourceStatusType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import java.time.OffsetDateTime; +import java.util.Map; + +@Tag(name = "ResourceMetricsApi", description = "The Resources' Metrics API") +public interface ResourceMetricsApi { + + Logger log = LoggerFactory.getLogger(ResourceMetricsApi.class); + + @Operation(summary = "Get total number of resources", operationId = "getTotalResources") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/totalResources", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getTotalResources( + @Valid @RequestParam(value = "state", required = false) ResourceStatusType state + ); + + @Operation(summary = "Get resources grouped by state", operationId = "getResourcesGroupedByState") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/resourcesGroupByState", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getResourcesGroupedByState( + @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, + @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime + ); +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApiController.java b/src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApiController.java new file mode 100644 index 0000000000000000000000000000000000000000..fac650828ed2384d72b70a6f6300816a7351a4e9 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApiController.java @@ -0,0 +1,76 @@ +package org.etsi.osl.tmf.metrics.api; + +import org.etsi.osl.tmf.metrics.*; +import org.etsi.osl.tmf.metrics.reposervices.ResourceMetricsRepoService; +import org.etsi.osl.tmf.ri639.model.ResourceStatusType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; + +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Controller +public class ResourceMetricsApiController implements ResourceMetricsApi { + + private static final Logger log = LoggerFactory.getLogger(ResourceMetricsApiController.class); + private final ResourceMetricsRepoService resourceMetricsRepoService; + + @Autowired + public ResourceMetricsApiController(ResourceMetricsRepoService resourceMetricsRepoService) { + this.resourceMetricsRepoService = resourceMetricsRepoService; + } + + @Override + public ResponseEntity getTotalResources(ResourceStatusType state) { + try { + int totalResources = resourceMetricsRepoService.countTotalResources(state); + TotalResources response = new TotalResources(totalResources); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + log.error("Couldn't retrieve total resources. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + public ResponseEntity getResourcesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { + try { + Map resourcesByState = resourceMetricsRepoService.getResourcesGroupedByState(starttime, endtime); + + // Initialize with all possible states and 0. Ensures that all states are represented, even if not present in the data. + Map fullStateMap = new LinkedHashMap<>(); + for (ResourceStatusType state : ResourceStatusType.values()) { + fullStateMap.put(state.name(), 0); // default to 0 + } + + // Overwrite counts with actual data + resourcesByState.forEach((key, value) -> { + fullStateMap.put(key.toUpperCase(), value); // normalize case just in case + }); + + // Create aggregation items + List groupByStateList = fullStateMap.entrySet().stream() + .map(entry -> new ResourcesGroupByStateItem(ResourceStatusType.valueOf(entry.getKey()), entry.getValue())) + .toList(); + + // Build response structure using models + ResourcesGroupByStateAggregations aggregations = new ResourcesGroupByStateAggregations(groupByStateList); + int total = fullStateMap.values().stream().mapToInt(Integer::intValue).sum(); + Resources services = new Resources(total, aggregations); + ResourcesGroupByState response = new ResourcesGroupByState(services); + + return new ResponseEntity<>(response, HttpStatus.OK); + + } catch (Exception e) { + log.error("Couldn't retrieve resources grouped by state. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceMetricsApi.java b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceMetricsApi.java new file mode 100644 index 0000000000000000000000000000000000000000..b5595535132a027f88cc6c34e38b8d6f3a2350fe --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceMetricsApi.java @@ -0,0 +1,49 @@ +package org.etsi.osl.tmf.metrics.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.etsi.osl.tmf.common.model.service.ServiceStateType; +import org.etsi.osl.tmf.metrics.ServicesGroupByState; +import org.etsi.osl.tmf.metrics.TotalServices; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import java.time.OffsetDateTime; +import java.util.Map; + +@Tag(name = "ServiceMetricsApi", description = "The Services' Metrics API") +public interface ServiceMetricsApi { + + Logger log = LoggerFactory.getLogger(ServiceMetricsApi.class); + + @Operation(summary = "Get total number of services", operationId = "getTotalServices") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/totalServices", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getTotalServices( + @Valid @RequestParam(value = "state", required = false) ServiceStateType state + ); + + @Operation(summary = "Get services grouped by state", operationId = "getServicesGroupedByState") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/servicesGroupByState", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getServicesGroupedByState( + @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, + @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime + ); +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceMetricsApiController.java b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceMetricsApiController.java new file mode 100644 index 0000000000000000000000000000000000000000..abe7575e19556a33442e830bdca100173f0d681a --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceMetricsApiController.java @@ -0,0 +1,75 @@ +package org.etsi.osl.tmf.metrics.api; + +import org.etsi.osl.tmf.common.model.service.ServiceStateType; +import org.etsi.osl.tmf.metrics.*; +import org.etsi.osl.tmf.metrics.reposervices.ServiceMetricsRepoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; + +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Controller +public class ServiceMetricsApiController implements ServiceMetricsApi { + + private static final Logger log = LoggerFactory.getLogger(ServiceMetricsApiController.class); + private final ServiceMetricsRepoService serviceMetricsRepoService; + + @Autowired + public ServiceMetricsApiController(ServiceMetricsRepoService serviceMetricsRepoService) { + this.serviceMetricsRepoService = serviceMetricsRepoService; + } + + @Override + public ResponseEntity getTotalServices(ServiceStateType state) { + try { + int totalServices = serviceMetricsRepoService.countTotalServices(state); + TotalServices response = new TotalServices(totalServices); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + log.error("Couldn't retrieve total services. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + public ResponseEntity getServicesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { + try { + Map servicesByState = serviceMetricsRepoService.getServicesGroupedByState(starttime, endtime); + + // Initialize with all possible states and 0. Ensures that all states are represented, even if not present in the data. + Map fullStateMap = new LinkedHashMap<>(); + for (ServiceStateType state : ServiceStateType.values()) { + fullStateMap.put(state.name(), 0); // default to 0 + } + + // Overwrite counts with actual data + servicesByState.forEach((key, value) -> { + fullStateMap.put(key.toUpperCase(), value); // normalize case just in case + }); + + // Create aggregation items + List groupByStateList = fullStateMap.entrySet().stream() + .map(entry -> new ServicesGroupByStateItem(ServiceStateType.valueOf(entry.getKey()), entry.getValue())) + .toList(); + + // Build response structure using metrics models + ServicesGroupByStateAggregations aggregations = new ServicesGroupByStateAggregations(groupByStateList); + int total = fullStateMap.values().stream().mapToInt(Integer::intValue).sum(); + Services services = new Services(total, aggregations); + ServicesGroupByState response = new ServicesGroupByState(services); + + return new ResponseEntity<>(response, HttpStatus.OK); + + } catch (Exception e) { + log.error("Couldn't retrieve services grouped by state. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApi.java b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApi.java new file mode 100644 index 0000000000000000000000000000000000000000..17afc56186a9fbbb4282a1dc17b93ef33386be0c --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApi.java @@ -0,0 +1,75 @@ +package org.etsi.osl.tmf.metrics.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.etsi.osl.tmf.metrics.ActiveServiceOrders; +import org.etsi.osl.tmf.metrics.ServiceOrdersGroupByDay; +import org.etsi.osl.tmf.metrics.ServiceOrdersGroupByState; +import org.etsi.osl.tmf.metrics.TotalServiceOrders; +import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import java.time.OffsetDateTime; +import java.util.Map; + +@Tag(name = "ServiceOrderMetricsApi", description = "The Service Orders' Metrics API") +public interface ServiceOrderMetricsApi { + + Logger log = LoggerFactory.getLogger(ServiceOrderMetricsApi.class); + + @Operation(summary = "Get total number of service orders", operationId = "getTotalServiceOrders") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/totalServiceOrders", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getTotalServiceOrders( + @Valid @RequestParam(value = "state", required = false) ServiceOrderStateType state + ); + + + @Operation(summary = "Get total number of active service orders", operationId = "getTotalActiveServiceOrders") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/activeServiceOrders", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getTotalActiveServiceOrders(); + + + @Operation(summary = "Get service orders grouped by day", operationId = "getServiceOrdersGroupedByDay") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/serviceOrdersGroupByDay", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getServiceOrdersGroupedByDay( + @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, + @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime + ); + + + @Operation(summary = "Get service orders grouped by state", operationId = "getServiceOrdersGroupedByState") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error") + }) + @RequestMapping(value = "/metrics/serviceOrdersGroupByState", method = RequestMethod.GET, produces = "application/json;charset=utf-8") + ResponseEntity getServiceOrdersGroupedByState( + @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, + @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime + ); +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApiController.java b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApiController.java new file mode 100644 index 0000000000000000000000000000000000000000..6b0a1bf8efe15abe954d20c65fd20f24a65603e8 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApiController.java @@ -0,0 +1,123 @@ +package org.etsi.osl.tmf.metrics.api; + +import org.etsi.osl.tmf.metrics.*; +import org.etsi.osl.tmf.metrics.reposervices.ServiceOrderMetricsRepoService; +import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + + +@Controller +public class ServiceOrderMetricsApiController implements ServiceOrderMetricsApi { + + private static final Logger log = LoggerFactory.getLogger(ServiceOrderMetricsApiController.class); + private final ServiceOrderMetricsRepoService serviceOrderMetricsRepoService; + + @Autowired + public ServiceOrderMetricsApiController(ServiceOrderMetricsRepoService serviceOrderMetricsRepoService) { + this.serviceOrderMetricsRepoService = serviceOrderMetricsRepoService; + } + + @Override + public ResponseEntity getTotalServiceOrders(ServiceOrderStateType state) { + try { + int totalServiceOrders = serviceOrderMetricsRepoService.countTotalServiceOrders(state); + TotalServiceOrders response = new TotalServiceOrders(totalServiceOrders); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + log.error("Couldn't retrieve total service orders. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + public ResponseEntity getTotalActiveServiceOrders() { + try { + int totalActiveServiceOrders = serviceOrderMetricsRepoService.countTotalActiveServiceOrders(); + ActiveServiceOrders response = new ActiveServiceOrders(totalActiveServiceOrders); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + log.error("Couldn't retrieve total active service orders. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + public ResponseEntity getServiceOrdersGroupedByDay(OffsetDateTime starttime, OffsetDateTime endtime) { + try { + Map orderDatesGroupedByDate = serviceOrderMetricsRepoService.getServiceOrdersGroupedByDay(starttime, endtime); + + // Fill missing days with count 0 + Map fullDayMap = new LinkedHashMap<>(); + OffsetDateTime cursor = starttime.truncatedTo(ChronoUnit.DAYS); + OffsetDateTime endDay = endtime.truncatedTo(ChronoUnit.DAYS); + while (!cursor.isAfter(endDay)) { + String key = cursor.toInstant().toString(); + fullDayMap.put(key, orderDatesGroupedByDate.getOrDefault(key, 0)); + cursor = cursor.plusDays(1); + } + + // Convert to model list + List groupByDayList = fullDayMap.entrySet().stream() + .map(entry -> new ServiceOrdersGroupByDayItem(entry.getKey(), entry.getValue())) + .toList(); + + ServiceOrdersGroupByDayAggregations aggregations = new ServiceOrdersGroupByDayAggregations(groupByDayList); + int total = fullDayMap.values().stream().mapToInt(Integer::intValue).sum(); + ServiceOrdersGroupByDayParent wrapper = new ServiceOrdersGroupByDayParent(total, aggregations); + ServiceOrdersGroupByDay response = new ServiceOrdersGroupByDay(wrapper); + + return new ResponseEntity<>(response, HttpStatus.OK); + + } catch (Exception e) { + log.error("Couldn't retrieve services grouped by state. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + public ResponseEntity getServiceOrdersGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { + try { + Map servicesByState = serviceOrderMetricsRepoService.getServiceOrdersGroupedByState(starttime, endtime); + + // Initialize with all possible states and 0. Ensures that all states are represented, even if not present in the data. + Map fullStateMap = new LinkedHashMap<>(); + for (ServiceOrderStateType state : ServiceOrderStateType.values()) { + fullStateMap.put(state.name(), 0); + } + + // Overwrite counts with actual data + servicesByState.forEach((key, value) -> { + fullStateMap.put(key.toUpperCase(), value); + }); + + // Create aggregation items + List groupByStateList = fullStateMap.entrySet().stream() + .map(entry -> new ServiceOrdersGroupByStateItem(ServiceOrderStateType.valueOf(entry.getKey()), entry.getValue())) + .toList(); + + // Build response structure using models + ServiceOrdersGroupByStateAggregations aggregations = new ServiceOrdersGroupByStateAggregations(groupByStateList); + int total = fullStateMap.values().stream().mapToInt(Integer::intValue).sum(); + ServiceOrdersGroupByStateParent services = new ServiceOrdersGroupByStateParent(total, aggregations); + ServiceOrdersGroupByState response = new ServiceOrdersGroupByState(services); + + return new ResponseEntity<>(response, HttpStatus.OK); + + } catch (Exception e) { + log.error("Couldn't retrieve services grouped by state. ", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/reposervices/GeneralMetricsRepoService.java b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/GeneralMetricsRepoService.java new file mode 100644 index 0000000000000000000000000000000000000000..00276eff2fa9e824d4792b0f95b81ef49c9a2218 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/GeneralMetricsRepoService.java @@ -0,0 +1,49 @@ +package org.etsi.osl.tmf.metrics.reposervices; + +import org.etsi.osl.tmf.pm632.repo.IndividualRepository; +import org.etsi.osl.tmf.rcm634.repo.ResourceSpecificationRepository; +import org.etsi.osl.tmf.scm633.model.ServiceCandidate; +import org.etsi.osl.tmf.scm633.repo.CandidateRepository; +import org.etsi.osl.tmf.scm633.repo.CategoriesRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class GeneralMetricsRepoService { + + @Autowired + IndividualRepository individualRepository; + + @Autowired + ResourceSpecificationRepository resourceSpecificationRepository; + + @Autowired + CategoriesRepository categoriesRepository; + + @Autowired + CandidateRepository candidateRepository; + + public int countRegisteredIndividuals() { + return individualRepository.countAll(); + } + + public int countPublishedServiceSpecifications() { + + List serviceCandidates = candidateRepository.findAll(); + int count = 0; + + for (ServiceCandidate serviceCandidate : serviceCandidates) { + System.out.println("ServiceCandidate Category: " + serviceCandidate.getCategoryObj()); + if (serviceCandidate.getCategory() != null) { + count += 1; + } + } + return count; + } + + public int countRegisteredResourceSpecifications() { + return resourceSpecificationRepository.countLogical() + resourceSpecificationRepository.countPhysical(); + } +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ResourceMetricsRepoService.java b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ResourceMetricsRepoService.java new file mode 100644 index 0000000000000000000000000000000000000000..70feca732a32c6d6bdac9890570ec24e79a53844 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ResourceMetricsRepoService.java @@ -0,0 +1,46 @@ +package org.etsi.osl.tmf.metrics.reposervices; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.etsi.osl.tmf.ri639.model.ResourceStatusType; +import org.etsi.osl.tmf.ri639.repo.ResourceRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Service +public class ResourceMetricsRepoService { + + @Autowired + ObjectMapper objectMapper; + + @Autowired + ResourceRepository resourceRepository; + + public int countTotalResources(ResourceStatusType state) { + if (state == null) { + return resourceRepository.countAll(); + } else { + return resourceRepository.countByResourceStatus(state); + } + } + + public Map getResourcesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { + if (starttime.plusDays(31).isBefore(endtime)) { + starttime = endtime.minusDays(31); + } + + List rawResults = resourceRepository.groupByStateBetweenDates(starttime, endtime); + + return rawResults.stream() + .collect(Collectors.toMap( + row -> row[0].toString(), + row -> ((Number) row[1]).intValue() + )); + } + +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceMetricsRepoService.java b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceMetricsRepoService.java new file mode 100644 index 0000000000000000000000000000000000000000..ef910dce296959d123368acaeccffb72fca095e8 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceMetricsRepoService.java @@ -0,0 +1,45 @@ +package org.etsi.osl.tmf.metrics.reposervices; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.etsi.osl.tmf.common.model.service.ServiceStateType; +import org.etsi.osl.tmf.sim638.repo.ServiceRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class ServiceMetricsRepoService { + + @Autowired + ObjectMapper objectMapper; + + @Autowired + ServiceRepository serviceRepo; + + public int countTotalServices(ServiceStateType state) { + if (state == null) { + return serviceRepo.countAll(); + } else { + return serviceRepo.countByState(state); + } + } + + public Map getServicesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { + if (starttime.plusDays(31).isBefore(endtime)) { + starttime = endtime.minusDays(31); + } + + List rawResults = serviceRepo.groupByStateBetweenDates(starttime, endtime); + + return rawResults.stream() + .collect(Collectors.toMap( + row -> row[0].toString(), + row -> ((Number) row[1]).intValue() + )); + } + +} diff --git a/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceOrderMetricsRepoService.java b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceOrderMetricsRepoService.java new file mode 100644 index 0000000000000000000000000000000000000000..9bd49793b0f0c264fe72b1231300313c7a406aa6 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceOrderMetricsRepoService.java @@ -0,0 +1,79 @@ +package org.etsi.osl.tmf.metrics.reposervices; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; +import org.etsi.osl.tmf.so641.repo.ServiceOrderRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class ServiceOrderMetricsRepoService { + + @Autowired + ObjectMapper objectMapper; + + @Autowired + ServiceOrderRepository serviceOrderRepository; + + public int countTotalServiceOrders(ServiceOrderStateType state) { + if (state == null) { + return serviceOrderRepository.countAll(); + } else { + return serviceOrderRepository.countByState(state); + } + } + + public int countTotalActiveServiceOrders() { + OffsetDateTime currentDate = OffsetDateTime.now(); + List activeStates = List.of( + ServiceOrderStateType.INPROGRESS, + ServiceOrderStateType.COMPLETED + ); + + return serviceOrderRepository.countAllActive(currentDate, activeStates); + } + + public Map getServiceOrdersGroupedByDay(OffsetDateTime starttime, OffsetDateTime endtime) { + if (starttime.plusDays(31).isBefore(endtime)) { + starttime = endtime.minusDays(31); + } + + List orderDates = serviceOrderRepository.getOrderDatesBetweenDates(starttime, endtime); + + // First group by day with count as Long + Map grouped = orderDates.stream() + .map(dt -> dt.truncatedTo(ChronoUnit.DAYS)) // Remove time portion + .collect(Collectors.groupingBy( + dt -> dt.toInstant().toString(), // Format as ISO string (Z) + Collectors.counting() + )); + + // Convert Map to Map + return grouped.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> e.getValue().intValue() + )); + } + + public Map getServiceOrdersGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { + if (starttime.plusDays(31).isBefore(endtime)) { + starttime = endtime.minusDays(31); + } + + List rawResults = serviceOrderRepository.groupByStateBetweenDates(starttime, endtime); + + return rawResults.stream() + .collect(Collectors.toMap( + row -> row[0].toString(), + row -> ((Number) row[1]).intValue() + )); + } + +} diff --git a/src/main/java/org/etsi/osl/tmf/pcm620/api/ProductCatalogApiRouteBuilder.java b/src/main/java/org/etsi/osl/tmf/pcm620/api/ProductCatalogApiRouteBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..950a9a5404769089d9d59c56c82a2297ad33d066 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/pcm620/api/ProductCatalogApiRouteBuilder.java @@ -0,0 +1,132 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 - 2020 openslice.io + * %% + * 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. + * =========================LICENSE_END================================== + */ +package org.etsi.osl.tmf.pcm620.api; + +import java.io.IOException; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.etsi.osl.tmf.pcm620.reposervices.ProductCatalogRepoService; +import org.etsi.osl.tmf.pcm620.reposervices.ProductCategoryRepoService; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreate; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationUpdate; +import org.etsi.osl.tmf.scm633.reposervices.CatalogRepoService; +import org.etsi.osl.tmf.scm633.reposervices.CategoryRepoService; +import org.etsi.osl.tmf.scm633.reposervices.ServiceSpecificationRepoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Configuration +//@RefreshScope +@Component +public class ProductCatalogApiRouteBuilder extends RouteBuilder { + + private static final transient Log logger = LogFactory.getLog(ProductCatalogApiRouteBuilder.class.getName()); + + + + @Value("${CATALOG_GET_PRODUCTCATALOGS}") + private String CATALOG_GET_PRODUCTCATALOGS = ""; + + @Value("${CATALOG_GET_PRODUCTCATALOG_BY_ID}") + private String CATALOG_GET_PRODUCTCATALOG_BY_ID = ""; + + @Value("${CATALOG_GET_PRODUCTCATALOG_BY_NAME}") + private String CATALOG_GET_PRODUCTCATALOG_BY_NAME = ""; + + @Value("${CATALOG_GET_PRODUCTCATEGORIES}") + private String CATALOG_GET_PRODUCTCATEGORIES = ""; + + @Value("${CATALOG_GET_PRODUCTCATEGORY_BY_ID}") + private String CATALOG_GET_PRODUCTCATEGORY_BY_ID = ""; + + + @Value("${CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID}") + private String CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID = ""; + + + @Autowired + ProductCatalogRepoService catalogRepoService; + + + @Autowired + ProductCategoryRepoService categoryRepoService; + + + @Override + public void configure() throws Exception { + + from( CATALOG_GET_PRODUCTCATALOG_BY_ID ) + .log(LoggingLevel.INFO, log, CATALOG_GET_PRODUCTCATALOG_BY_ID + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findByUuidEager(${header.catalogId})"); + + from( CATALOG_GET_PRODUCTCATALOGS ) + .log(LoggingLevel.INFO, log, CATALOG_GET_PRODUCTCATALOGS + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findAllEager()"); + + from( CATALOG_GET_PRODUCTCATALOG_BY_NAME ) + .log(LoggingLevel.INFO, log, CATALOG_GET_PRODUCTCATALOG_BY_NAME + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findByNameEager(${header.catalogName})") + .marshal().json( JsonLibrary.Jackson, String.class) + .convertBodyTo( String.class ); + + + from( CATALOG_GET_PRODUCTCATEGORIES ) + .log(LoggingLevel.INFO, log, CATALOG_GET_PRODUCTCATEGORIES + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findAllCategoriesByCatalogName(${header.catalogName})"); + + + from( CATALOG_GET_PRODUCTCATEGORY_BY_ID ) + .log(LoggingLevel.INFO, log, CATALOG_GET_PRODUCTCATEGORY_BY_ID + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( categoryRepoService, "findByIdEager(${header.catalogId})"); + + + from( CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID ) + .log(LoggingLevel.INFO, log, CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( categoryRepoService, "findAllProductOfferingsByCategId(${header.categoryId})"); + + } + + + + + + static T toJsonObj(String content, Class valueType) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper.readValue( content, valueType); + } + +} diff --git a/src/main/java/org/etsi/osl/tmf/pcm620/api/ProductSpecificationApiRouteBuilder.java b/src/main/java/org/etsi/osl/tmf/pcm620/api/ProductSpecificationApiRouteBuilder.java index 07fe723d0e242df176992fc1729001098dd3427e..0c55c76983439e340b18b69c30807cfad260a407 100644 --- a/src/main/java/org/etsi/osl/tmf/pcm620/api/ProductSpecificationApiRouteBuilder.java +++ b/src/main/java/org/etsi/osl/tmf/pcm620/api/ProductSpecificationApiRouteBuilder.java @@ -1,5 +1,6 @@ package org.etsi.osl.tmf.pcm620.api; +import java.util.ArrayList; import org.apache.camel.LoggingLevel; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.dataformat.JsonLibrary; @@ -38,6 +39,10 @@ public class ProductSpecificationApiRouteBuilder extends RouteBuilder { @Value("${CATALOG_GET_PRODUCTOFFERING_BY_ID}") private String CATALOG_GET_PRODUCTOFFERING_BY_ID = ""; + + + @Value("${CATALOG_SEARCH_PRODUCTOFFERINGS}") + private String CATALOG_SEARCH_PRODUCTOFFERINGS = ""; @@ -90,6 +95,14 @@ public class ProductSpecificationApiRouteBuilder extends RouteBuilder { .marshal().json( JsonLibrary.Jackson, String.class) .convertBodyTo( String.class ); + + + from( CATALOG_SEARCH_PRODUCTOFFERINGS ) + .log(LoggingLevel.INFO, log, CATALOG_SEARCH_PRODUCTOFFERINGS + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .unmarshal().json( JsonLibrary.Jackson, ArrayList.class, true) + .bean( productOfferingRepoService, "searchProductOfferings( ${body} )"); + } } diff --git a/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCatalogRepoService.java b/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCatalogRepoService.java index 126999bd90598748e8c8d91146cb28b070f282ac..3f66f5c7686023d4734ae40376100f99e179e269 100644 --- a/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCatalogRepoService.java +++ b/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCatalogRepoService.java @@ -21,8 +21,12 @@ package org.etsi.osl.tmf.pcm620.reposervices; import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule; import org.etsi.osl.tmf.common.model.ELifecycle; import org.etsi.osl.tmf.common.model.TimePeriod; import org.etsi.osl.tmf.pcm620.model.Catalog; @@ -31,11 +35,16 @@ import org.etsi.osl.tmf.pcm620.model.CatalogUpdate; import org.etsi.osl.tmf.pcm620.model.Category; import org.etsi.osl.tmf.pcm620.model.CategoryRef; import org.etsi.osl.tmf.pcm620.repo.ProductCatalogRepository; +import org.etsi.osl.tmf.scm633.model.ServiceCatalog; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryRef; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import jakarta.validation.Valid; @Service +@Transactional public class ProductCatalogRepoService { @@ -80,6 +89,65 @@ public class ProductCatalogRepoService { return null; } + + public String findByUuidEager(String id) { + + Catalog sc = this.findById(id); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + String res; + try { + res = mapper.writeValueAsString( sc ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return "{}"; + } + + return res; + } + + public String findAllEager() { + + List oids = (List) this.catalogRepo.findByOrderByName(); + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + String res; + try { + res = mapper.writeValueAsString( oids ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return "{}"; + } + + return res; + } + + public String findByNameEager(String aname) { + Catalog sc = this.findByName(aname); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + String res; + try { + res = mapper.writeValueAsString( sc ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return "{}"; + } + + return res; + + } public Catalog updateCatalog(String id, CatalogUpdate Catalog) { @@ -131,5 +199,64 @@ public class ProductCatalogRepoService { public Catalog updateCatalog(Catalog scatalog) { return this.catalogRepo.save(scatalog); } + + /** + * return recursively all categories in catalog + * @param catalogName + */ + @Transactional + public String findAllCategoriesByCatalogName(String catalogName) { + String res="[]"; + + Optional scopt = this.catalogRepo.findByName(catalogName); + + if (scopt.isEmpty() ) { + return res; + } + + Catalog sc = scopt.get(); + + sc.getCategoryRefs(); + + + List allcategories = this.getCategories( sc.getCategoryRefs()); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + + + try { + res = mapper.writeValueAsString( allcategories ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + return res; + + } + + + @Transactional + private List getCategories( @Valid List list) { + List categories = new ArrayList(); + + for (CategoryRef c : list ) { + Category category = this.categRepoService.findByUuid( c.getId()); + categories.add(category); + + if (category.getCategoryRefs()!=null && category.getCategoryRefs().size()>0) { + List subcategories = this.getCategories( category.getCategoryRefs() ); + categories.addAll(subcategories );//add children + } + + } + + return categories; + } + } diff --git a/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCategoryRepoService.java b/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCategoryRepoService.java index 60ebcca044262ec1f144f26d8f63ca2e01d46891..c7e226c03bbea2d617b95b6c1c4dae13b8820053 100644 --- a/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCategoryRepoService.java +++ b/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductCategoryRepoService.java @@ -26,39 +26,41 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule; import org.etsi.osl.tmf.common.model.ELifecycle; import org.etsi.osl.tmf.common.model.TimePeriod; +import org.etsi.osl.tmf.common.model.service.ServiceSpecificationRef; import org.etsi.osl.tmf.pcm620.model.Category; import org.etsi.osl.tmf.pcm620.model.CategoryCreate; import org.etsi.osl.tmf.pcm620.model.CategoryRef; import org.etsi.osl.tmf.pcm620.model.CategoryUpdate; import org.etsi.osl.tmf.pcm620.model.ProductOffering; import org.etsi.osl.tmf.pcm620.model.ProductOfferingRef; +import org.etsi.osl.tmf.pcm620.model.ProductSpecificationRef; import org.etsi.osl.tmf.pcm620.repo.ProductCatalogRepository; import org.etsi.osl.tmf.pcm620.repo.ProductCategoriesRepository; import org.etsi.osl.tmf.pcm620.repo.ProductOfferingRepository; +import org.etsi.osl.tmf.scm633.model.ServiceCandidate; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import jakarta.persistence.EntityManagerFactory; import jakarta.validation.Valid; @Service public class ProductCategoryRepoService { - @Autowired - ProductCategoriesRepository categsRepo; - - @Autowired - ProductCatalogRepository catalogRepo; + private final ProductCategoriesRepository categsRepo; - @Autowired - ProductOfferingRepository prodsOfferingRepo; - - private SessionFactory sessionFactory; + private final ProductOfferingRepository prodsOfferingRepo; /** * from @@ -67,11 +69,11 @@ public class ProductCategoryRepoService { * @param factory */ @Autowired - public ProductCategoryRepoService(EntityManagerFactory factory) { - if (factory.unwrap(SessionFactory.class) == null) { - throw new NullPointerException("factory is not a hibernate factory"); - } - this.sessionFactory = factory.unwrap(SessionFactory.class); + public ProductCategoryRepoService( ProductCategoriesRepository categsRepo, + ProductOfferingRepository prodsOfferingRepo) { + + this.categsRepo = categsRepo; + this.prodsOfferingRepo = prodsOfferingRepo; } @@ -100,28 +102,31 @@ public class ProductCategoryRepoService { } - public Category findByIdEager(String id) { -// Optional optionalCat = this.categsRepo.findByIdEager( id ); -// return optionalCat -// .orElse(null); - - Session session = sessionFactory.openSession(); - Transaction tx = session.beginTransaction(); - Category dd = null; - try { - dd = (Category) session.get(Category.class, id); - Hibernate.initialize( dd.getCategoryObj() ); - Hibernate.initialize( dd.getProductOfferingRefs() ); - for (ProductOfferingRef sc : dd.getProductOfferingRefs()) { - Hibernate.initialize(sc ); - } - - tx.commit(); - } finally { - session.close(); - } - return dd; - } + @Transactional + public String findByIdEager(String id) { + Category sc = this.findByUuid( id ); + + String res= "{}"; + + if ( sc == null ) { + return res; + } + + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + + try { + res = mapper.writeValueAsString( sc ); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + + return res; + } @@ -321,4 +326,35 @@ public class ProductCategoryRepoService { return optionalCat .orElse(null); } + + @Transactional + public String findAllProductOfferingsByCategId(String categoryId) { + + + String res="[]"; + List productSpecificationRefList = new ArrayList<>(); + Category category = this.findByUuid(categoryId); + + if ( category == null ) { + return res; + } + + Set proffs = category.getProductOfferingObj(); + + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + + try { + res = mapper.writeValueAsString( proffs ); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + + return res; + + } } diff --git a/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductOfferingRepoService.java b/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductOfferingRepoService.java index 40176d7b632d3795da8fa4b598a4fdfd4d25ea4c..942d0e7d91331ea7958797bf88af6814d2996736 100644 --- a/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductOfferingRepoService.java +++ b/src/main/java/org/etsi/osl/tmf/pcm620/reposervices/ProductOfferingRepoService.java @@ -26,18 +26,20 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import org.etsi.osl.tmf.JsonUtils; +import java.util.StringJoiner; +import java.util.stream.Collectors; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule; import org.etsi.osl.tmf.am651.model.AgreementRef; import org.etsi.osl.tmf.common.model.Any; import org.etsi.osl.tmf.common.model.AttachmentRefOrValue; import org.etsi.osl.tmf.common.model.ELifecycle; import org.etsi.osl.tmf.common.model.TimePeriod; -import org.etsi.osl.tmf.common.model.service.ServiceSpecificationRef; import org.etsi.osl.tmf.pcm620.model.BundledProductOffering; import org.etsi.osl.tmf.pcm620.model.ProductOffering; import org.etsi.osl.tmf.pcm620.model.ProductOfferingCreate; @@ -50,8 +52,6 @@ import org.etsi.osl.tmf.pcm620.model.ProductSpecificationCharacteristicValueUse; import org.etsi.osl.tmf.pcm620.model.ProductSpecificationCreate; import org.etsi.osl.tmf.pcm620.model.ProductSpecificationRef; import org.etsi.osl.tmf.pcm620.repo.ProductOfferingRepository; -import org.etsi.osl.tmf.pcm620.repo.ProductSpecificationRepository; -import org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristicValue; import org.etsi.osl.tmf.scm633.model.ServiceSpecification; import org.etsi.osl.tmf.scm633.reposervices.ServiceSpecificationRepoService; import org.hibernate.Hibernate; @@ -142,15 +142,14 @@ public class ProductOfferingRepoService { } sql += " FROM ProductOffering s"; - if (allParams.size() > 0) { - sql += " WHERE "; - for (String pname : allParams.keySet()) { - sql += " " + pname + " LIKE "; - String pval = URLDecoder.decode(allParams.get(pname), StandardCharsets.UTF_8.toString()); - sql += "'" + pval + "'"; - } - - } + if (allParams.size() > 0) { + String items = allParams.entrySet() + .stream() + .map(entry -> "s." + entry.getKey() + " LIKE '%" + URLDecoder.decode( entry.getValue(), StandardCharsets.UTF_8 )+ "%'" ) + .collect(Collectors.joining(" OR ")); + sql += " WHERE " + items; + + } sql += " ORDER BY s.name"; @@ -632,5 +631,124 @@ public class ProductOfferingRepoService { return pOffer; } + + + @Transactional + public String searchProductOfferings(List searchText) { + String res = "[]"; + + try { + + List specs= this.searchOfferingsInCategories( searchText); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + res = mapper.writeValueAsString( specs ); + + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + + return res; + } + + + /** + * + * This findAll is optimized on fields. + * @param fields + * @param allParams + * @return + * @throws UnsupportedEncodingException + */ + @Transactional + public List searchOfferingsInCategories( List searchList ) + throws UnsupportedEncodingException { + + if ( searchList == null || searchList.size() ==0) { + return new ArrayList<>(); + } + + Session session = sessionFactory.openSession(); + Transaction tx = session.beginTransaction(); + + try { + String sql = "SELECT p.id as productOfferingId, p.name as productName, p.description as productDescription"; + + + + sql += " FROM ProductCategory as pcateg JOIN pcateg.productOffObj as p "; + sql += " WHERE " ; + + + // Build the name LIKE clause + StringJoiner nameJoiner = new StringJoiner(" AND "); + for (String term : searchList) { + nameJoiner.add("p.name LIKE '%" + term + "%'"); + } + + // Build the description LIKE clause + StringJoiner descriptionJoiner = new StringJoiner(" AND "); + for (String term : searchList) { + descriptionJoiner.add("p.description LIKE '%" + term + "%'"); + } + + // Combine both clauses with OR + sql += "(" + nameJoiner.toString() + ") OR (" + descriptionJoiner.toString() + ")"; + + sql += " ORDER BY p.name"; + +// List specs = session +// .createQuery( sql, ServiceSpecification.class) +// .getResultList(); + + + List mapaEntity = session + .createQuery(sql ) + .setResultTransformer( new ResultTransformer() { + + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + Map result = new LinkedHashMap(tuple.length); + for (int i = 0; i < tuple.length; i++) { + String alias = aliases[i]; + if (alias != null) { + if (alias.equals("type")) { + alias = "@type"; + } + result.put(alias, tuple[i]); + } + } + + return result; + } + + @Override + public List transformList(List collection) { + return collection; + } + } ) + .list(); + +// //this will fetch the whole object fields + + + return mapaEntity; + + + + + } finally { + tx.commit(); + session.close(); + } + + } } diff --git a/src/main/java/org/etsi/osl/tmf/pm628/api/MeasurementCollectionJobApiRouteBuilder.java b/src/main/java/org/etsi/osl/tmf/pm628/api/MeasurementCollectionJobApiRouteBuilder.java index b8fbcca3e6274e3a625dcd4ba4440b3f5dc43959..ed20d281d98f63037f95733aa1719d879cbb3a93 100644 --- a/src/main/java/org/etsi/osl/tmf/pm628/api/MeasurementCollectionJobApiRouteBuilder.java +++ b/src/main/java/org/etsi/osl/tmf/pm628/api/MeasurementCollectionJobApiRouteBuilder.java @@ -3,7 +3,6 @@ package org.etsi.osl.tmf.pm628.api; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.camel.LoggingLevel; -import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.dataformat.JsonLibrary; import org.apache.commons.logging.Log; @@ -12,7 +11,6 @@ import org.etsi.osl.centrallog.client.CentralLogger; import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJobFVO; import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJobMVO; import org.etsi.osl.tmf.pm628.reposervices.MeasurementCollectionJobService; -import org.etsi.osl.tmf.pm628.api.MeasurementCollectionJobApiRouteBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -41,8 +39,8 @@ public class MeasurementCollectionJobApiRouteBuilder extends RouteBuilder { @Value("${PM_MEASUREMENT_COLLECTION_JOB_UPDATE}") private String PM_UPDATE_MEASUREMENT_COLLECTION_JOB; - @Autowired - private ProducerTemplate template; + @Value("${PM_MEASUREMENT_COLLECTION_JOB_GET_INPROGRESS_OR_PENDING}") + private String PM_MEASUREMENT_COLLECTION_JOB_GET_INPROGRESS_OR_PENDING; @Autowired MeasurementCollectionJobService measurementCollectionJobService; @@ -53,16 +51,17 @@ public class MeasurementCollectionJobApiRouteBuilder extends RouteBuilder { @Override public void configure() throws Exception { from(PM_GET_MEASUREMENT_COLLECTION_JOBS) - .log(LoggingLevel.INFO, log, PM_GET_MEASUREMENT_COLLECTION_JOBS + " message received!") - .to("log:DEBUG?showBody=true&showHeaders=true") - .bean(measurementCollectionJobService, "findAllMeasurementCollectionJobs") - .convertBodyTo( String.class ); + .log(LoggingLevel.INFO, log, PM_GET_MEASUREMENT_COLLECTION_JOBS + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean(measurementCollectionJobService, "findAllMeasurementCollectionJobs") + .convertBodyTo(String.class); + from(PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID) - .log(LoggingLevel.INFO, log, PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID + " message received!") - .to("log:DEBUG?showBody=true&showHeaders=true") - .bean(measurementCollectionJobService, "findMeasurementCollectionJobByUuidEagerAsString") - .convertBodyTo( String.class ); + .log(LoggingLevel.INFO, log, PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean(measurementCollectionJobService, "findMeasurementCollectionJobByUuidEagerAsString") + .convertBodyTo(String.class); from(PM_ADD_MEASUREMENT_COLLECTION_JOB) .log(LoggingLevel.INFO, log, PM_ADD_MEASUREMENT_COLLECTION_JOB + " message received!") @@ -70,16 +69,29 @@ public class MeasurementCollectionJobApiRouteBuilder extends RouteBuilder { .unmarshal() .json(JsonLibrary.Jackson, MeasurementCollectionJobFVO.class, true) .bean(measurementCollectionJobService, "createMeasurementCollectionJob(${body})") - .marshal().json( JsonLibrary.Jackson) - .convertBodyTo( String.class ); + .marshal().json(JsonLibrary.Jackson) + .convertBodyTo(String.class); from(PM_UPDATE_MEASUREMENT_COLLECTION_JOB) .log(LoggingLevel.INFO, log, PM_UPDATE_MEASUREMENT_COLLECTION_JOB + " message received!") .to("log:DEBUG?showBody=true&showHeaders=true").unmarshal() .json(JsonLibrary.Jackson, MeasurementCollectionJobMVO.class, true) .bean(measurementCollectionJobService, "updateMeasurementCollectionJob(${header.mcjid}, ${body})") - .marshal().json( JsonLibrary.Jackson) - .convertBodyTo( String.class ); + .marshal().json(JsonLibrary.Jackson) + .convertBodyTo(String.class); + + from(PM_MEASUREMENT_COLLECTION_JOB_GET_INPROGRESS_OR_PENDING) + .log(LoggingLevel.INFO, log, PM_MEASUREMENT_COLLECTION_JOB_GET_INPROGRESS_OR_PENDING + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean(measurementCollectionJobService, "findPendingOrInProgressMeasurementCollectionJobsAsJson") + .process(exchange -> { + Object body = exchange.getIn().getBody(); + if (!(body instanceof String)) { + throw new IllegalArgumentException("Unexpected body type: " + body.getClass()); + } + // Body remains as a String + exchange.getIn().setBody(body); + }); } static String toJsonString(Object object) throws IOException { diff --git a/src/main/java/org/etsi/osl/tmf/pm628/reposervices/MeasurementCollectionJobService.java b/src/main/java/org/etsi/osl/tmf/pm628/reposervices/MeasurementCollectionJobService.java index 4ca0ceaeb4875242189cd57f36867ee9984a4d92..a78a6029aa0d8d95b685dd5419bea5b6f80efb54 100755 --- a/src/main/java/org/etsi/osl/tmf/pm628/reposervices/MeasurementCollectionJobService.java +++ b/src/main/java/org/etsi/osl/tmf/pm628/reposervices/MeasurementCollectionJobService.java @@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.io.UnsupportedEncodingException; +import java.net.URI; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; @@ -456,4 +457,42 @@ public class MeasurementCollectionJobService { routeBuilderEvents.publishEvent(event, mcj.getUuid()); } + + /* + This method is creating the JSON array manually because of a bug in the object mapper where: + -> When the object mapper serializes 1 MeasurementCollectionJob it works fine + -> When the object mapper serializes a list of Measurement CollectionJob it ommits the "@type" field + As a result when de-serializing the list of MeasurementCollectionJob this error comes-up: + com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class org.etsi.osl.tmf.pm628.model.MeasurementCollectionJob]: missing type id property '@type' + */ + + @Transactional + public String findPendingOrInProgressMeasurementCollectionJobsAsJson() { + log.debug("findPendingOrInProgressMeasurementCollectionJobsAsJson"); + List pendingOrInProgressMeasurementCollectionJobs = findAllByExecutionState(ExecutionStateType.PENDING); + pendingOrInProgressMeasurementCollectionJobs.addAll(findAllByExecutionState(ExecutionStateType.INPROGRESS)); + + try { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonArray; + + List jobJsonStrings = new ArrayList<>(); + for (MeasurementCollectionJob job : pendingOrInProgressMeasurementCollectionJobs) { + jobJsonStrings.add(objectMapper.writeValueAsString(job)); + } + StringJoiner joiner = new StringJoiner(",", "[", "]"); + for (String jobStr : jobJsonStrings) { + joiner.add(jobStr); + } + jsonArray = joiner.toString(); + log.debug("Serialized JSON Array: {}", jsonArray); + + return jsonArray; + } catch (JsonProcessingException e) { + log.error("Error serializing measurement collection jobs to JSON: {}", e.getMessage()); + throw new RuntimeException("Failed to serialize jobs to JSON", e); + } + } + + } diff --git a/src/main/java/org/etsi/osl/tmf/pm632/repo/IndividualRepository.java b/src/main/java/org/etsi/osl/tmf/pm632/repo/IndividualRepository.java index 1e16ed9f435307b98ed881fab7e0b40c58aa0fe4..214a5bfd9cde3f3aac5170968b03c5ec08641458 100644 --- a/src/main/java/org/etsi/osl/tmf/pm632/repo/IndividualRepository.java +++ b/src/main/java/org/etsi/osl/tmf/pm632/repo/IndividualRepository.java @@ -22,6 +22,7 @@ package org.etsi.osl.tmf.pm632.repo; import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.pm632.model.Individual; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; @@ -40,4 +41,10 @@ public interface IndividualRepository extends CrudRepository, Optional findByPreferredGivenName(String username); + //Methods for metrics + + @Query("SELECT COUNT(ind) FROM Individual ind") + int countAll(); + + } diff --git a/src/main/java/org/etsi/osl/tmf/rcm634/repo/ResourceSpecificationRepository.java b/src/main/java/org/etsi/osl/tmf/rcm634/repo/ResourceSpecificationRepository.java index 456b890768270f1806cade84f393def6d17cd299..c7726f9bb4b0661244d3c8ab18f9d6c6e9636d4b 100644 --- a/src/main/java/org/etsi/osl/tmf/rcm634/repo/ResourceSpecificationRepository.java +++ b/src/main/java/org/etsi/osl/tmf/rcm634/repo/ResourceSpecificationRepository.java @@ -52,4 +52,12 @@ public interface ResourceSpecificationRepository extends CrudRepository findAllPhysical(); + // Methods for metrics + + @Query("SELECT COUNT(sc) FROM LogicalRspec sc") + int countLogical(); + + @Query("SELECT COUNT(sc) FROM PhysicalRspec sc") + int countPhysical(); + } diff --git a/src/main/java/org/etsi/osl/tmf/ri639/repo/ResourceRepository.java b/src/main/java/org/etsi/osl/tmf/ri639/repo/ResourceRepository.java index 446a04ca1c4193c892f0f27ece6d20126ac148cf..c324cad99e2a734d147fc881981f769e9c726244 100644 --- a/src/main/java/org/etsi/osl/tmf/ri639/repo/ResourceRepository.java +++ b/src/main/java/org/etsi/osl/tmf/ri639/repo/ResourceRepository.java @@ -19,9 +19,11 @@ */ package org.etsi.osl.tmf.ri639.repo; +import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.ri639.model.Resource; +import org.etsi.osl.tmf.ri639.model.ResourceStatusType; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -56,4 +58,18 @@ public interface ResourceRepository extends JpaRepository { List findByNameAndResourceVersion(String aname, String aversion); List findByNameAndCategoryAndResourceVersion(String aname, String acategory, String aversion); + + + // Methods for metrics + + @Query("SELECT COUNT(res) FROM RIResource res") + int countAll(); + + int countByResourceStatus(ResourceStatusType status); + + @Query("SELECT res.resourceStatus, COUNT(res) FROM RIResource res " + + "WHERE res.startOperatingDate >= :starttime AND res.endOperatingDate <= :endtime " + + "GROUP BY res.resourceStatus") + List groupByStateBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); + } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceCatalogApiRouteBuilder.java b/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceCatalogApiRouteBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..afa3892c5eaee8f732aab0b7e3a8d65b316de67d --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceCatalogApiRouteBuilder.java @@ -0,0 +1,135 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 - 2020 openslice.io + * %% + * 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. + * =========================LICENSE_END================================== + */ +package org.etsi.osl.tmf.scm633.api; + +import java.io.IOException; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreate; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationUpdate; +import org.etsi.osl.tmf.scm633.reposervices.CatalogRepoService; +import org.etsi.osl.tmf.scm633.reposervices.CategoryRepoService; +import org.etsi.osl.tmf.scm633.reposervices.ServiceSpecificationRepoService; +import org.etsi.osl.tmf.sim638.model.ServiceCreate; +import org.etsi.osl.tmf.sim638.model.ServiceUpdate; +import org.etsi.osl.tmf.so641.api.ServiceOrderApiRouteBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Configuration +//@RefreshScope +@Component +public class ServiceCatalogApiRouteBuilder extends RouteBuilder { + + private static final transient Log logger = LogFactory.getLog(ServiceCatalogApiRouteBuilder.class.getName()); + + + + @Value("${CATALOG_GET_SERVICECATALOGS}") + private String CATALOG_GET_SERVICECATALOGS = ""; + + @Value("${CATALOG_GET_SERVICECATALOG_BY_ID}") + private String CATALOG_GET_SERVICECATALOG_BY_ID = ""; + + @Value("${CATALOG_GET_SERVICECATALOG_BY_NAME}") + private String CATALOG_GET_SERVICECATALOG_BY_NAME = ""; + + @Value("${CATALOG_GET_SERVICECATEGORIES}") + private String CATALOG_GET_SERVICECATEGORIES = ""; + + @Value("${CATALOG_GET_SERVICECATEGORY_BY_ID}") + private String CATALOG_GET_SERVICECATEGORY_BY_ID = ""; + + + @Value("${CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID}") + private String CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID = ""; + + + + + @Autowired + CatalogRepoService catalogRepoService; + + + @Autowired + CategoryRepoService categoryRepoService; + + + @Override + public void configure() throws Exception { + + from( CATALOG_GET_SERVICECATALOG_BY_ID ) + .log(LoggingLevel.INFO, log, CATALOG_GET_SERVICECATALOG_BY_ID + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findByUuidEager(${header.catalogId})"); + + from( CATALOG_GET_SERVICECATALOGS ) + .log(LoggingLevel.INFO, log, CATALOG_GET_SERVICECATALOGS + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findAllEager()"); + + from( CATALOG_GET_SERVICECATALOG_BY_NAME ) + .log(LoggingLevel.INFO, log, CATALOG_GET_SERVICECATALOG_BY_NAME + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findByNameEager(${header.catalogName})") + .marshal().json( JsonLibrary.Jackson, String.class) + .convertBodyTo( String.class ); + + + from( CATALOG_GET_SERVICECATEGORIES ) + .log(LoggingLevel.INFO, log, CATALOG_GET_SERVICECATEGORIES + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( catalogRepoService, "findAllCategoriesByCatalogName(${header.catalogName})"); + + + from( CATALOG_GET_SERVICECATEGORY_BY_ID ) + .log(LoggingLevel.INFO, log, CATALOG_GET_SERVICECATEGORY_BY_ID + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( categoryRepoService, "findByIdEager(${header.catalogId})"); + + + from( CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID ) + .log(LoggingLevel.INFO, log, CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .bean( categoryRepoService, "findAllServiceSpecRefsByCategId(${header.categoryId})"); + + } + + + + + + static T toJsonObj(String content, Class valueType) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper.readValue( content, valueType); + } + +} diff --git a/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceSpecificationApiRouteBuilder.java b/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceSpecificationApiRouteBuilder.java index 8116a38c20479395b44ff0e2e7770f470f5c7f2f..ed5f01481ad6635cb123a3e33ffaeed08a49b6d6 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceSpecificationApiRouteBuilder.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceSpecificationApiRouteBuilder.java @@ -20,7 +20,7 @@ package org.etsi.osl.tmf.scm633.api; import java.io.IOException; - +import java.util.ArrayList; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; @@ -46,7 +46,7 @@ import org.springframework.stereotype.Component; @Component public class ServiceSpecificationApiRouteBuilder extends RouteBuilder { - private static final transient Log logger = LogFactory.getLog(ServiceOrderApiRouteBuilder.class.getName()); + private static final transient Log logger = LogFactory.getLog(ServiceSpecificationApiRouteBuilder.class.getName()); @Value("${CATALOG_GET_SERVICESPEC_BY_ID}") private String CATALOG_GET_SERVICESPEC_BY_ID = ""; @@ -67,7 +67,14 @@ public class ServiceSpecificationApiRouteBuilder extends RouteBuilder { @Value("${CATALOG_UPD_EXTERNAL_SERVICESPEC}") private String CATALOG_UPD_EXTERNAL_SERVICESPEC = ""; - + + + @Value("${CATALOG_SEARCH_SERVICESPECREFS}") + private String CATALOG_SEARCH_SERVICESPECREFS = ""; + + + + @Autowired ServiceSpecificationRepoService serviceSpecificationRepoService; @@ -114,6 +121,16 @@ public class ServiceSpecificationApiRouteBuilder extends RouteBuilder { .bean( serviceSpecificationRepoService, "updateOrAddServiceSpecification(${header.serviceSpecId}, ${header.forceId}, ${body} )") .marshal().json( JsonLibrary.Jackson) .convertBodyTo( String.class ); + + + + from( CATALOG_SEARCH_SERVICESPECREFS ) + .log(LoggingLevel.INFO, log, CATALOG_SEARCH_SERVICESPECREFS + " message received!") + .to("log:DEBUG?showBody=true&showHeaders=true") + .unmarshal().json( JsonLibrary.Jackson, ArrayList.class, true) + .bean( serviceSpecificationRepoService, "searchServiceSpecRefs( ${body} )"); + + } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/repo/CandidateRepository.java b/src/main/java/org/etsi/osl/tmf/scm633/repo/CandidateRepository.java index df131d4b69dbc5c10a2a6e9107a8e5a0edab5ca6..85e56f4b7317c9259a789dbccf91fbb510dabb48 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/repo/CandidateRepository.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/repo/CandidateRepository.java @@ -19,6 +19,7 @@ */ package org.etsi.osl.tmf.scm633.repo; +import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.scm633.model.ServiceCandidate; import org.springframework.data.jpa.repository.Query; @@ -36,4 +37,8 @@ public interface CandidateRepository extends CrudRepository findByServiceSpecUuid(String id); + // Methods for metrics + @Query("SELECT sc FROM ServiceCandidate sc") + List findAll(); + } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CandidateRepoService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CandidateRepoService.java index 872a8229686fa2cf112d5769db4efb4f29281068..24cd95d1a87309f68ffe1e02e081d30bc747b59b 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CandidateRepoService.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CandidateRepoService.java @@ -39,18 +39,26 @@ import org.springframework.transaction.annotation.Transactional; import jakarta.validation.Valid; @Service +@Transactional public class CandidateRepoService { - @Autowired - CandidateRepository candidateRepo; + private final CandidateRepository candidateRepo; - @Autowired - CategoryRepoService categsRepoService; - + private final CategoryRepoService categoryRepoService; + private final ServiceSpecificationRepository serviceSpecificationRepo; + @Autowired - ServiceSpecificationRepository serviceSpecificationRepo; + public CandidateRepoService( + CandidateRepository candidateRepo, + CategoryRepoService categoryRepoService, + ServiceSpecificationRepository serviceSpecificationRepo + ) { + this.candidateRepo = candidateRepo; + this.categoryRepoService = categoryRepoService; + this.serviceSpecificationRepo = serviceSpecificationRepo; + } public ServiceCandidate addServiceCandidate( ServiceCandidate c) { @@ -153,11 +161,11 @@ public class CandidateRepoService { if ( serviceCandidateUpd.getCategory() !=null ){ for (ServiceCategoryRef sCategD : serviceCandidateUpd.getCategory()) { - ServiceCategory catObj = this.categsRepoService.findByIdEager(sCategD.getId()); + ServiceCategory catObj = this.categoryRepoService.findByUuid(sCategD.getId()); if ( catObj!=null){ catObj.getServiceCandidateObj().add(savedCand); //add candidate ref to category - catObj = this.categsRepoService.categsRepo.save(catObj); + catObj = this.categoryRepoService.getCategsRepo().save(catObj); } } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CatalogRepoService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CatalogRepoService.java index db4c70237acaab21e585f1ce3e41a0fe10b98ec2..124f96125b32cb49a85d6e6f27c3be4e0e2bb342 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CatalogRepoService.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CatalogRepoService.java @@ -21,8 +21,12 @@ package org.etsi.osl.tmf.scm633.reposervices; import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule; import org.etsi.osl.tmf.common.model.ELifecycle; import org.etsi.osl.tmf.common.model.TimePeriod; import org.etsi.osl.tmf.scm633.model.ServiceCatalog; @@ -30,12 +34,21 @@ import org.etsi.osl.tmf.scm633.model.ServiceCatalogCreate; import org.etsi.osl.tmf.scm633.model.ServiceCatalogUpdate; import org.etsi.osl.tmf.scm633.model.ServiceCategory; import org.etsi.osl.tmf.scm633.model.ServiceCategoryRef; +import org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristic; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; import org.etsi.osl.tmf.scm633.repo.CatalogRepository; +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import jakarta.persistence.EntityManagerFactory; import jakarta.validation.Valid; @Service +@Transactional public class CatalogRepoService { @@ -46,10 +59,8 @@ public class CatalogRepoService { CategoryRepoService categRepoService; @Autowired - ServiceSpecificationRepoService specRepoService; - - @Autowired - CandidateRepoService candidateRepoService; + ServiceSpecificationRepoService specRepoService; + public ServiceCatalog addCatalog(ServiceCatalog c) { @@ -64,10 +75,75 @@ public class CatalogRepoService { return this.catalogRepo.save(sc); } + public String findAllEager() { + + List oids = (List) this.catalogRepo.findByOrderByName(); + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + String res; + try { + res = mapper.writeValueAsString( oids ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return "{}"; + } + + return res; + } + + + public List findAll() { return (List) this.catalogRepo.findByOrderByName(); } + + public String findByUuidEager(String id) { + + ServiceCatalog sc = this.findById(id); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + String res; + try { + res = mapper.writeValueAsString( sc ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return "{}"; + } + + return res; + } + + + + public String findByNameEager(String aname) { + ServiceCatalog sc = this.findByName(aname); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + String res; + try { + res = mapper.writeValueAsString( sc ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return "{}"; + } + + return res; + + } + + public ServiceCatalog findById(String id) { Optional optionalCat = this.catalogRepo.findByUuid(id); return optionalCat.orElse(null); @@ -136,6 +212,65 @@ public class CatalogRepoService { public ServiceCatalog updateCatalog(ServiceCatalog scatalog) { return this.catalogRepo.save(scatalog); } + + + /** + * return recursively all categories in catalog + * @param catalogName + */ + @Transactional + public String findAllCategoriesByCatalogName(String catalogName) { + String res="[]"; + + Optional scopt = this.catalogRepo.findByName(catalogName); + + if (scopt.isEmpty() ) { + return res; + } + + ServiceCatalog sc = scopt.get(); + + sc.getCategoryRefs(); + + + List allcategories = this.getCategories( sc.getCategoryRefs()); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + + + try { + res = mapper.writeValueAsString( allcategories ); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + return res; + + } + + + @Transactional + private List getCategories( @Valid List list) { + List categories = new ArrayList(); + + for (ServiceCategoryRef c : list ) { + ServiceCategory category = this.categRepoService.findByUuid( c.getId()); + categories.add(category); + + if (category.getCategoryRefs()!=null && category.getCategoryRefs().size()>0) { + List subcategories = this.getCategories( category.getCategoryRefs() ); + categories.addAll(subcategories );//add children + } + + } + + return categories; + } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CategoryRepoService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CategoryRepoService.java index cb43791abb4ecb3c54a7414e80badeab7b6b20f6..2ebf74d01b9a64db3389e6f295fe90e46a60842b 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CategoryRepoService.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/CategoryRepoService.java @@ -23,67 +23,49 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule; import org.etsi.osl.tmf.common.model.ELifecycle; import org.etsi.osl.tmf.common.model.TimePeriod; +import org.etsi.osl.tmf.common.model.service.ServiceSpecificationRef; import org.etsi.osl.tmf.scm633.model.ServiceCandidate; import org.etsi.osl.tmf.scm633.model.ServiceCandidateRef; import org.etsi.osl.tmf.scm633.model.ServiceCategory; import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreate; import org.etsi.osl.tmf.scm633.model.ServiceCategoryRef; import org.etsi.osl.tmf.scm633.model.ServiceCategoryUpdate; -import org.etsi.osl.tmf.scm633.model.ServiceSpecCharRelationship; -import org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristic; -import org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristicValue; import org.etsi.osl.tmf.scm633.repo.CandidateRepository; -import org.etsi.osl.tmf.scm633.repo.CatalogRepository; import org.etsi.osl.tmf.scm633.repo.CategoriesRepository; -import org.hibernate.Hibernate; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import jakarta.persistence.EntityManagerFactory; +import org.springframework.transaction.annotation.Transactional; import jakarta.validation.Valid; @Service +@Transactional public class CategoryRepoService { - @Autowired - CategoriesRepository categsRepo; - - - @Autowired - CandidateRepository candidateRepo; - - @Autowired - CatalogRepository catalogRepo; + private final CategoriesRepository categsRepo; + private final CandidateRepository candidateRepo; - private SessionFactory sessionFactory; - /** - * from https://stackoverflow.com/questions/25063995/spring-boot-handle-to-hibernate-sessionfactory - * @param factory - */ - @Autowired - public CategoryRepoService(EntityManagerFactory factory) { - if(factory.unwrap(SessionFactory.class) == null){ - throw new NullPointerException("factory is not a hibernate factory"); - } - this.sessionFactory = factory.unwrap(SessionFactory.class); - } - + @Autowired + public CategoryRepoService(CategoriesRepository categsRepo, CandidateRepository candidateRepo) { + this.categsRepo = categsRepo; + this.candidateRepo = candidateRepo; + } public ServiceCategory addCategory(ServiceCategory c) { - return this.categsRepo.save( c ); + return this.getCategsRepo().save( c ); } public ServiceCategory addCategory(@Valid ServiceCategoryCreate serviceCategory) { @@ -91,71 +73,99 @@ public class CategoryRepoService { ServiceCategory sc = new ServiceCategory() ; sc = updateCategoryDataFromAPICall(sc, serviceCategory); - return this.categsRepo.save( sc ); + return this.getCategsRepo().save( sc ); } + @Transactional public List findAll() { - return (List) this.categsRepo.findByOrderByName(); + return (List) this.getCategsRepo().findByOrderByName(); } + @Transactional public ServiceCategory findByUuid(String id) { - Optional optionalCat = this.categsRepo.findByUuid( id ); + Optional optionalCat = this.getCategsRepo().findByUuid( id ); return optionalCat .orElse(null); } - public ServiceCategory findByIdEager(String id) { -// Optional optionalCat = this.categsRepo.findByIdEager( id ); -// return optionalCat -// .orElse(null); + @Transactional + public String findByIdEager(String id) { + ServiceCategory sc = this.findByUuid( id ); + + String res= "{}"; + + if ( sc == null ) { + return res; + } + - Session session = sessionFactory.openSession(); - Transaction tx = session.beginTransaction(); - ServiceCategory dd = null; - try { - dd = (ServiceCategory) session.get(ServiceCategory.class, id); - Hibernate.initialize( dd.getCategoryObj() ); - Hibernate.initialize( dd.getServiceCandidateObj() ); - for (ServiceCandidate sc : dd.getServiceCandidateObj()) { - Hibernate.initialize(sc ); - Hibernate.initialize(sc.getCategoryObj() ); - Hibernate.initialize(sc.getServiceSpecificationObj() ); - Hibernate.initialize(sc.getServiceSpecificationObj().getServiceSpecCharacteristic() ); - for (ServiceSpecCharacteristic ssc : sc.getServiceSpecificationObj().getServiceSpecCharacteristic() ) { - Hibernate.initialize(ssc.getServiceSpecCharRelationship() ); - for (ServiceSpecCharRelationship srel : ssc.getServiceSpecCharRelationship() ) { - Hibernate.initialize( srel ); - } - Hibernate.initialize(ssc.getServiceSpecCharacteristicValue() ); - for (ServiceSpecCharacteristicValue srel : ssc.getServiceSpecCharacteristicValue() ) { - Hibernate.initialize( srel ); - } - } - Hibernate.initialize(sc.getServiceSpecificationObj().getServiceSpecRelationship() ); - } - - tx.commit(); - } finally { - session.close(); - } - return dd; + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + + try { + res = mapper.writeValueAsString( sc ); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + + return res; } - + + + @Transactional + public String findAllServiceSpecRefsByCategId(String categoryId) { + + + String res="[]"; + List serviceSpecificationRefList = new ArrayList<>(); + ServiceCategory category = this.findByUuid(categoryId); + + if ( category == null ) { + return res; + } + + Set serviceCands = category.getServiceCandidateObj(); + + for (ServiceCandidate serviceCandidate : serviceCands) { + @Valid + ServiceSpecificationRef specRef = serviceCandidate.getServiceSpecificationRef(); + serviceSpecificationRefList.add(specRef); + } + + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + + try { + res = mapper.writeValueAsString( serviceSpecificationRefList ); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + + return res; + + } public boolean deleteById(String id) { - Optional optionalCat = this.categsRepo.findByUuid( id ); + Optional optionalCat = this.getCategsRepo().findByUuid( id ); if ( optionalCat.get().getCategoryObj().size()>0 ) { return false; //has children } if ( optionalCat.get().getParentId() != null ) { - ServiceCategory parentCat = (this.categsRepo.findByUuid( optionalCat.get().getParentId() )).get(); + ServiceCategory parentCat = (this.getCategsRepo().findByUuid( optionalCat.get().getParentId() )).get(); //remove from parent category for (ServiceCategory ss : parentCat.getCategoryObj()) { @@ -164,24 +174,24 @@ public class CategoryRepoService { break; } } - parentCat = this.categsRepo.save(parentCat); + parentCat = this.getCategsRepo().save(parentCat); } - this.categsRepo.delete( optionalCat.get()); + this.getCategsRepo().delete( optionalCat.get()); return true; } public ServiceCategory updateCategory(String id, @Valid ServiceCategoryUpdate serviceCategory) { - Optional optionalCat = this.categsRepo.findByUuid( id ); + Optional optionalCat = this.getCategsRepo().findByUuid( id ); if ( optionalCat == null ) { return null; } ServiceCategory sc = optionalCat.get(); sc = updateCategoryDataFromAPICall(sc, serviceCategory); - return this.categsRepo.save( sc ); + return this.getCategsRepo().save( sc ); } public ServiceCategory updateCategoryDataFromAPICall( ServiceCategory sc, ServiceCategoryUpdate serviceCatUpd ) @@ -227,14 +237,14 @@ public class CategoryRepoService { } } if (!idexists) { - Optional catToAdd = this.categsRepo.findByUuid( ref.getId() ); + Optional catToAdd = this.getCategsRepo().findByUuid( ref.getId() ); if ( catToAdd.isPresent() ) { ServiceCategory scatadd = catToAdd.get(); sc.getCategoryObj().add( scatadd ); idAddedUpdated.put( ref.getId(), true); scatadd.setParentId( sc.getUuid()); - scatadd = this.categsRepo.save( scatadd ); + scatadd = this.getCategsRepo().save( scatadd ); } } } @@ -292,10 +302,15 @@ public class CategoryRepoService { public ServiceCategory findByName(String aName) { - Optional optionalCat = this.categsRepo.findByName( aName ); + Optional optionalCat = this.getCategsRepo().findByName( aName ); return optionalCat .orElse(null); } + public CategoriesRepository getCategsRepo() { + return categsRepo; + + } + } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceSpecificationRepoService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceSpecificationRepoService.java index eb6ca09c1cf0d752a8a84412b2b5b054b6e2b2a5..9b3f2fdf4108328e2a9cfec761d327e04fb31863 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceSpecificationRepoService.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceSpecificationRepoService.java @@ -34,10 +34,12 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.StringJoiner; import java.util.UUID; - +import java.util.stream.Collectors; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; - +import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.etsi.osl.tmf.common.model.Any; @@ -62,6 +64,7 @@ import org.etsi.osl.tmf.scm633.api.ServiceSpecificationApiRouteBuilderNSD; import org.etsi.osl.tmf.scm633.model.ServiceCandidate; import org.etsi.osl.tmf.scm633.model.ServiceCandidateCreate; import org.etsi.osl.tmf.scm633.model.ServiceCandidateUpdate; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; import org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristic; import org.etsi.osl.tmf.scm633.model.ServiceSpecCharacteristicValue; import org.etsi.osl.tmf.scm633.model.ServiceSpecRelationship; @@ -208,13 +211,12 @@ public class ServiceSpecificationRepoService { } sql += " FROM ServiceSpecification s"; - if (allParams.size() > 0) { - sql += " WHERE "; - for (String pname : allParams.keySet()) { - sql += " " + pname + " LIKE "; - String pval = URLDecoder.decode(allParams.get(pname), StandardCharsets.UTF_8.toString()); - sql += "'" + pval + "'"; - } + if (allParams.size() > 0) { + String items = allParams.entrySet() + .stream() + .map(entry -> "s." + entry.getKey() + " LIKE '%" + URLDecoder.decode( entry.getValue(), StandardCharsets.UTF_8 )+ "%'" ) + .collect(Collectors.joining(" OR ")); + sql += " WHERE " + items; } sql += " ORDER BY s.name"; @@ -230,10 +232,10 @@ public class ServiceSpecificationRepoService { Map result = new LinkedHashMap(tuple.length); for (int i = 0; i < tuple.length; i++) { String alias = aliases[i]; - if (alias.equals("type")) { - alias = "@type"; - } if (alias != null) { + if (alias.equals("type")) { + alias = "@type"; + } result.put(alias, tuple[i]); } } @@ -271,7 +273,11 @@ public class ServiceSpecificationRepoService { } -// @Transactional(propagation=Propagation.REQUIRED , readOnly=true, + + + + + // @Transactional(propagation=Propagation.REQUIRED , readOnly=true, // noRollbackFor=Exception.class) public ServiceSpecification findByUuid(String id) { Optional optionalCat = this.serviceSpecificationRepo.findByUuid(id); @@ -1464,6 +1470,124 @@ public class ServiceSpecificationRepoService { } + @Transactional + public String searchServiceSpecRefs(List searchText) { + String res = "[]"; + + try { + + List specs= this.searchSpecsInCategories( searchText); + + ObjectMapper mapper = new ObjectMapper(); + // Registering Hibernate4Module to support lazy objects + // this will fetch all lazy objects before marshaling + mapper.registerModule(new Hibernate5JakartaModule()); + res = mapper.writeValueAsString( specs ); + + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + + return res; + } + + + /** + * + * This findAll is optimized on fields. + * @param fields + * @param allParams + * @return + * @throws UnsupportedEncodingException + */ + @Transactional + public List searchSpecsInCategories( List searchList ) + throws UnsupportedEncodingException { + + if ( searchList == null || searchList.size() ==0) { + return new ArrayList<>(); + } + + Session session = sessionFactory.openSession(); + Transaction tx = session.beginTransaction(); + + try { + String sql = "SELECT s.id as serviceSpecificationId, s.name as serviceName, s.description as serviceDescription"; + + + + sql += " FROM ServiceCategory as scateg JOIN scateg.serviceCandidateObj as scandidate JOIN scandidate.serviceSpecificationObj as s "; + sql += " WHERE " ; + + + // Build the name LIKE clause + StringJoiner nameJoiner = new StringJoiner(" AND "); + for (String term : searchList) { + nameJoiner.add("s.name LIKE '%" + term + "%'"); + } + + // Build the description LIKE clause + StringJoiner descriptionJoiner = new StringJoiner(" AND "); + for (String term : searchList) { + descriptionJoiner.add("s.description LIKE '%" + term + "%'"); + } + + // Combine both clauses with OR + sql += "(" + nameJoiner.toString() + ") OR (" + descriptionJoiner.toString() + ")"; + + sql += " ORDER BY s.name"; + +// List specs = session +// .createQuery( sql, ServiceSpecification.class) +// .getResultList(); + + + List mapaEntity = session + .createQuery(sql ) + .setResultTransformer( new ResultTransformer() { + + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + Map result = new LinkedHashMap(tuple.length); + for (int i = 0; i < tuple.length; i++) { + String alias = aliases[i]; + if (alias != null) { + if (alias.equals("type")) { + alias = "@type"; + } + result.put(alias, tuple[i]); + } + } + + return result; + } + + @Override + public List transformList(List collection) { + return collection; + } + } ) + .list(); + +// //this will fetch the whole object fields + + + return mapaEntity; + + + + + } finally { + tx.commit(); + session.close(); + } + + } + } diff --git a/src/main/java/org/etsi/osl/tmf/sim638/repo/ServiceRepository.java b/src/main/java/org/etsi/osl/tmf/sim638/repo/ServiceRepository.java index 8c920375ad11b35fcd9eb5ad794f3e029ad6f839..ee3d9c3b56894e9b87299d26465af958924dce54 100644 --- a/src/main/java/org/etsi/osl/tmf/sim638/repo/ServiceRepository.java +++ b/src/main/java/org/etsi/osl/tmf/sim638/repo/ServiceRepository.java @@ -19,8 +19,11 @@ */ package org.etsi.osl.tmf.sim638.repo; +import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; + +import org.etsi.osl.tmf.common.model.service.ServiceStateType; import org.etsi.osl.tmf.sim638.model.Service; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -68,4 +71,15 @@ public interface ServiceRepository extends JpaRepository { + "WHERE sres.id = ?1 " ) List findServicesHavingThisSupportingResourceID(String resourceID); + // Methods for metrics + + @Query("SELECT COUNT(srv) FROM Service srv") + int countAll(); + + int countByState(ServiceStateType state); + + @Query("SELECT srv.state, COUNT(srv) FROM Service srv " + + "WHERE srv.startDate >= :starttime AND srv.endDate <= :endtime " + + "GROUP BY srv.state") + List groupByStateBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); } diff --git a/src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java b/src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java index c717e063b2fd3728703133654adcc4f3a58e6e04..b6ee5c83b42f86826ac670677dbbd7858dfa57d0 100644 --- a/src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java +++ b/src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java @@ -19,6 +19,7 @@ */ package org.etsi.osl.tmf.so641.repo; +import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.common.model.UserPartRoleType; @@ -51,4 +52,27 @@ public interface ServiceOrderRepository extends JpaRepository findNotesOfServOrder(String id); + + + // Methods for metrics + + @Query("SELECT COUNT(sor) FROM ServiceOrder sor") + int countAll(); + + int countByState(ServiceOrderStateType state); + + @Query("SELECT COUNT(sor) FROM ServiceOrder sor " + + "WHERE sor.state IN :states " + + "AND sor.requestedStartDate < :currentDate AND sor.requestedCompletionDate > :currentDate") + int countAllActive(OffsetDateTime currentDate, List states); + + @Query("SELECT sor.state, COUNT(sor) FROM ServiceOrder sor " + + "WHERE sor.orderDate >= :starttime AND sor.orderDate <= :endtime " + + "GROUP BY sor.state") + List groupByStateBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); + + @Query("SELECT sor.orderDate FROM ServiceOrder sor " + + "WHERE sor.orderDate >= :starttime AND sor.orderDate <= :endtime") + List getOrderDatesBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); + } diff --git a/src/main/resources/application-testing.yml b/src/main/resources/application-testing.yml index 0ec537c55d1b5267645cb41bb7d15cba12837e4b..dc15a9c271e512228cced92f454f39da56b09f55 100644 --- a/src/main/resources/application-testing.yml +++ b/src/main/resources/application-testing.yml @@ -80,15 +80,57 @@ oauthsign: key: "XXX" #QUEUE MESSAGES -CATALOG_GET_SERVICEORDERS: "jms:queue:CATALOG.GET.SERVICEORDERS" -CATALOG_GET_SERVICEORDER_BY_ID: "jms:queue:CATALOG.GET.SERVICEORDER_BY_ID" -CATALOG_ADD_SERVICEORDER: "jms:queue:CATALOG.ADD.SERVICEORDER" -CATALOG_UPD_SERVICEORDER_BY_ID: "jms:queue:CATALOG.UPD.SERVICEORDER_BY_ID" CATALOG_GET_SERVICESPEC_BY_ID: "jms:queue:CATALOG.GET.SERVICESPEC_BY_ID" CATALOG_ADD_SERVICESPEC: "jms:queue:CATALOG.ADD.SERVICESPEC" CATALOG_UPD_SERVICESPEC: "jms:queue:CATALOG.UPD.SERVICESPEC" CATALOG_UPDADD_SERVICESPEC: "jms:queue:CATALOG.UPDADD.SERVICESPEC" +CATALOG_SERVICE_QUEUE_ITEMS_GET: "jms:queue:CATALOG.SERVICEQUEUEITEMS.GET" +CATALOG_SERVICE_QUEUE_ITEM_UPD: "jms:queue:CATALOG.SERVICEQUEUEITEM.UPDATE" +CATALOG_SERVICE_QUEUE_ITEM_DELETE: "jms:queue:CATALOG.SERVICEQUEUEITEM.DELETE" +CATALOG_GET_PARTNER_ORGANIZATON_BY_ID: "jms:queue:CATALOG.GET.PARTNER_ORGANIZATION_BY_ID" +CATALOG_UPDATE_PARTNER_ORGANIZATION: "jms:queue:CATALOG.UPD.PARTNER_ORGANIZATION" +CATALOG_SERVICES_TO_TERMINATE: "jms:queue:CATALOG.GET.SERVICETOTERMINATE" +CATALOG_SERVICES_OF_PARTNERS: "jms:queue:CATALOG.GET.SERVICESOFPARTNERS" +CATALOG_GET_EXTERNAL_SERVICE_PARTNERS: "jms:queue:CATALOG.GET.EXTERNALSERVICEPARTNERS" +CATALOG_UPD_EXTERNAL_SERVICESPEC: "jms:queue:CATALOG.UPD.EXTERNAL_SERVICESPEC" + +#SERVICE_INVENTORY +CATALOG_ADD_SERVICE: "jms:queue:CATALOG.ADD.SERVICE" +CATALOG_UPD_SERVICE: "jms:queue:CATALOG.UPD.SERVICE" +CATALOG_GET_SERVICE_BY_ID: "jms:queue:CATALOG.GET.SERVICE" +CATALOG_GET_SERVICE_BY_ORDERID: "jms:queue:CATALOG.GET.SERVICE_BY_ORDERID" + + +#SERVICE ORDERS +CATALOG_GET_SERVICEORDERS: "jms:queue:CATALOG.GET.SERVICEORDERS" +CATALOG_GET_SERVICEORDER_BY_ID: "jms:queue:CATALOG.GET.SERVICEORDER_BY_ID" +CATALOG_ADD_SERVICEORDER: "jms:queue:CATALOG.ADD.SERVICEORDER" +CATALOG_UPD_SERVICEORDER_BY_ID: "jms:queue:CATALOG.UPD.SERVICEORDER_BY_ID" +CATALOG_GET_INITIAL_SERVICEORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_SERVICEORDERS" +CATALOG_GET_SERVICEORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_SERVICEORDERS" +CATALOG_GET_PRODUCTCATALOGS: "jms:queue:CATALOG.GET.PRODUCTCATALOGS" +CATALOG_GET_PRODUCTCATALOG_BY_ID: "jms:queue:CATALOG.GET.PRODUCTCATALOG_BY_ID" +CATALOG_GET_PRODUCTCATALOG_BY_NAME: "jms:queue:CATALOG.GET.PRODUCTCATALOG_BY_NAME" +CATALOG_GET_PRODUCTCATEGORIES: "jms:queue:CATALOG.GET.PRODUCTCATEGORIES" +CATALOG_GET_PRODUCTCATEGORY_BY_ID: "jms:queue:CATALOG.GET.PRODUCTCATEGORY_BY_ID" +CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID: "jms:queue:CATALOG.GET.PRODUCTOFFERINGS.CATEGORY_ID" +CATALOG_SEARCH_PRODUCTOFFERINGS: "jms:queue:CATALOG.CATALOG_SEARCH_PRODUCTOFFERINGS" + + +#SERVICE CATALOGS, CATEGORIES +CATALOG_GET_SERVICECATALOGS: "jms:queue:CATALOG.GET.SERVICECATALOGS" +CATALOG_GET_SERVICECATALOG_BY_ID: "jms:queue:CATALOG.GET.SERVICECATALOG_BY_ID" +CATALOG_GET_SERVICECATALOG_BY_NAME: "jms:queue:CATALOG.GET.SERVICECATALOG_BY_NAME" + +CATALOG_GET_SERVICECATEGORIES: "jms:queue:CATALOG.GET.SERVICECATEGORIES" +CATALOG_GET_SERVICECATEGORY_BY_ID: "jms:queue:CATALOG.GET.SERVICECATEGORY_BY_ID" + +CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID: "jms:queue:CATALOG.GETSERVICESPECREFS.SERVICECATEGORY_BY_ID" +CATALOG_SEARCH_SERVICESPECREFS: "jms:queue:CATALOG.CATALOG_SEARCH_SERVICESPECREFS" + + +#PRODUCT CATALOGS CATALOG_GET_PRODUCTSPEC_BY_ID: "jms:queue:CATALOG.GET.PRODUCTSPEC_BY_ID" CATALOG_ADD_PRODUCTSPEC: "jms:queue:CATALOG.ADD.PRODUCTSPEC" CATALOG_UPD_PRODUCTSPEC: "jms:queue:CATALOG.UPD.PRODUCTSPEC" @@ -100,29 +142,17 @@ CATALOG_ADD_PRODUCTORDER: "jms:queue:CATALOG.ADD.PRODUCTORDER" CATALOG_UPD_PRODUCTORDER_BY_ID: "jms:queue:CATALOG.UPD.PRODUCTORDER_BY_ID" CATALOG_GET_INITIAL_PRODUCTORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_PRODUCTORDERS" CATALOG_GET_PRODUCTORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_PRODUCTORDERS" -CATALOG_GET_INITIAL_SERVICEORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_SERVICEORDERS" -CATALOG_GET_SERVICEORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_SERVICEORDERS" -CATALOG_ADD_SERVICE: "jms:queue:CATALOG.ADD.SERVICE" -CATALOG_UPD_SERVICE: "jms:queue:CATALOG.UPD.SERVICE" -CATALOG_GET_SERVICE_BY_ID: "jms:queue:CATALOG.GET.SERVICE" -CATALOG_GET_SERVICE_BY_ORDERID: "jms:queue:CATALOG.GET.SERVICE_BY_ORDERID" -CATALOG_SERVICE_QUEUE_ITEMS_GET: "jms:queue:CATALOG.SERVICEQUEUEITEMS.GET" -CATALOG_SERVICE_QUEUE_ITEM_UPD: "jms:queue:CATALOG.SERVICEQUEUEITEM.UPDATE" -CATALOG_SERVICE_QUEUE_ITEM_DELETE: "jms:queue:CATALOG.SERVICEQUEUEITEM.DELETE" -CATALOG_GET_PARTNER_ORGANIZATON_BY_ID: "jms:queue:CATALOG.GET.PARTNER_ORGANIZATION_BY_ID" -CATALOG_UPDATE_PARTNER_ORGANIZATION: "jms:queue:CATALOG.UPD.PARTNER_ORGANIZATION" -CATALOG_SERVICES_TO_TERMINATE: "jms:queue:CATALOG.GET.SERVICETOTERMINATE" -CATALOG_SERVICES_OF_PARTNERS: "jms:queue:CATALOG.GET.SERVICESOFPARTNERS" -CATALOG_GET_EXTERNAL_SERVICE_PARTNERS: "jms:queue:CATALOG.GET.EXTERNALSERVICEPARTNERS" -CATALOG_UPD_EXTERNAL_SERVICESPEC: "jms:queue:CATALOG.UPD.EXTERNAL_SERVICESPEC" + + +#PM_MEASUREMENT_COLLECTION PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.GET_BY_ID" PM_MEASUREMENT_COLLECTION_JOBS_GET: "jms:queue:PM.MEASUREMENTCOLLECTIONJOBS.GET" PM_MEASUREMENT_COLLECTION_JOB_ADD: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.ADD" PM_MEASUREMENT_COLLECTION_JOB_CREATED: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.CREATED" PM_MEASUREMENT_COLLECTION_JOB_UPDATE: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.UPDATE" - +PM_MEASUREMENT_COLLECTION_JOB_GET_INPROGRESS_OR_PENDING: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.GET_INPROGRESS_OR_PENDING" #ALARMS ALARMS_ADD_ALARM: "jms:queue:ALARMS.ADD.ALARM" @@ -157,7 +187,9 @@ EVENT_PRODUCT_ORDER_ATTRIBUTE_VALUE_CHANGED: "jms:topic:EVENT.PRODUCTORDER.ATTRC #QUEUE MESSSAGES WITH VNFNSD CATALOG NFV_CATALOG_GET_NSD_BY_ID: "jms:queue:NFVCATALOG.GET.NSD_BY_ID" -GET_USER_BY_USERNAME: "direct:get_user_byusername" + +#MISC +GET_USER_BY_USERNAME: "jms:queue:GET.USER_BY_USERNAME" #RESOURCES MESSAGES CATALOG_ADD_RESOURCE: "jms:queue:CATALOG.ADD.RESOURCE" @@ -181,7 +213,6 @@ CATALOG_UPD_RESOURCEACTIVATION: "jms:queue:CATALOG.UPD.RESOURCEACTIVATION" CATALOG_UPDADD_RESOURCEACTIVATION: "jms:queue:CATALOG.UPDADD.RESOURCEACTIVATION" CATALOG_GET_RESOURCEACTIVATION_BY_ID: "jms:queue:CATALOG.GET.RESOURCEACTIVATION" - #LCM MESSAGES CATALOG_GET_LCMRULE_BY_ID: "jms:queue:CATALOG.GET.LCMRULE" CATALOG_GET_LCMRULES_BY_SPECID_PHASE: "jms:queue:CATALOG.GET.LCMRULES_BY_SPECID_PHASE" @@ -200,3 +231,8 @@ NFV_CATALOG_NS_LCMCHANGED: "jms:topic:NFV_CATALOG_NS_LCMCHANGED" #RESERVATION_API RESERVATION_CREATE: "jms:queue:RESERVATION.ADD" RESERVATION_AVAILABILITY_CHECK: "jms:queue:RESERVATION.AVAILABILITYCHECK" + + +--- + + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3722fa870b9ede79c840948872329f4e8874fd5a..dc4f0ce805b2dccea5a1762bd78947b7093795be 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -111,15 +111,46 @@ oauthsign: key: "EK97Y7Y9WPGG1MEG" #QUEUE MESSAGES -CATALOG_GET_SERVICEORDERS: "jms:queue:CATALOG.GET.SERVICEORDERS" -CATALOG_GET_SERVICEORDER_BY_ID: "jms:queue:CATALOG.GET.SERVICEORDER_BY_ID" -CATALOG_ADD_SERVICEORDER: "jms:queue:CATALOG.ADD.SERVICEORDER" -CATALOG_UPD_SERVICEORDER_BY_ID: "jms:queue:CATALOG.UPD.SERVICEORDER_BY_ID" CATALOG_GET_SERVICESPEC_BY_ID: "jms:queue:CATALOG.GET.SERVICESPEC_BY_ID" CATALOG_ADD_SERVICESPEC: "jms:queue:CATALOG.ADD.SERVICESPEC" CATALOG_UPD_SERVICESPEC: "jms:queue:CATALOG.UPD.SERVICESPEC" CATALOG_UPDADD_SERVICESPEC: "jms:queue:CATALOG.UPDADD.SERVICESPEC" +CATALOG_SERVICE_QUEUE_ITEMS_GET: "jms:queue:CATALOG.SERVICEQUEUEITEMS.GET" +CATALOG_SERVICE_QUEUE_ITEM_UPD: "jms:queue:CATALOG.SERVICEQUEUEITEM.UPDATE" +CATALOG_SERVICE_QUEUE_ITEM_DELETE: "jms:queue:CATALOG.SERVICEQUEUEITEM.DELETE" +CATALOG_GET_PARTNER_ORGANIZATON_BY_ID: "jms:queue:CATALOG.GET.PARTNER_ORGANIZATION_BY_ID" +CATALOG_UPDATE_PARTNER_ORGANIZATION: "jms:queue:CATALOG.UPD.PARTNER_ORGANIZATION" +CATALOG_SERVICES_TO_TERMINATE: "jms:queue:CATALOG.GET.SERVICETOTERMINATE" +CATALOG_SERVICES_OF_PARTNERS: "jms:queue:CATALOG.GET.SERVICESOFPARTNERS" +CATALOG_GET_EXTERNAL_SERVICE_PARTNERS: "jms:queue:CATALOG.GET.EXTERNALSERVICEPARTNERS" +CATALOG_UPD_EXTERNAL_SERVICESPEC: "jms:queue:CATALOG.UPD.EXTERNAL_SERVICESPEC" + +#SERVICE_INVENTORY +CATALOG_ADD_SERVICE: "jms:queue:CATALOG.ADD.SERVICE" +CATALOG_UPD_SERVICE: "jms:queue:CATALOG.UPD.SERVICE" +CATALOG_GET_SERVICE_BY_ID: "jms:queue:CATALOG.GET.SERVICE" +CATALOG_GET_SERVICE_BY_ORDERID: "jms:queue:CATALOG.GET.SERVICE_BY_ORDERID" + + +#SERVICE ORDERS +CATALOG_GET_SERVICEORDERS: "jms:queue:CATALOG.GET.SERVICEORDERS" +CATALOG_GET_SERVICEORDER_BY_ID: "jms:queue:CATALOG.GET.SERVICEORDER_BY_ID" +CATALOG_ADD_SERVICEORDER: "jms:queue:CATALOG.ADD.SERVICEORDER" +CATALOG_UPD_SERVICEORDER_BY_ID: "jms:queue:CATALOG.UPD.SERVICEORDER_BY_ID" +CATALOG_GET_INITIAL_SERVICEORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_SERVICEORDERS" +CATALOG_GET_SERVICEORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_SERVICEORDERS" + +#SERVICE CATALOGS, CATEGORIES +CATALOG_GET_SERVICECATALOGS: "jms:queue:CATALOG.GET.SERVICECATALOGS" +CATALOG_GET_SERVICECATALOG_BY_ID: "jms:queue:CATALOG.GET.SERVICECATALOG_BY_ID" +CATALOG_GET_SERVICECATALOG_BY_NAME: "jms:queue:CATALOG.GET.SERVICECATALOG_BY_NAME" +CATALOG_GET_SERVICECATEGORIES: "jms:queue:CATALOG.GET.SERVICECATEGORIES" +CATALOG_GET_SERVICECATEGORY_BY_ID: "jms:queue:CATALOG.GET.SERVICECATEGORY_BY_ID" +CATALOG_GET_SERVICESPECREFS_BYCATEGORY_ID: "jms:queue:CATALOG.GETSERVICESPECREFS.SERVICECATEGORY_BY_ID" +CATALOG_SEARCH_SERVICESPECREFS: "jms:queue:CATALOG.CATALOG_SEARCH_SERVICESPECREFS" + +#PRODUCT CATALOGS CATALOG_GET_PRODUCTSPEC_BY_ID: "jms:queue:CATALOG.GET.PRODUCTSPEC_BY_ID" CATALOG_ADD_PRODUCTSPEC: "jms:queue:CATALOG.ADD.PRODUCTSPEC" CATALOG_UPD_PRODUCTSPEC: "jms:queue:CATALOG.UPD.PRODUCTSPEC" @@ -131,30 +162,22 @@ CATALOG_ADD_PRODUCTORDER: "jms:queue:CATALOG.ADD.PRODUCTORDER" CATALOG_UPD_PRODUCTORDER_BY_ID: "jms:queue:CATALOG.UPD.PRODUCTORDER_BY_ID" CATALOG_GET_INITIAL_PRODUCTORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_PRODUCTORDERS" CATALOG_GET_PRODUCTORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_PRODUCTORDERS" -CATALOG_GET_INITIAL_SERVICEORDERS_IDS: "jms:queue:CATALOG.GET.INITIAL_SERVICEORDERS" -CATALOG_GET_SERVICEORDER_IDS_BY_STATE: "jms:queue:CATALOG.GET.ACKNOWLEDGED_SERVICEORDERS" -CATALOG_ADD_SERVICE: "jms:queue:CATALOG.ADD.SERVICE" -CATALOG_UPD_SERVICE: "jms:queue:CATALOG.UPD.SERVICE" -CATALOG_GET_SERVICE_BY_ID: "jms:queue:CATALOG.GET.SERVICE" -CATALOG_GET_SERVICE_BY_ORDERID: "jms:queue:CATALOG.GET.SERVICE_BY_ORDERID" -CATALOG_SERVICE_QUEUE_ITEMS_GET: "jms:queue:CATALOG.SERVICEQUEUEITEMS.GET" -CATALOG_SERVICE_QUEUE_ITEM_UPD: "jms:queue:CATALOG.SERVICEQUEUEITEM.UPDATE" -CATALOG_SERVICE_QUEUE_ITEM_DELETE: "jms:queue:CATALOG.SERVICEQUEUEITEM.DELETE" -CATALOG_GET_PARTNER_ORGANIZATON_BY_ID: "jms:queue:CATALOG.GET.PARTNER_ORGANIZATION_BY_ID" -CATALOG_UPDATE_PARTNER_ORGANIZATION: "jms:queue:CATALOG.UPD.PARTNER_ORGANIZATION" -CATALOG_SERVICES_TO_TERMINATE: "jms:queue:CATALOG.GET.SERVICETOTERMINATE" -CATALOG_SERVICES_OF_PARTNERS: "jms:queue:CATALOG.GET.SERVICESOFPARTNERS" - -CATALOG_GET_EXTERNAL_SERVICE_PARTNERS: "jms:queue:CATALOG.GET.EXTERNALSERVICEPARTNERS" -CATALOG_UPD_EXTERNAL_SERVICESPEC: "jms:queue:CATALOG.UPD.EXTERNAL_SERVICESPEC" - +CATALOG_GET_PRODUCTCATALOGS: "jms:queue:CATALOG.GET.PRODUCTCATALOGS" +CATALOG_GET_PRODUCTCATALOG_BY_ID: "jms:queue:CATALOG.GET.PRODUCTCATALOG_BY_ID" +CATALOG_GET_PRODUCTCATALOG_BY_NAME: "jms:queue:CATALOG.GET.PRODUCTCATALOG_BY_NAME" +CATALOG_GET_PRODUCTCATEGORIES: "jms:queue:CATALOG.GET.PRODUCTCATEGORIES" +CATALOG_GET_PRODUCTCATEGORY_BY_ID: "jms:queue:CATALOG.GET.PRODUCTCATEGORY_BY_ID" +CATALOG_GET_PRODUCTOFFERINGS_BYCATEGORY_ID: "jms:queue:CATALOG.GET.PRODUCTOFFERINGS.CATEGORY_ID" +CATALOG_SEARCH_PRODUCTOFFERINGS: "jms:queue:CATALOG.CATALOG_SEARCH_PRODUCTOFFERINGS" +#PM_MEASUREMENT_COLLECTION PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.GET_BY_ID" PM_MEASUREMENT_COLLECTION_JOBS_GET: "jms:queue:PM.MEASUREMENTCOLLECTIONJOBS.GET" PM_MEASUREMENT_COLLECTION_JOB_ADD: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.ADD" PM_MEASUREMENT_COLLECTION_JOB_CREATED: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.CREATED" PM_MEASUREMENT_COLLECTION_JOB_UPDATE: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.UPDATE" +PM_MEASUREMENT_COLLECTION_JOB_GET_INPROGRESS_OR_PENDING: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.GET_INPROGRESS_OR_PENDING" #ALARMS ALARMS_ADD_ALARM: "jms:queue:ALARMS.ADD.ALARM" @@ -234,6 +257,7 @@ NFV_CATALOG_NS_LCMCHANGED: "jms:topic:NFV_CATALOG_NS_LCMCHANGED" RESERVATION_CREATE: "jms:queue:RESERVATION.ADD" RESERVATION_AVAILABILITY_CHECK: "jms:queue:RESERVATION.AVAILABILITYCHECK" + --- diff --git a/src/test/java/org/etsi/osl/services/api/ServiceCatalogIntegrationTest.java b/src/test/java/org/etsi/osl/services/api/ServiceCatalogIntegrationTest.java index 807e356072382992b7e28cef11a50efe9ba29558..fdf65d7519654a24899e69f58d0f9765873d86a9 100644 --- a/src/test/java/org/etsi/osl/services/api/ServiceCatalogIntegrationTest.java +++ b/src/test/java/org/etsi/osl/services/api/ServiceCatalogIntegrationTest.java @@ -164,7 +164,7 @@ public class ServiceCatalogIntegrationTest { ServiceCategory categ = categRepoService.findByName( "Generic Services" ); assertThat( categ.getServiceCandidateRefs().size() ).isEqualTo( FIXED_BOOTSTRAPS_SPECS ); - ServiceCategory categ2 = categRepoService.findByIdEager( categ.getId() ); + ServiceCategory categ2 = categRepoService.findByUuid( categ.getId() ); assertThat( categ2.getServiceCandidateRefs().size() ).isEqualTo( FIXED_BOOTSTRAPS_SPECS ); boolean vinnisbFound = false; @@ -1014,7 +1014,7 @@ public class ServiceCatalogIntegrationTest { logger.info("Test: testGSTUpdate " ); ServiceCategory categ = categRepoService.findByName( "Generic Services" ); - ServiceCategory categ2 = categRepoService.findByIdEager( categ.getId() ); + ServiceCategory categ2 = categRepoService.findByUuid( categ.getId() ); assertThat( categ2.getServiceCandidateRefs().size() ).isEqualTo( FIXED_BOOTSTRAPS_SPECS ); ServiceSpecification spec = this.specRepoService.findByNameAndVersion("A GST(NEST) Service Example", "5.0.0" ); diff --git a/src/test/java/org/etsi/osl/services/api/metrics/GeneralMetricsApiControllerTest.java b/src/test/java/org/etsi/osl/services/api/metrics/GeneralMetricsApiControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..af13cb39e75dbd9453d995778398b0eb4285939f --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/metrics/GeneralMetricsApiControllerTest.java @@ -0,0 +1,124 @@ +package org.etsi.osl.services.api.metrics; + +import com.jayway.jsonpath.JsonPath; +import org.etsi.osl.tmf.OpenAPISpringBoot; +import org.etsi.osl.tmf.pm632.model.IndividualCreate; +import org.etsi.osl.tmf.pm632.reposervices.IndividualRepoService; +import org.etsi.osl.tmf.rcm634.reposervices.ResourceSpecificationRepoService; +import org.etsi.osl.tmf.scm633.model.ServiceCandidate; +import org.etsi.osl.tmf.scm633.reposervices.CandidateRepoService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@Transactional +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.MOCK, + classes = OpenAPISpringBoot.class +) +//@AutoConfigureTestDatabase //this automatically uses h2 +@AutoConfigureMockMvc +@ActiveProfiles("testing") +//@TestPropertySource( +// locations = "classpath:application-testing.yml") + +public class GeneralMetricsApiControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + private WebApplicationContext context; + + @Autowired + IndividualRepoService individualRepoService; + + @Autowired + ResourceSpecificationRepoService resourceSpecificationRepoService; + + @Autowired + CandidateRepoService candidateRepoService; + + + @Before + public void setup() throws Exception { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testGetRegisteredIndividuals() throws Exception { + + IndividualCreate individualCreate = new IndividualCreate(); + individualCreate.setFullName("John Doe"); + individualRepoService.addIndividual(individualCreate); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/registeredIndividuals" ) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalIndividuals = JsonPath.read(response, "$.registeredIndividuals"); + + assertThat(totalIndividuals).isEqualTo(individualRepoService.findAll().size()); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testGetPublishedServiceSpecifications() throws Exception { + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/publishedServiceSpecifications" ) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalSpecs = JsonPath.read(response, "$.publishedServiceSpecifications"); + + List serviceCandidates = candidateRepoService.findAll(); + int count = 0; + + for (ServiceCandidate serviceCandidate : serviceCandidates) { + if (serviceCandidate.getCategory() != null) { + count += 1; + } + } + + assertThat(totalSpecs).isEqualTo(count); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testGetRegisteredResourceSpecifications() throws Exception { + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/registeredResourceSpecifications" ) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalSpecs = JsonPath.read(response, "$.registeredResourceSpecifications"); + + assertThat(totalSpecs).isEqualTo(resourceSpecificationRepoService.findAll().size()); + } +} diff --git a/src/test/java/org/etsi/osl/services/api/metrics/ResourceMetricsApiControllerTest.java b/src/test/java/org/etsi/osl/services/api/metrics/ResourceMetricsApiControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e0578d5933fac6f60c97ad564485f6a14c72af1a --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/metrics/ResourceMetricsApiControllerTest.java @@ -0,0 +1,237 @@ +package org.etsi.osl.services.api.metrics; + +import com.jayway.jsonpath.JsonPath; +import org.apache.commons.io.IOUtils; +import org.etsi.osl.tmf.JsonUtils; +import org.etsi.osl.tmf.OpenAPISpringBoot; +import org.etsi.osl.tmf.common.model.Any; +import org.etsi.osl.tmf.common.model.service.Note; +import org.etsi.osl.tmf.rcm634.model.*; +import org.etsi.osl.tmf.ri639.model.*; +import org.etsi.osl.tmf.ri639.reposervices.ResourceRepoService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URI; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@Transactional +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.MOCK, + classes = OpenAPISpringBoot.class +) +//@AutoConfigureTestDatabase //this automatically uses h2 +@AutoConfigureMockMvc +@ActiveProfiles("testing") +//@TestPropertySource( +// locations = "classpath:application-testing.yml") +public class ResourceMetricsApiControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + ResourceRepoService resourceRepoService; + + @Autowired + private WebApplicationContext context; + + @Before + public void setup() throws Exception { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testCountTotalResources() throws Exception { + createResource(ResourceStatusType.AVAILABLE); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalResources" ) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalResources = JsonPath.read(response, "$.totalResources"); + + + assertThat(totalResources).isEqualTo(resourceRepoService.findAll().size()); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testCountTotalServicesWithState() throws Exception { + createResource(ResourceStatusType.AVAILABLE); + createResource(ResourceStatusType.STANDBY); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalResources" ) + .param("state", "STANDBY") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalResources = JsonPath.read(response, "$.totalResources"); + + + List resourcesList = resourceRepoService.findAll(); + int standByResources = (int) resourcesList.stream().filter(resource -> resource.getResourceStatus() == ResourceStatusType.STANDBY).count(); + + assertThat(totalResources).isEqualTo(standByResources); + assertThat(totalResources).isEqualTo(1); + } + + @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) + @Test + public void testGetServicesGroupedByState() throws Exception { + String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); + + createResource(ResourceStatusType.AVAILABLE); + createResource(ResourceStatusType.AVAILABLE); + createResource(ResourceStatusType.AVAILABLE); + createResource(ResourceStatusType.RESERVED); + createResource(ResourceStatusType.RESERVED); + createResource(ResourceStatusType.STANDBY); + + String endTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/resourcesGroupByState") + .param("starttime", startTime) + .param("endtime", endTime) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + List> groupByState = JsonPath.read(response, "$.resources.aggregations.groupByState"); + + // Create a map from key -> count + Map stateCounts = groupByState.stream() + .collect(Collectors.toMap( + entry -> (String) entry.get("key"), + entry -> (Integer) entry.get("count") + )); + + assertThat(stateCounts.get("AVAILABLE")).isEqualTo(3); + assertThat(stateCounts.get("RESERVED")).isEqualTo(2); + assertThat(stateCounts.get("STANDBY")).isEqualTo(1); + assertThat(stateCounts.get("ALARM")).isEqualTo(0); + assertThat(stateCounts.get("UNKNOWN")).isEqualTo(0); + assertThat(stateCounts.get("SUSPENDED")).isEqualTo(0); + } + + private void createResource(ResourceStatusType statusType) throws Exception{ + + /** + * first add 2 specs + */ + + File sspec = new File( "src/test/resources/testResourceSpec.json" ); + InputStream in = new FileInputStream( sspec ); + String sspectext = IOUtils.toString(in, "UTF-8"); + + + ResourceSpecificationCreate sspeccr1 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); + sspeccr1.setName("Spec1"); + ResourceSpecification responsesSpec1 = createResourceSpec( sspeccr1); + + //res 2 is an RFS + ResourceSpecificationCreate sspeccr2 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); + sspeccr2.setName("Spec2"); + + sspeccr2.addResourceSpecificationRelationshipWith( responsesSpec1 ); + LogicalResourceSpecification responsesSpec2 = (LogicalResourceSpecification) createResourceSpec( sspeccr2 ); + /** + * add them as bundle + */ + + ResourceSpecificationCreate sspeccr3 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); + sspeccr3.setName("BundleExampleSpec"); + sspeccr3.isBundle(true); + sspeccr3.addResourceSpecificationRelationshipWith( responsesSpec1 ); + sspeccr3.addResourceSpecificationRelationshipWith( responsesSpec2 ); + ResourceSpecification responsesSpec3 = createResourceSpec( sspeccr3); + + ResourceCreate aResource = new ResourceCreate(); + aResource.setName("aNew Resource parent"); + aResource.setCategory("Experimentation"); + aResource.setDescription("Experimentation Descr"); + aResource.setStartOperatingDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); + aResource.setEndOperatingDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); + aResource.setResourceStatus(statusType); + + + + Note noteItem = new Note(); + noteItem.text("test note"); + aResource.addNoteItem(noteItem); + + Characteristic resCharacteristicItem = new Characteristic(); + + resCharacteristicItem.setName( "externalPartnerServiceId" ); + resCharacteristicItem.setValue( new Any("NONE")); + aResource.addResourceCharacteristicItem(resCharacteristicItem); + + ResourceSpecificationRef aServiceSpecificationRef = new ResourceSpecificationRef(); + aServiceSpecificationRef.setId(responsesSpec3.getId() ); + aServiceSpecificationRef.setName(responsesSpec3.getName()); + + aResource.setResourceSpecification( aServiceSpecificationRef ); + + resourceRepoService.addResource(aResource); + } + + + private ResourceSpecification createResourceSpec(ResourceSpecificationUpdate sspeccr1) throws Exception{ + + URI url = new URI("/resourceCatalogManagement/v4/resourceSpecification"); + if (sspeccr1 instanceof PhysicalResourceSpecificationUpdate ) { + url = new URI("/resourceCatalogManagement/v4/resourceSpecification"); + } + String responseSpec = mvc.perform(MockMvcRequestBuilders.post( url ) + .with( SecurityMockMvcRequestPostProcessors.csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content( JsonUtils.toJson( sspeccr1 ) )) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + ResourceSpecification responsesSpec1; + if (sspeccr1 instanceof PhysicalResourceSpecificationUpdate ) { + responsesSpec1 = JsonUtils.toJsonObj(responseSpec, PhysicalResourceSpecification.class); + }else { + responsesSpec1 = JsonUtils.toJsonObj(responseSpec, LogicalResourceSpecification.class); + } + + return responsesSpec1; + } +} diff --git a/src/test/java/org/etsi/osl/services/api/metrics/ServiceMetricsApiControllerTest.java b/src/test/java/org/etsi/osl/services/api/metrics/ServiceMetricsApiControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e7562ec4338ad9c501a888ba82f335553943110d --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/metrics/ServiceMetricsApiControllerTest.java @@ -0,0 +1,215 @@ +package org.etsi.osl.services.api.metrics; + +import com.jayway.jsonpath.JsonPath; +import org.apache.commons.io.IOUtils; +import org.etsi.osl.tmf.JsonUtils; +import org.etsi.osl.tmf.OpenAPISpringBoot; +import org.etsi.osl.tmf.common.model.Any; +import org.etsi.osl.tmf.common.model.service.*; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreate; +import org.etsi.osl.tmf.sim638.model.Service; +import org.etsi.osl.tmf.sim638.model.ServiceCreate; +import org.etsi.osl.tmf.sim638.service.ServiceRepoService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@Transactional +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.MOCK, + classes = OpenAPISpringBoot.class +) +//@AutoConfigureTestDatabase //this automatically uses h2 +@AutoConfigureMockMvc +@ActiveProfiles("testing") +//@TestPropertySource( +// locations = "classpath:application-testing.yml") +public class ServiceMetricsApiControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + ServiceRepoService serviceRepoService; + + @Autowired + private WebApplicationContext context; + + @Before + public void setup() throws Exception { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testCountTotalServices() throws Exception { + createService(ServiceStateType.ACTIVE); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServices" ) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalServices = JsonPath.read(response, "$.totalServices"); + + + assertThat(totalServices).isEqualTo(serviceRepoService.findAll().size()); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testCountTotalServicesWithState() throws Exception { + createService(ServiceStateType.ACTIVE); + createService(ServiceStateType.INACTIVE); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServices" ) + .param("state", "ACTIVE") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalServices = JsonPath.read(response, "$.totalServices"); + + + List servicesList = serviceRepoService.findAll(); + int activeServices = (int) servicesList.stream().filter(service -> service.getState() == ServiceStateType.ACTIVE).count(); + + assertThat(totalServices).isEqualTo(activeServices); + assertThat(activeServices).isEqualTo(1); + } + + @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) + @Test + public void testGetServicesGroupedByState() throws Exception { + String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); + + createService(ServiceStateType.ACTIVE); + createService(ServiceStateType.ACTIVE); + createService(ServiceStateType.ACTIVE); + createService(ServiceStateType.INACTIVE); + createService(ServiceStateType.INACTIVE); + createService(ServiceStateType.TERMINATED); + + String endTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/servicesGroupByState") + .param("starttime", startTime) + .param("endtime", endTime) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + List> groupByState = JsonPath.read(response, "$.services.aggregations.groupByState"); + + // Create a map from key -> count + Map stateCounts = groupByState.stream() + .collect(Collectors.toMap( + entry -> (String) entry.get("key"), + entry -> (Integer) entry.get("count") + )); + + assertThat(stateCounts.get("ACTIVE")).isEqualTo(3); + assertThat(stateCounts.get("INACTIVE")).isEqualTo(2); + assertThat(stateCounts.get("TERMINATED")).isEqualTo(1); + assertThat(stateCounts.get("FEASIBILITYCHECKED")).isEqualTo(0); + assertThat(stateCounts.get("RESERVED")).isEqualTo(0); + assertThat(stateCounts.get("DESIGNED")).isEqualTo(0); + } + + + + @Transactional + void createService(ServiceStateType state ) throws Exception { + int servicesCount = serviceRepoService.findAll().size(); + + File sspec = new File( "src/test/resources/testServiceSpec.json" ); + InputStream in = new FileInputStream( sspec ); + String sspectext = IOUtils.toString(in, "UTF-8"); + + ServiceSpecificationCreate sspeccr1 = JsonUtils.toJsonObj( sspectext, ServiceSpecificationCreate.class); + sspeccr1.setName("Spec1"); + ServiceSpecification responsesSpec = createServiceSpec(sspeccr1); + + ServiceCreate aService = new ServiceCreate(); + aService.setName("aNew Service"); + aService.setCategory("Test Category"); + aService.setDescription("A Test Service"); + aService.setStartDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); + aService.setEndDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); + aService.setState(state); + + Characteristic serviceCharacteristicItem = new Characteristic(); + + serviceCharacteristicItem.setName( "ConfigStatus" ); + serviceCharacteristicItem.setValue( new Any("NONE")); + aService.addServiceCharacteristicItem(serviceCharacteristicItem); + + ServiceSpecificationRef aServiceSpecificationRef = new ServiceSpecificationRef(); + aServiceSpecificationRef.setId(responsesSpec.getId() ); + aServiceSpecificationRef.setName(responsesSpec.getName()); + + aService.setServiceSpecificationRef(aServiceSpecificationRef ); + + String response = mvc.perform(MockMvcRequestBuilders.post("/serviceInventory/v4/service") + .with( SecurityMockMvcRequestPostProcessors.csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content( JsonUtils.toJson( aService ) )) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + Service responseService = JsonUtils.toJsonObj(response, Service.class); + + assertThat( serviceRepoService.findAll().size() ).isEqualTo( servicesCount + 1 ); + assertThat(responseService.getCategory()).isEqualTo("Test Category"); + assertThat(responseService.getDescription()).isEqualTo("A Test Service"); + + } + + private ServiceSpecification createServiceSpec(ServiceSpecificationCreate sspeccr1) throws Exception{ + String response = mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/serviceSpecification") + .with( SecurityMockMvcRequestPostProcessors.csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content( JsonUtils.toJson( sspeccr1 ) )) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + return JsonUtils.toJsonObj(response, ServiceSpecification.class); + } +} diff --git a/src/test/java/org/etsi/osl/services/api/metrics/ServiceOrderMetricsApiControllerTest.java b/src/test/java/org/etsi/osl/services/api/metrics/ServiceOrderMetricsApiControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..757f82cd45d6445b6427d08bf4910743fcd8cf27 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/metrics/ServiceOrderMetricsApiControllerTest.java @@ -0,0 +1,254 @@ +package org.etsi.osl.services.api.metrics; + +import com.jayway.jsonpath.JsonPath; +import org.etsi.osl.tmf.JsonUtils; +import org.etsi.osl.tmf.OpenAPISpringBoot; +import org.etsi.osl.tmf.so641.model.*; +import org.etsi.osl.tmf.so641.reposervices.ServiceOrderRepoService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@Transactional +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.MOCK, + classes = OpenAPISpringBoot.class +) +//@AutoConfigureTestDatabase //this automatically uses h2 +@AutoConfigureMockMvc +@ActiveProfiles("testing") +//@TestPropertySource( +// locations = "classpath:application-testing.yml") +public class ServiceOrderMetricsApiControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + ServiceOrderRepoService serviceOrderRepoService; + + @Autowired + private WebApplicationContext context; + + @Before + public void setup() throws Exception { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testCountTotalServiceOrders() throws Exception { + createServiceOrder(ServiceOrderStateType.INPROGRESS); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServiceOrders" ) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalServiceOrders = JsonPath.read(response, "$.totalServiceOrders"); + + + assertThat(totalServiceOrders).isEqualTo(serviceOrderRepoService.findAll().size()); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testCountTotalServiceOrdersWithState() throws Exception { + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServiceOrders" ) + .param("state", "ACKNOWLEDGED") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalServiceOrders = JsonPath.read(response, "$.totalServiceOrders"); + + + List serviceOrdersList = serviceOrderRepoService.findAll(); + int activeServiceOrders = (int) serviceOrdersList.stream().filter(serviceOrder -> serviceOrder.getState() == ServiceOrderStateType.ACKNOWLEDGED).count(); + + assertThat(totalServiceOrders).isEqualTo(activeServiceOrders); + assertThat(activeServiceOrders).isEqualTo(1); + } + + @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) + @Test + public void testGetTotalActiveServiceOrders() throws Exception { + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.COMPLETED); + createServiceOrder(ServiceOrderStateType.COMPLETED); + createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); + createServiceOrder(ServiceOrderStateType.REJECTED); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/activeServiceOrders" ) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk() ) + .andReturn().getResponse().getContentAsString(); + + int totalServiceOrders = JsonPath.read(response, "$.activeServiceOrders"); + + assertThat(totalServiceOrders).isEqualTo(4); + } + + @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) + @Test + public void testGetServiceOrdersGroupedByDay() throws Exception { + String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); + + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); + createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); + createServiceOrder(ServiceOrderStateType.PARTIAL); + + String endTime = OffsetDateTime.now(ZoneOffset.UTC).plusDays(4).format(DateTimeFormatter.ISO_INSTANT); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/serviceOrdersGroupByDay") + .param("starttime", startTime) + .param("endtime", endTime) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + List> groupByDay = JsonPath.read(response, "$.serviceOrders.aggregations.groupByDay"); + + + OffsetDateTime start = OffsetDateTime.parse(startTime); + OffsetDateTime end = OffsetDateTime.parse(endTime); + + DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; + + Map dayCounts = groupByDay.stream() + .collect(Collectors.toMap( + entry -> (String) entry.get("key"), + entry -> (Integer) entry.get("count") + )); + + int totalDays = (int) ChronoUnit.DAYS.between(start.toLocalDate(), end.toLocalDate()) + 1; + + for (int i = 0; i < totalDays; i++) { + OffsetDateTime day = start.plusDays(i).toLocalDate().atStartOfDay().atOffset(ZoneOffset.UTC); + String dayKey = formatter.format(day.toInstant()); + + if (i == 0) { + // Today: should have all 6 + assertThat(dayCounts.get(dayKey)).isEqualTo(6); + } else { + // Other days: should be 0 + assertThat(dayCounts.get(dayKey)).isEqualTo(0); + } + } + } + + @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) + @Test + public void testGetServiceOrdersGroupedByState() throws Exception { + String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); + + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.INPROGRESS); + createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); + createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); + createServiceOrder(ServiceOrderStateType.PARTIAL); + + String endTime = OffsetDateTime.now(ZoneOffset.UTC).plusDays(4).format(DateTimeFormatter.ISO_INSTANT); + + String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/serviceOrdersGroupByState") + .param("starttime", startTime) + .param("endtime", endTime) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + List> groupByState = JsonPath.read(response, "$.serviceOrders.aggregations.groupByState"); + + // Create a map from key -> count + Map stateCounts = groupByState.stream() + .collect(Collectors.toMap( + entry -> (String) entry.get("key"), + entry -> (Integer) entry.get("count") + )); + + assertThat(stateCounts.get("INPROGRESS")).isEqualTo(3); + assertThat(stateCounts.get("ACKNOWLEDGED")).isEqualTo(2); + assertThat(stateCounts.get("PARTIAL")).isEqualTo(1); + assertThat(stateCounts.get("INITIAL")).isEqualTo(0); + assertThat(stateCounts.get("REJECTED")).isEqualTo(0); + assertThat(stateCounts.get("PENDING")).isEqualTo(0); + assertThat(stateCounts.get("HELD")).isEqualTo(0); + assertThat(stateCounts.get("CANCELLED")).isEqualTo(0); + assertThat(stateCounts.get("COMPLETED")).isEqualTo(0); + assertThat(stateCounts.get("FAILED")).isEqualTo(0); + } + + private void createServiceOrder(ServiceOrderStateType stateType) throws Exception { + + ServiceOrderCreate serviceOrder = new ServiceOrderCreate(); + serviceOrder.setCategory("Test Category"); + serviceOrder.setDescription("A Test Service Order"); + serviceOrder.setRequestedStartDate(OffsetDateTime.now(ZoneOffset.UTC).toString()); + serviceOrder.setRequestedCompletionDate(OffsetDateTime.now(ZoneOffset.UTC).plusDays(3).toString()); + + String response = mvc + .perform(MockMvcRequestBuilders.post("/serviceOrdering/v4/serviceOrder") + .with( SecurityMockMvcRequestPostProcessors.csrf()) + .contentType(MediaType.APPLICATION_JSON).content(JsonUtils.toJson(serviceOrder))) + .andExpect(status().isOk()).andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + + ServiceOrder responseSO = JsonUtils.toJsonObj(response, ServiceOrder.class); + + // Update Service Order State + String soId = responseSO.getId(); + + ServiceOrderUpdate servOrderUpd = new ServiceOrderUpdate(); + servOrderUpd.setState(stateType); + + String response2 = mvc.perform(MockMvcRequestBuilders.patch("/serviceOrdering/v4/serviceOrder/" + soId) + .with( SecurityMockMvcRequestPostProcessors.csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content( JsonUtils.toJson( servOrderUpd ) )) + .andExpect(status().isOk() ) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andReturn().getResponse().getContentAsString(); + + ServiceOrder responsesServiceOrder2 = JsonUtils.toJsonObj(response2, ServiceOrder.class); + assertThat(responsesServiceOrder2.getState().toString()).isEqualTo(stateType.toString()); + } + +} diff --git a/src/test/java/org/etsi/osl/services/api/pm628/ManagementJobMVOTest.java b/src/test/java/org/etsi/osl/services/api/pm628/ManagementJobMVOTest.java new file mode 100644 index 0000000000000000000000000000000000000000..27275dfbafea5019c3630e65e451bdfbe7afb5c1 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/pm628/ManagementJobMVOTest.java @@ -0,0 +1,35 @@ +package org.etsi.osl.services.api.pm628; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.etsi.osl.tmf.pm628.model.ExecutionStateType; +import org.etsi.osl.tmf.pm628.model.ManagementJobMVO; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ManagementJobMVOTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testToStringShowsExecutionState() { + ManagementJobMVO job = new ManagementJobMVO("ManagementJob"); + job.setExecutionState(ExecutionStateType.ACKNOWLEDGED); + + String str = job.toString(); + // executionState is not included in the default toString, so this will fail unless you add it to the toString method + assertTrue(str.contains("executionState: acknowledged"), "Default toString does not show executionState"); + } + + @Test + void testSerializationDeserialization() throws Exception { + ManagementJobMVO job = new ManagementJobMVO("ManagementJob"); + job.setExecutionState(ExecutionStateType.ACKNOWLEDGED); + + String json = objectMapper.writeValueAsString(job); + ManagementJobMVO deserialized = objectMapper.readValue(json, ManagementJobMVO.class); + + assertEquals(job, deserialized); + assertEquals(ExecutionStateType.ACKNOWLEDGED, deserialized.getExecutionState()); + } +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/pm628/MeasurementCollectionJobMVOTest.java b/src/test/java/org/etsi/osl/services/api/pm628/MeasurementCollectionJobMVOTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5b34a0c8cf85441b7e77fce9aee274350bfead35 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/pm628/MeasurementCollectionJobMVOTest.java @@ -0,0 +1,48 @@ +package org.etsi.osl.services.api.pm628; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.etsi.osl.tmf.pm628.model.*; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.*; + +class MeasurementCollectionJobMVOTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testToString() { + MeasurementCollectionJobMVO job = new MeasurementCollectionJobMVO("MeasurementCollectionJob") + .outputFormat("JSON") + .jobOnDemand(true); + job.setExecutionState(ExecutionStateType.ACKNOWLEDGED); + + String str = job.toString(); + assertTrue(str.contains("outputFormat: JSON")); + assertTrue(str.contains("jobOnDemand: true")); + assertTrue(str.contains("executionState: acknowledged")); + assertTrue(str.contains("class MeasurementCollectionJobMVO")); + } + + @Test + void testSerializationDeserialization() throws Exception { + MeasurementCollectionJobMVO job = new MeasurementCollectionJobMVO("MeasurementCollectionJob") + .outputFormat("JSON") + .jobOnDemand(false); + + // Set a nested object for better coverage + job.setReportingPeriod(ReportingPeriod.R_1H); + job.setExecutionState(ExecutionStateType.ACKNOWLEDGED); + + String json = objectMapper.writeValueAsString(job); + MeasurementCollectionJobMVO deserialized = objectMapper.readValue(json, MeasurementCollectionJobMVO.class); + + assertEquals(job, deserialized); + assertEquals("JSON", deserialized.getOutputFormat()); + assertFalse(deserialized.getJobOnDemand()); + assertNotNull(deserialized.getReportingPeriod()); + assertEquals(ExecutionStateType.ACKNOWLEDGED, deserialized.getExecutionState()); + } +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/pm628/MeasurementCollectionJobServiceTest.java b/src/test/java/org/etsi/osl/services/api/pm628/MeasurementCollectionJobServiceTest.java index d718e0ab2f954b6ab5510258ee4a01911b596564..65fdd391310872225a6220d3b4580dc30a2d5086 100644 --- a/src/test/java/org/etsi/osl/services/api/pm628/MeasurementCollectionJobServiceTest.java +++ b/src/test/java/org/etsi/osl/services/api/pm628/MeasurementCollectionJobServiceTest.java @@ -192,4 +192,38 @@ public class MeasurementCollectionJobServiceTest { return response; } + + private MeasurementCollectionJob createNewMeasurementCollectionJobWithExecutionState(int previousNumberOfMcjs, ExecutionStateType executionStateType) throws Exception { + assertThat(measurementCollectionJobService.findAllMeasurementCollectionJobs().size()).isEqualTo(FIXED_BOOTSTRAPS_JOBS + previousNumberOfMcjs); + + File fvo = new File("src/test/resources/testMeasurementCollectionJobFVO.json"); + InputStream in = new FileInputStream(fvo); + String mcjFVOText = IOUtils.toString(in, "UTF-8"); + + MeasurementCollectionJobFVO mcjFVO = JsonUtils.toJsonObj(mcjFVOText, MeasurementCollectionJobFVO.class); + mcjFVO.setExecutionState(executionStateType); + + MeasurementCollectionJob response = measurementCollectionJobService.createMeasurementCollectionJob(mcjFVO); + + assertThat(measurementCollectionJobService.findAllMeasurementCollectionJobs().size()).isEqualTo(FIXED_BOOTSTRAPS_JOBS + previousNumberOfMcjs + 1); + + return response; + } + +// @WithMockUser(username="osadmin", roles = {"USER","ADMIN"}) +// @Test +// public void testFindPendingOrInProgressMeasurementCollectionJobs() throws Exception { +// MeasurementCollectionJob pendingMcj = createNewMeasurementCollectionJobWithExecutionState(measurementCollectionJobService.findAllMeasurementCollectionJobs().size(), ExecutionStateType.PENDING); +// +// int currentNumOfMcjs = measurementCollectionJobService.findAllMeasurementCollectionJobs().size(); +// MeasurementCollectionJob inProgressMcj = createNewMeasurementCollectionJobWithExecutionState(currentNumOfMcjs, ExecutionStateType.INPROGRESS); +// +// +// List ackMcjList = measurementCollectionJobService.findAllByExecutionState(ExecutionStateType.ACKNOWLEDGED); +// +// List mcjList = measurementCollectionJobService.findPendingOrInProgressMeasurementCollectionJobs(); +// +// +// assertThat(mcjList.size()).isEqualTo(FIXED_BOOTSTRAPS_JOBS + 2); +// } } diff --git a/src/test/java/org/etsi/osl/services/api/pm628/SerializationTest.java b/src/test/java/org/etsi/osl/services/api/pm628/SerializationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6d7bf41356702236ddaade97737af96038fd6f0f --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/pm628/SerializationTest.java @@ -0,0 +1,51 @@ +package org.etsi.osl.services.api.pm628; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; +import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJob; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SerializationTest { + + @Test + public void testJsonArraySerialization() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + + // Create a list of objects to serialize + MeasurementCollectionJob job1 = new MeasurementCollectionJob("JobType1").outputFormat("JSON"); + job1.setType("MeasurementCollectionJob"); + MeasurementCollectionJob job2 = new MeasurementCollectionJob("JobType2").outputFormat("JSON"); + job2.setType("MeasurementCollectionJob"); + String job1Str = objectMapper.writeValueAsString(job1); + System.out.println(job1Str); +// List jobs = List.of(job1, job2); + List jobs = new ArrayList<>(); + jobs.add(job1); + jobs.add(job2); + + // Serialize the list to JSON + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); + + String jsonArray = objectMapper.writeValueAsString(jobs); + System.out.println(jsonArray); + + // Deserialize the JSON back to a list + List deserializedJobs = objectMapper.readValue( + jsonArray, + objectMapper.getTypeFactory().constructCollectionType(List.class, MeasurementCollectionJob.class) + ); + + // Assert the deserialized list matches the original + assertEquals(jobs.size(), deserializedJobs.size()); + assertEquals(jobs.get(0).getOutputFormat(), deserializedJobs.get(0).getOutputFormat()); + assertEquals(jobs.get(1).getOutputFormat(), deserializedJobs.get(1).getOutputFormat()); + } +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/sim638/ServiceRepoServiceTest.java b/src/test/java/org/etsi/osl/services/api/sim638/ServiceRepoServiceTest.java index d433726a7f82478384f861b19c7d5644ce43283a..ded942c8a351a41ddd5ba20e18204a2070b5308a 100644 --- a/src/test/java/org/etsi/osl/services/api/sim638/ServiceRepoServiceTest.java +++ b/src/test/java/org/etsi/osl/services/api/sim638/ServiceRepoServiceTest.java @@ -524,7 +524,7 @@ public class ServiceRepoServiceTest { r1.setResourceStatus(ResourceStatusType.SUSPENDED); nstate = s.findNextStateBasedOnResourceList(rlist); - assertThat(nstate).isEqualTo( ServiceStateType.TERMINATED ); + assertThat(nstate).isEqualTo( ServiceStateType.ACTIVE ); s.setState( ServiceStateType.TERMINATED ); r1.setResourceStatus(ResourceStatusType.AVAILABLE); diff --git a/src/test/resources/testMeasurementCollectionJobFVO.json b/src/test/resources/testMeasurementCollectionJobFVO.json index 3854d4e47a8bacd2af998805f2ffdf3033c27a8e..14b324bd4337204263e82e999835a3a13891ac66 100644 --- a/src/test/resources/testMeasurementCollectionJobFVO.json +++ b/src/test/resources/testMeasurementCollectionJobFVO.json @@ -35,7 +35,6 @@ "groupCategory": "CPUGroup", "performanceIndicatorSpecification": [ { - "uuid": "5000", "href": "https://host:port/tmf-api/performanceManagement/v5/performanceIndicatorSpecification/5000", "@type": "PerformanceIndicatorSpecificationRef" } @@ -47,7 +46,6 @@ ], "performanceIndicatorSpecification": [ { - "uuid": "101", "href": "https://host:port/tmf-api/performanceManagement/v5/performanceIndicatorSpecification/101", "derivationAlgorithm": "na", "derivationMethod": "average", @@ -60,7 +58,6 @@ "indicatorType": "float", "performanceIndicatorSpecRelationship": [ { - "uuid": "321", "href": "https://host:port/tmf-api/performanceManagement/v5/performanceIndicatorSpecRelationship/321", "relationshipType": "reliesOn", "validFor": {